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;
}
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
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: