将多维数组从 c# 编组到 delphi

Marshalling Multidimensional arrays from c# to delphi

我正在将 lib 从 delphi 重写为 c#。库方法在delphi客户端调用,参数如下

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

我试过像这样将相同的数组传递给 c#:

 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;

然后扔出去

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

然后这样尝试:

 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;

然后扔出去

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

初始条件:

c#调用delphi方法:

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

Params 是一维变量数组。我准备如下:

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;
}

然后我打电话给:

 object T = tVector;

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

当传递的参数很简单时:int、string 等。一切正常。但是传递一个数组我得到一个异常

这是 Delphi 上的客户端代码,其中一切正常:

 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');

找到您引用的内容: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);

在哪里

TRetCode = integer – completion code.

TModelHandle = THandle – pointer to a model;

所以我会说 TModelHandle 是一个 IntPtr(32 位有 32 位进程,64 位有 64 位进程)。所以:

[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;
}

我已经构建了一个 C#->C++ 代码,其中包含为 C++ 提议的签名,并且它可以正常工作。参数传递正确,res正确传递出去

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);