与D接口正确返回一个Struct数组

Raj*_*lix 8 c# interop pointers d

这个问题指的是'新'D: DMD32 D编译器v2.068.2

对于TL; DR如果您不需要详细信息,请跳至下面的问题

使用visual studio(我正在使用v2010),通过创建new project- > D- >Dynamic Library

当项目creartion过程完成时,在解决方案资源管理器中有2个文件:

  • dllmain.d
  • dll.def

保持.def文件dllmain.d不变,我已经设法理解通过添加一些新功能和优先:

extern (Windows) export  
Run Code Online (Sandbox Code Playgroud)

将导出该函数,它将可以调用c#,没有尝试使用CC++.

请注意,除非您知道自己在做什么,否则请勿触摸任何现有代码.

所以下面的代码按预期工作

extern (Windows) export uint D_mathPower(uint p)
{     
    return p * p; 
}
Run Code Online (Sandbox Code Playgroud)

使用以下签名从C#调用它:

    [DllImport(@"pathTo...\DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
    public static extern uint D_mathPower(uint p);
Run Code Online (Sandbox Code Playgroud)

我可以很容易地使用它如下:

uint powD = D_mathPower(5);
Run Code Online (Sandbox Code Playgroud)

我的问题是

我如何返回一组结构(最好是最具成本效益的方式)?

struct dpack{ char* Name; uint Id; }
Run Code Online (Sandbox Code Playgroud)

我一直在使用这两种尝试char[]char*,但没有成功.

到目前为止这是我的代码

extern (Windows) export
dpack[] D_getPacks(uint size)
{
    dpack[] rtDpArr = new dpack[size];
    char[] str = "someText".dup;

    for(uint i=0; i<size; i++)
    {

        str[$ - 1] = cast(char)('0' + i % (126 - '0'));
        rtDpArr[i].Id = i;
        rtDpArr[i].Name= str.dup;
    }
   return rtDpArr;
}


void getPacksPtr(uint size, dpack** DpArr)
{
 // this is the signature i have successfully implemented via c++
}
Run Code Online (Sandbox Code Playgroud)

Abs*_*ype 1

由于 D 数组具有特殊布局,因此您应该返回指向第一项的指针。然后在 C# 中,您可以通过每 8 个字节读取 8 个字节(这与dpack.sizeof)来从基指针转换每个项目,因为您已经知道计数:

struct dpack{ immutable(char)* Name; uint Id; }

extern (Windows) export
void* D_getPacks(uint count)
{
    dpack[] rtDpArr = new dpack[count];
    char[] str = "someText".dup;

    import std.string;
    for(uint i=0; i<count; i++)
    {
        rtDpArr[i].Id = i;
        // add a trailing '\0'
        rtDpArr[i].Name = toStringz(str);
    }
    // pointer to the first item
    return rtDpArr.ptr;
}
Run Code Online (Sandbox Code Playgroud)

另外,要转换.Name成员,必须添加终止符,否则您无法知道字符串的长度。这是通过std.string.toStringz在字符串末尾添加一个空字符来完成的。然后可以将该成员char* Name转换为通常由具有 C 接口的 dll 中的函数提供的字符串。