www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How can I make this work?

reply Jack <jckj33 gmail.com> writes:
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?

for example, I need something like this to work:

int[] arr = [1, 2, 3];
long l = cast(long) cast(void*) arr.ptr;
int[] a = cast(int[]) cast(void*) l;
Feb 27 2021
next sibling parent evilrat <evilrat666 gmail.com> writes:
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?

 for example, I need something like this to work:

 int[] arr = [1, 2, 3];
 long l = cast(long) cast(void*) arr.ptr;
 int[] a = cast(int[]) cast(void*) l;
Should already work like that. Just be aware that array can be garbage collected if no references for it are kept somewhere else between set callback and the actual call, otherwise you can get some random garbage. Also be aware that such casts 99% basically a speculation, there is no guarantee that returned data is actually an int[].
Feb 27 2021
prev sibling next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 28/02/2021 8:05 PM, Jack wrote:
 int[] arr = [1, 2, 3];
size_t l = cast(size_t)arr.ptr; Okay, so far so good
 int[] a = cast(int[]) cast(void*) l;
Umm, you haven't specified a length? int[] a = (cast(int*)l)[0 .. 3]; If the callback is being called (in effect under the current stack frame and won't escape), I would wrap the data you need in a struct and pass that to it instead by pointer. No need for heap allocation and gives a way to pass more complex data should the need arise.
Feb 28 2021
prev sibling next sibling parent reply Rumbu <rumbu rumbu.ro> writes:
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?

 for example, I need something like this to work:

 int[] arr = [1, 2, 3];
 long l = cast(long) cast(void*) arr.ptr;
 int[] a = cast(int[]) cast(void*) l;
LPARAM is not long on 32 bits, it's int. Use LPARAM instead of long.
Feb 28 2021
parent reply Rumbu <rumbu rumbu.ro> writes:
On Sunday, 28 February 2021 at 09:04:49 UTC, Rumbu 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?

 for example, I need something like this to work:

 int[] arr = [1, 2, 3];
 long l = cast(long) cast(void*) arr.ptr;
 int[] a = cast(int[]) cast(void*) l;
LPARAM is not long on 32 bits, it's int. Use LPARAM instead of long.
And you are passing only the address of the first element this way, loosing the array/slice length. This should work, but keep in mind that you have no warranty that the array stays in memory and it is not garbage collected. int[] arr = [1, 2, 3]; LPARAM l = cast(LPARAM)cast(void*)&arr; int[] a = *cast(int[]*)(cast(void*)l);
Feb 28 2021
parent reply Max Haughton <maxhaton gmail.com> writes:
On Sunday, 28 February 2021 at 09:18:56 UTC, Rumbu wrote:
 On Sunday, 28 February 2021 at 09:04:49 UTC, Rumbu 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?

 for example, I need something like this to work:

 int[] arr = [1, 2, 3];
 long l = cast(long) cast(void*) arr.ptr;
 int[] a = cast(int[]) cast(void*) l;
LPARAM is not long on 32 bits, it's int. Use LPARAM instead of long.
And you are passing only the address of the first element this way, loosing the array/slice length. This should work, but keep in mind that you have no warranty that the array stays in memory and it is not garbage collected. int[] arr = [1, 2, 3]; LPARAM l = cast(LPARAM)cast(void*)&arr; int[] a = *cast(int[]*)(cast(void*)l);
Do the windows APIs expect the length in memory rather than as a parameter? Also Rumbu can you check your email - I may have emailed you on an old email address by accident, but it's about the blog and it will be from mh240 ...
Feb 28 2021
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 28/02/2021 11:05 PM, Max Haughton wrote:
 Do the windows APIs expect the length in memory rather than as a parameter?
This sounds like its being sent via a user field to be passed to a callback. I.e. event loop for a window. In this sort of case you only get one parameter on the callback and it is only big enough for a pointer.
Feb 28 2021
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
Feb 28 2021
next sibling parent Jack <jckj33 gmail.com> writes:
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
Mar 15 2021
prev sibling parent reply Vinod K Chandran <kcvinu82 gmail.com> writes:
On Sunday, 28 February 2021 at 13:15:47 UTC, Adam D. Ruppe wrote:
 
 And it is the simplest thing, no missing length, no weird 
 property casting. The GC handled with two simple add/remove 
 calls.
Perfect example of teaching something. Thank you for this knowledge. Even though, this was not my problem, Its really helpful for me to my future project. :)
Mar 16 2021
parent Jack <jckj33 gmail.com> writes:
On Tuesday, 16 March 2021 at 16:02:14 UTC, Vinod K Chandran wrote:
 On Sunday, 28 February 2021 at 13:15:47 UTC, Adam D. Ruppe 
 wrote:
 
 And it is the simplest thing, no missing length, no weird 
 property casting. The GC handled with two simple add/remove 
 calls.
Perfect example of teaching something. Thank you for this knowledge. Even though, this was not my problem, Its really helpful for me to my future project. :)
elegant approach
Mar 16 2021