与D接口正确返回结构数组

本文关键字:返回 结构 数组 接口 | 更新日期: 2023-09-27 18:20:17

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

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

使用visualstudio(我使用的是v2010),通过创建new project->D->Dynamic Library

项目创建过程完成后,在解决方案资源管理器中有两个文件:

  • dllmain.d
  • dll.def

保持.def文件的原样,我已经设法理解了通过在dllmain.d中添加一些新功能并首选

extern (Windows) export  

将导出该函数,并且它将从c#调用,没有尝试使用CC++

注意,除非你知道自己在做什么,否则不要触摸任何现有的代码

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

extern (Windows) export uint D_mathPower(uint p)
{     
    return p * p; 
}

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

    [DllImport(@"pathTo...'DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
    public static extern uint D_mathPower(uint p);

我可以简单地使用它如下:

uint powD = D_mathPower(5);

我的问题是

如何返回structs数组(最好是最具成本效益的方法)?

struct dpack{ char* Name; uint Id; }

我尝试过使用CCD_ 9和CCD_。

这是我到目前为止的代码

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

与D接口正确返回结构数组

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

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

这是我能实现它的最有效的方法。

extern (Windows) export
void D_getPacksPtr(uint size, dpack** DpArr)
{
    *DpArr = cast(dpack*) malloc(size * dpack.sizeof);
    dpack* curP = *DpArr;
    char[] str = "abcdefghij".dup;
    uint i=0;
    while(i!=size){
        str[$ - 1] = cast(char)('0' + i % (126 - '0'));
        curP.Name = cast(char*)str.dup; curP.Id = i;
        ++i;++curP;
    }
}
    [DllImport(@"PathTo...'DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity]
    public static extern void D_getPacksPtr(uint size, dpack** DPArr);

使用它:

    dpack* outDpack;
    D_getPacksPtr(500000, &outDpack);