2015-11-02 80 views
8

这个问题指的是“新” d数组: DMD32 d编译v2.068.2与d接口正确返回结构

为TL; DR,如果你不需要细节跳过下面

与Visual Studio(我使用V2010)工作,通过创建一个new project问题 - >D - >Dynamic Library

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

  • dllmain.d
  • dll.def

离开.def文件,因为它是我成功要明白, 通过添加一些新的功能到dllmain.d与prefexing:

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

我的问题是

我如何返回结构的数组(优选最经济有效的方式)?

struct dpack{ char* Name; uint Id; } 

我已经尝试使用这两种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++ 
} 
+0

返回d阵列到另一种语言可以工作,但通常不会因为ABI细节不一定匹配。尝试使用自己的指针和长度来为interop创建结构类型,或者执行像getArray(size_t * lengthPtr,dpack ** ptrPtr){* lengthPtr = array.length; * ptrPtr = array.ptr; }' –

+0

您应该练习创建一个C DLL并在C#中使用它,然后使用D DLL进行尝试。弄清楚如何使用从C#返回“数组”的C函数,然后在D中使用相同的技术.C#不知道D如何存储切片,因此您将无法按原样使用它们。 –

回答

1

因为d阵列有一个特殊的布局,你应该一个指针,而返回的第一个项目。然后在C#中,你可以每8个字节(此匹配dpack.sizeof)读8个字节投从基指针的每个项目,因为你已经知道计数:

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中的函数提供的字符串。

+0

嘿感谢@嵌套类型..代码,我已经测试了很多变化,但没有包括'std.string'我已经尝试过你的代码后,我已经找到了答案和基准对'C++'实现后,我然后测试与'char *'字段相比,'std.string'的性能下降了0.75%。和迄今为止D中最快的代码(这是我发布的)。它仍然比C++中最快的aproach还慢,因此C++的代码是0.75%,所以C++是45 ms,D(char * )'是57毫秒,'D(std.string)'是79毫秒。 –

+0

奇怪的是,每当我调用函数的内容不同时,元素[0]处的尾部可能曾经是'G'然后再次执行它'';那么'G'再次不稳定,它是否有任何东西用'malloc'来处理没有'free'的或者它可能是什么? –

0

这是我可以实现它的最有效的方法。使用

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