Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

Marshalling Multidimensional arrays from c# to delphi

I am rewrite lib from delphi to c#. The library method is called in the delphi client with the following parameter

T:=VarArrayCreate([1,2,1,1],varDouble);
T[1,1]:=Tmin;
T[2,1]:=Tmax;

I tried to pass the same array to c # like this:

 Array tVector = Array.CreateInstance(typeof(double), new[] { 2, 1 }, new[] { 1, 1 });
 tVector.SetValue(Tmin, 1, 1);
 tVector.SetValue(Tmax, 2, 1);

 object T = tVector;

Then thrown out

System.Runtime.InteropServices.SEHException: "External component has thrown an exception."

And tried like this:

 Array tVector1 = Array.CreateInstance(typeof(double), new[] { 1 }, new[] { 1 });
 Array tVector2 = Array.CreateInstance(typeof(double), new[] { 1 }, new[] { 1 });
 Array tVector = Array.CreateInstance(tVector1.GetType(), new[] { 2 }, new[] { 1 });

 tVector.SetValue(tVector1, 1);
 tVector.SetValue(tVector2, 2);

 object T = tVector;

Then thrown out

System.Runtime.InteropServices.SafeArrayTypeMismatchException: "Specified array was not of the expected type."

Init conditions:

c# calls the delphi method:

function  call (hModel: TModelHandle; const FunName: variant; var Params: variant; var Res: variant): TRetCode; stdcall;

Params is a 1d variant array. I prepare it as follows:

public object Call(string functionName, params object[] parameters)
{
        object res = new();

        object funName = functionName;
        
        Array endParamsArray = Array.CreateInstance(typeof(object), new[] {parameters.Length}, new[] {1});
        Array.Copy(parameters, endParamsArray, parameters.Length);
        object endParams = endParamsArray;
        
        var rc = call(hModel, ref funName, ref endParams, ref res);

        if (rc != TRetCode.rcOK)
            error(rc);

        return res;
}

And then I call:

 object T = tVector;

 PM.Call("funname", ID, Name, T, RamStab, Ktrans, sec_overcoming);

When the passed parameters are simple: int, string, etc. everything works well. But passing an array I get an exception

And this is the client code on Delphi, in which everything works:

 w:='funname'; FunName:=w;
Params:=VarArrayCreate([1,6],varVariant);
Params[1]:=ID;
Params[2]:=Name;
T:=VarArrayCreate([1,2,1,1],varDouble);
T[1,1]:=Tmin;
T[2,1]:=Tmax;
Params[3]:=T;
Params[4]:=RamStab;
Params[5]:=Ktrans;
Params[6]:=sec_overcoming;
rc:=PM.call(PM.hModel,FunName,Params,Res);
Bar:=PM.getObject(Name);
if Bar=nil then
  error('create');
question from:https://stackoverflow.com/questions/66051770/marshalling-multidimensional-arrays-from-c-sharp-to-delphi

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Found what you are referencing: https://www.mvstudium.com/eng/RMDmanual-en.pdf

function call (hModel: TModelHandle; const FunName: variant; var Params: variant; var Res: variant): TRetCode; stdcall;

TRetCode __stdcall call (TModelHandle hModel, variant *FunName, variant *Params, variant *Res);

Where

TRetCode = integer – completion code.

and

TModelHandle = THandle – pointer to a model;

So I would sai TModelHandle is a IntPtr (32 bits with 32 bits processes, 64 bits with 64 bits processes). So:

[DllImport(@"Yourdll", CallingConvention = CallingConvention.StdCall)]
public static extern int call(IntPtr hModel, ref object funName, ref object @params, ref object res);

public static object Call(string functionName, params object[] parameters)
{
    object res = null;

    object funName = functionName;

    Array endParamsArray = Array.CreateInstance(typeof(object), new[] { parameters.Length }, new[] { 1 });
    Array.Copy(parameters, endParamsArray, parameters.Length);
    object endParams = endParamsArray;

    var rc = call(hModel, ref funName, ref endParams, out res);

    return res;
}

I've built a C#->C++ code with the signature proposed for C++ and it works correctly. The parameters are correctly passed, res is correctly passed out.

double Tmin = double.MinValue;
double Tmax = double.MaxValue;

int ID = 1;
string Name = "Foo";
double RamStab = 5;
long Ktrans = 3;
int sec_overcoming = 2;

Array tVector = Array.CreateInstance(typeof(double), new[] { 2, 1 }, new[] { 1, 1 });
tVector.SetValue(Tmin, 1, 1);
tVector.SetValue(Tmax, 2, 1);

object response = Call("Hello world", ID, Name, tVector, RamStab, Ktrans, sec_overcoming);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...