Jump to page: 1 2
Thread overview
How can I make this work?
Feb 28, 2021
Jack
Feb 28, 2021
evilrat
Feb 28, 2021
rikki cattermole
Feb 28, 2021
Rumbu
Feb 28, 2021
Rumbu
Feb 28, 2021
Max Haughton
Feb 28, 2021
rikki cattermole
Feb 28, 2021
Adam D. Ruppe
Mar 16, 2021
Jack
Mar 16, 2021
Vinod K Chandran
Mar 16, 2021
Jack
February 28, 2021
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;
February 28, 2021
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[].

February 28, 2021
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.
February 28, 2021
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.

February 28, 2021
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);


February 28, 2021
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@...
February 28, 2021
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.
February 28, 2021
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.
March 16, 2021
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
March 16, 2021
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. :)


« First   ‹ Prev
1 2