On Sunday, 28 February 2021 at 13:15:47 UTC, Adam D. Ruppe wrote:
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.
This is what I ended up using. using a single pointer such as
MyMessage makes things much simpler. Thanks for the rememinder of
GC.removeRoot()
Everyone else in this theread, thank you guys. Always helpful