this question is referring to the 'new' D : DMD32 D Compiler v2.068.2
for TL;DR if you don't need details skip to the question below
working with visual studio(i am using v2010), by creating a new project
-> D
-> Dynamic Library
when the project creartion process is complete, in the solution explorer there's 2 files:
leaving the .def
file as it is, i have managed to understand that
by adding some new functions to the dllmain.d
and prefexing with :
extern (Windows) export
will export the the function and it will be callable from c#
, didn't try it with C
or C++
.
side note, do not touch any of the existing code unless you know what you're 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 easy use it as follows:
uint powD = D_mathPower(5);
how do i return an array of structs (preferably the most cost-efficient way) ?
struct dpack{ char* Name; uint Id; }
i have tried using both char[]
and char*
but with no 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++
}
Because a D array has a special layout you should rather return a pointer to the first item. Then in C# you can cast each item from the base pointer by reading 8 bytes per 8 bytes (this matches dpack.sizeof
), since you already know the count:
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 cast the .Name
member it's necessary to add a terminator, otherwise you cant know the length of the string. This is done by std.string.toStringz
which will add a null character at the end of the string. The char* Name
member can then be cast as are usually strings provided by a function in a dll with a C interface.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With