Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a UDT from a LongPtr in VBA

Tags:

excel

vba

winapi

I want to get a UDT that is kept as a pointer in the user data associated with a subclassed window. The UDT is declared as:

Type ID
 nPID As long
 hDefProc As LongPtr
End Type

Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr

GetWindowLongPtr() returns a LongPtr, and I can't seem to dereference that

Inside my subclassed WindowProc I'm trying to access it like this

Dim pID As ID
pID = GetWindowLongPtr(hWnd, GWLP_USERDATA) '<- Err: Type mismatch

Is there a way to dereference this in vb6? If not, what are my alternatives to store data in a sub-classed windowclass?

  • EDIT :

I did a poor job at explaining. The problem I'm having boils down to this. I can't allocate an UDT on the heap and dereference it after: This is the full code:

Type IDT
    id As Long
    SomeOther As Long
End Type

Public Const HEAP_NO_SERIALIZE = &H1
Public Const HEAP_ZERO_MEMORY = &H8

Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Declare PtrSafe Function HeapAlloc Lib "kernel32" Alias "HeapAlloc" (ByVal hHeap As LongPtr, ByVal dwFlags As Long, ByVal dwBytes As LongPtr) As LongPtr
Declare PtrSafe Function GetProcessHeap Lib "kernel32" Alias "GetProcessHeap" () As LongPtr

Sub main()
   Dim SourceIDT As IDT
   Dim HeapIDT As LongPtr
   Dim TestIDT As IDT

   SourceIDT.id = 1234
   Debug.Print "SourceIDT.id = " & SourceIDT.id ' returns 1234

   HeapIDT = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY, LenB(SourceIDT))
   CopyMemory ByVal HeapIDT, VarPtr(SourceIDT), LenB(SourceIDT)

   CopyMemory VarPtr(TestIDT), ByVal HeapIDT, LenB(SourceIDT)
   Debug.Print "TestIDT.id = " & TestIDT.id ' expected 1234, but getting 0
   ' to do: free
End Sub

"Dereferencing" it like that always yields garbage or zero. What am I doing wrong? It's a VBA6 macro in Excel x86 if that matters.

like image 463
ptim Avatar asked Feb 01 '26 10:02

ptim


2 Answers

You need to add ByVal for the CopyMemory parameter, like:

Sub main()
   Dim SourceIDT As IDT
   Dim TestIDT As IDT

   SourceIDT.id = 1234
   Debug.Print "SourceIDT.id = " & SourceIDT.id ' returns 1234

   CopyMemory ByVal TestIDT, ByVal SourceIDT, LenB(SourceIDT)
   Debug.Print "TestIDT.id = " & TestIDT.id ' get 1234
   ' to do: free
End Sub
like image 177
Drake Wu Avatar answered Feb 03 '26 23:02

Drake Wu


You need to assign it to the element of ID that has a matching type, not the ID itself. Like

pID.hDefProc = GetWindowLongPtr(Application.hwnd, -21)
like image 38
Dick Kusleika Avatar answered Feb 04 '26 00:02

Dick Kusleika



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!