Pairing with D Correctly return an array of structures

this question is about the "new" D: Compiler DMD32 D v2.068.2

for TL; DR, if you do not need details, skip the question below

working with visual studio (I am using v2010) by creating a new project D Dynamic Library

when the project creation process is completed, there are 2 files in the solution explorer:

  • dllmain.d
  • dll.def

dllmain.d .def file .def it is, I was able to understand that by adding some new functions to dllmain.d and prefilling with:

 extern (Windows) export 

will export the function, and it will be called from c# , have not tried it using C or C++ .

note, do not touch any existing code if you do not know what you are doing.

so the code below works as expected

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

calling it from C # with the following signature:

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

I could easily use it as follows:

 uint powD = D_mathPower(5); 

my question

How can I return an array of structures (preferably the most economical way)?

 struct dpack{ char* Name; uint Id; } 

I tried using both char[] and char* , but without success.

this is my code so far

 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++ } 
+8
pointers c # interop d
source share
2 answers

Since array D has a special layout, you should rather return a pointer to the first element. Then in C # you can drop every element from the base pointer by reading 8 bytes by 8 bytes (this corresponds to dpack.sizeof ), since you already know the counter:

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

Also, to add the .Name member, .Name must add a terminator, otherwise you cannot know the length of the string. This is done using std.string.toStringz , which will add a null character at the end of the line. The char* Name element can be run, as usual, with strings provided by a function in a dll with a C interface.

+1
source share

This is the most effective way to implement it.

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

using it:

  dpack* outDpack; D_getPacksPtr(500000, &outDpack); 
0
source share

All Articles