2015-11-02 51 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);