Search notes:

Accessing and calling DLLs from VBA: Pointer to structs

This test aims at trying to pass a type (struct in c) to a DLL.

dll.c

The DLL defines a struct (named FOO) and a function passPtrToFOO which takes a pointer to this struct.
If the pointer passed to the function is a null pointer, the function just displays a message box that a null pointer was passed.
If a non-null pointer is passed, the function displays a message box with the values of the stuct elements.
#include <windows.h>

struct FOO {
   char* str;
   int   num;
};

__declspec(dllexport) int __stdcall passPtrFOO(struct FOO* ptrFoo) {

    char buf[200];

    if (! ptrFoo) {
  
        MessageBox(0, "ptrFoo is null", "passPtrFOO", 0);
  
     // return 0 (false) to indicate that ptrFoo was a null pointer
        return 0;
    }
  
  
    wsprintf(buf, "str = %s, num = %i", ptrFoo->str, ptrFoo->num); 
    MessageBox(0, buf, "passPtrFOO", 0);
  
 // return -1 (true) to indicate that ptrFoo was not a null pointer
    return -1;

}
Github repository VBA-calls-DLL, path: /pointer-to-struct/dll.c

call-the-dll.bas

This is the VBA program that uses the DLL.
First, a type is defined that matches the struct in the DLL.
It then declares three aliases for the function so that (a pointer) to the type (or a null pointer) can be passed to the DLL function either as FOO, as any or as longPtr.
It then declares a variable (f, which is a FOO) and initializes its members.

Running the VBA program

The function is then ready to call the DLL function.
option explicit

type FOO
  str as string
  num as long
end type

'
' "Normal" operation: the c-struct / VBA-type FOO is passed
' as a pointer to the DLL:
'
declare function passPtrFOO                                _
        lib "c:\github\VBA-calls-DLL\pointer-to-struct\the.dll"  _
        alias "passPtrFOO"                                    (  _
                 ptrFoo as FOO                                   _
        ) as boolean

declare function passPtrFOOasAny        _
        lib "c:\github\VBA-calls-DLL\pointer-to-struct\the.dll"  _
        alias "passPtrFOO"                                    (  _
           NullPtrFoo as any                                     _
        ) as boolean

'
' "Hack": Using a longPtr along with byVal, a null pointer
' can be passed to the DLL:
'
declare function passNullPtrFOO        _
        lib "c:\github\VBA-calls-DLL\pointer-to-struct\the.dll"  _
        alias "passPtrFOO"                                    (  _
           byVal NullPtrFoo as longPtr                           _
        ) as boolean

    

sub main()

    dim f as FOO

    f.str = "hello world"
    f.num =  42

  '
  ' Pass the struct as pointer.
  ' Works ok
  '
    if not passPtrFOO(           f ) then
'   if not passPtrFOO( ptrFoo := f ) then
       msgBox "Unexpectedly, passPtrFOO returned false"
    end if

    if not passPtrFOOasAny(f) then
       msgBox "Unexpectedly, passPtrFOOasAny returned false"
    end if

  '
  ' Trying to pass a null pointer.
  ' It does not work if (or because) the parameter is declared with 'as any':
  '
    if not passPtrFOOasAny(0) then
       msgBox "Unexpectely, passPtrFOOasAny returned false"
    end if

  '
  ' Pass the number 0 as a longPtr which will be
  ' interpreted as a null pointer in the DLL:
  '
    if passNullPtrFOO( 0 ) then
       msgBox "Unexpectely, passNullPtrFOO returned true"
    end if

  '
  ' varPtr creates a pointer - BUT the BSTR f.str is
  ' not converted into a c string. Instead of »hello world", just
  ' an »h« is received.
  '
    if not passNullPtrFOO( varPtr(f) ) then
       msgBox "Unexpectedly, passNullPtrFOO returned false"
    end if

end sub
Github repository VBA-calls-DLL, path: /pointer-to-struct/call-the-dll.bas
First, f is passed as FOO. The DLL receives a pointer to the struct and is able to display the values of the members of the struct. Note: VBA automagically converts its BSTR strings to char* for the DLL:
The second call uses passPtrFOOasAny to demonstrate that f can also be passed to the DLL as any. The DLL displays the same message box.
The third call tries pass a null pointer to the DLL. However, the intent fails. The DLL receives a pointer to an unitialized struct and displays
However, a null pointer can be passed by calling the function as longPtr.
Lastly, the function is called with varPtr(). This passes a pointer to the struct to the DLL, but the BSTR is not converted to a char*, thus, the DLL displays the following message box:

dll.def

LIBRARY the
EXPORTS
  passPtrFOO
Github repository VBA-calls-DLL, path: /pointer-to-struct/dll.def

See also

Accessing and calling DLLs from VBA (Visual Basic for Applications)

Index