TVITEM structure for 64 bit VBA in MS Access

100 views Asked by At

I'm stuggling with a crash in MS Access where I have to work with an ocx TreeView item via the Win32 API. The 32 bit code I have works with the TVITEM when used with SendMessage:

Public Type TVITEM
    Mask As Long
    hItem As LongPtr
    State As Long
    StateMask As Long
    pszText As String
    cchTextMax As Long
    iImage As Long
    iSelectedImage As Long
    cChildren As Long
    lParam As LongPtr
End Type

But it seems it's causing a crash when used with SendMessage on 64 bit MS Access. Can anyone confirm that the structure is correct for 64 bit, and if not how it should be arranged so it works?

TIA

Edit (20/07/2023 11:16): context for this is the code is trying to hide or show check boxes on specific nodes in the treeview:

If oModTreeViewParent.CheckBoxes Then
    If blnHide Then
        With typTVI
            .hItem = lpModNodeHandle
            .Mask = TVIF_STATE
            .StateMask = TVIS_STATEIMAGEMASK
            .State = 0 'ShiftLeft(1, 12)
        End With
        lpTemp = SendMessageA(oModTreeViewParent.hWnd, TVM_SETITEMA, CLngPtr(0), typTVI)
        'Debug.Print lpTemp & " - " & lpModNodeHandle
        blnModCheckBoxHidden = True
    Else
        With typTVI
            .hItem = lpModNodeHandle
            .Mask = TVIF_STATE
            .StateMask = TVIS_STATEIMAGEMASK
            .State = 1 'ShiftLeft(0, 12)
        End With
        lpTemp = SendMessageA(oModTreeViewParent.hWnd, TVM_SETITEMA, CLngPtr(0), typTVI)
        'Debug.Print lpTemp & " - " & lpModNodeHandle
        blnModCheckBoxHidden = False
    End If
End If

Edit (20/07/2023 15:57): OK, minor update. It looks like using TVM_SETITEMW in SendMessage stops the crash, however it doesn't hide the check box(es). The SendMessage comes back with 0^ in both the 32 bit and 64 bit environments. I'm not sure if this is helpful or not.

Edit (02/08/2023 11:46): Tried to add a Padding long to the structure as per comment, but the crash still occurs in 64 bit Access. Without the Padding and in 32 bit Access all works fine.

2

There are 2 answers

1
xMRi On

You can't use SendMessage with a pointe rto the TVITEM object to a window that resides in another process space.

The pointer you are using is a pointer to the TVITEM object in your program. Wenn the message arrives in MS-Access in the other process space, it tries to dereference the pointer and finds nothing there...

You need to inject code into the other process. Or you need to allocate memory in the other process space. Prepare the data in the other process and use SendMessage again, with the address you just allocated.

2
Alex Guteniev On

Add padding:

Public Type TVITEM
    Mask As Long
    Padding As Long // <-- here
    hItem As LongPtr
    State As Long
    StateMask As Long
    pszText As String
    cchTextMax As Long
    iImage As Long
    iSelectedImage As Long
    cChildren As Long
    lParam As LongPtr
End Type

This makes the layout matching the default MSVC alignment, which is 8. It means that 8 byte integers and pointers will always start at offset that is a multiple of 8, ditto for 2 and 4 byte sizes.

Most of the structures in the Platform SDK created the way that they are not dependent on alignment, but sometimes it is screwed, especially after x64 transition.