www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What exactly gets returned with extern(C) export string func() ?

reply cc <cc nevernet.com> writes:
D under dmd/Win10/64-bit currently seems to store strings 
(slices) internally like so:
```d
static struct DString {
	size_t length;
	immutable(char)* ptr;
}
static assert(DString.sizeof == string.sizeof);
string s = "abcde";
DString d;
memcpy(&d, &s, s.sizeof);
assert(d.length == s.length);
assert(d.ptr == s.ptr);
```

If I write a DLL export like:
```d
extern(C) export string someDLLFunc() {
	return "hello";
}
```


struct DString {
	public long length;
	public IntPtr ptr;
}
[DllImport("mydll.dll")]
extern DString someDLLFunc();
...
DString d = someDLLFunc();
System.Console.WriteLine("dstr: {0} : {1}", d.length, d.ptr);
```

value from `someDLLFunc()`, the length and ptr parameters are 
both 0.

If I explicitly pass a struct back from D instead like so:
```d
static struct DString {
	size_t length;
	immutable(char)* ptr;
	this(string str) {
		length = str.length;
		ptr = str.ptr;
	}
}
extern(C) export DString someDLLFunc() {
	return DString("hello");
}
```

explicitly disallow slices as an extern(C) export parameter type?
Jun 13 2021
parent reply frame <frame86 live.com> writes:
On Sunday, 13 June 2021 at 10:02:45 UTC, cc wrote:


 explicitly disallow slices as an extern(C) export parameter 
 type?
The spec says that there is no equivalent to type[]. You get a type* instead.
Jun 13 2021
parent reply cc <cc nevernet.com> writes:
On Sunday, 13 June 2021 at 21:13:33 UTC, frame wrote:
 On Sunday, 13 June 2021 at 10:02:45 UTC, cc wrote:


 explicitly disallow slices as an extern(C) export parameter 
 type?
The spec says that there is no equivalent to type[]. You get a type* instead.
I can't seem to get it to work as a return type, but interestingly it does work as an out/pass by ref parameter. D: ```d export void D_testString(out string ret) { ret = "hello".idup; } ``` public struct DString { public ulong length; public IntPtr ptr; public string str { get { byte[] b = new byte[length]; for (int i = 0; i < (int)length; i++) { b[i] = Marshal.ReadByte(ptr, i); } return Encoding.UTF8.GetString(b); } } } [DllImport("test.dll")] private static extern void D_testString(out DString dd); public static string testString() { DString d; D_testString(out d); return d.str; } ```
Jun 15 2021
parent frame <frame86 live.com> writes:
On Wednesday, 16 June 2021 at 02:46:36 UTC, cc wrote:

 I can't seem to get it to work as a return type, but 
 interestingly it does work as an out/pass by ref parameter.
Probably for returning the struct it needs some allocation to do with the IntPtr. It may work if you use a struct on the DLL side too and convert any specific things like pointers to simple integers instead. The out keyword however basically is just a pointer to the struct, so reading directly from the memory offset from the DLL works instead. As long the GC sees the data alive - .(i)dup doesn't protect your memory here. The data could be collected by the GC anytime the function call goes out of scope.
Jun 16 2021