On Sunday, 28 February 2021 at 07:05:27 UTC, Jack wrote:
I'm using a windows callback function where the user-defined
value is passed thought a LPARAM argument type. I'd like to
pass my D array then access it from that callback function. How
is the casting from LPARAM to my type array done in that case?
The best way to do this is to put the array inside a struct and
pass the address of the struct instead. This way both length and
pointer are passed, and you have the option to add more things if
you ended up needing it later, and there's fewer weird things to
worry about.
int[] arr = [1, 2, 3];
struct MyMessage {
int[] arr;
}
// this far is easy enough
MyMessage* messagePointer = new MyMessage(arr);
// but we do need to tell the GC we intend to pass this to the
outside world
// failure to do this MIGHT lead to random crashes as the GC
can't see it (it can't look inside the Windows message queue),
assumes it is unused, and frees it out from under you.
import core.memory;
GC.addRoot(messagePointer);
// when the GC has a root, it will consider that pointer live
until further notice and not collect it nor its member variables.
// so it is now cool to do this
PostMessage(hwnd, MSG_WHATEVER, 0, cast(LPARAM) messagePointer);
/* then on the other side */
switch(iMsg) {
case MSG_WHATEVER:
MyMessage* messagePointer = cast(MyMessage*) lParam;
// need to tell the GC the pointer can be automatically
managed normally again. failure to do this will lead to a memory
leak
import core.memory;
GC.removeRoot(messagePointer);
// now can use it
foreach(item; messagePointer.arr) {
// yada yada yada
}
}
And it is the simplest thing, no missing length, no weird
property casting. The GC handled with two simple add/remove calls.