Working with C DLLs in Visual Basic
Some tips
- As working with C functions from Visual
Basic often leads to GPF's while still developing,
remember to save your project before running it.
- As a GPF takes down the IDE, remember to compile and
test using the EXE instead of runnign your code in the IDE...
- By default, Basic passes all parameters by
reference, ie. it passes the address of the
variable and not its actual value. The routine
will thus work on the original data, which is the reason
why changes made inside the routine remain when this
routine returns. Before working with C functions, it's
something that we take for granted.
C, however, passes numeric data by value, and strings
by reference as its default behavior. "Passing
by value" means that the routine will work on a copy
of the value held by the data that is passed to the
routine, ie. the changes made by the routine to this data
will only be local, and the original data will remain
untouched.
For example,
Option Explicit
Dim strGlobalString As String
Sub ValRoutine(ByVal strDummy As String)
strDummy = "ABCD"
MsgBox "strGlobalString=" + strGlobalString +
Chr$(13) + "strDummy=" + strDummy
End Sub
Sub RefRoutine(strDummy As String)
strDummy = "ABCD"
MsgBox "strGlobalString=" + strGlobalString +
Chr$(13) + "strDummy=" + strDummy
End Sub
Private Sub Form_Click()
strGlobalString = "1234"
Call ValRoutine(strGlobalString)
Call RefRoutine(strGlobalString)
End Sub
- The magical words are ByVal and ByRef.
ByRef is implicit, since by default Basic passes
parameters by reference.
- Input strings: If a string will
only be read by a routine, all you have
to do is pass it by value.
Output strings: If a routine will write
into a string you passed it, you must first set it to a
fixed size, long enough to fit.
There are three ways to do this:
Dim strMyString * 128
Dim strMyString
strMyString = Space (128)
Dim strMyString
strMyString = String (128, vbNullChar)
Then, remember to pass this string by value, so that
Visual Basic turns it from a regular BSTR Basic string
(The variable holds 2 information: The address of the
string, and its length) to a C-type string (The variable
only contains the address of the string, and the string
ends with a chr$(0) .)
- If you need to retrieve the address of
either a variable or routine, use the
no-longer-documented-but-still-operational function
VarPtr (). When used with a string, use VarPtr
(strMyString(0)) to get the address of the first
character.
- If you need to declare a variable to hold
the address of a variable, use a Long. As of now, a
pointer is 4-byte wide, just like a Long in VB. if you
need to pass the address of a pointer, ie. a pointer to a
pointer (void** pMyPointer), pass this Long by reference.
- If the C function returned a pointer to a
data block, you can copy it to a VB string by using the
following function:
Public Declare Sub CopyMem Lib "Kernel32" Alias
"RtlMoveMemory" (pTo As Any, pFrom As Any,
ByVal lCount As Long)
- If you need to work with C functions
often, you might want to buy THE classic: Dan Appleman's
"Visual Basic 5.0 Programmer's Guide to the
Win32 API" (ZD Press, $59.99, ISBN
1-56276-446-2.)
- Another great book : "Hardcore VB"
- Getting GPFs ? Check that you got your
ByRef and ByVal right in the DLL declaration; If the DLL
will write to a variable, make sure you either set enough
bytes (strings), or that the variable indicating the
number of bytes available for output is right (eg. if you
pass it a 4-byte buffer, and tell it that this buffer is
8-byte long, the DLL may happily write 8 bytes instead of
the 4 your buffer can hold.
- If you get a 'Bad DLL Calling convention
(Error 49)' when calling an API, check that it was
compiled with _stdcall instead of _default.
Checking loaded DLL's
There are different utilities available to check which DLLs are currently
loaded:
- Use the "Microsoft System Information" utility (MSINFO32.EXE
on your disk. It is probably in some location like: \Program Files\Common
Files\Microsoft Shared\MSInfo. Alternatively, you can run it via the "System
Info..." button in the About box of some Microsoft Office apps (Word,
Excel, Power Point, etc.).)
In the tree view on the left, select
"Active Modules" (or "Loaded modules", depending on
the version you have) to get a complete list of all loaded DLLs, including
the full path of the DLL's filename
- The freeware utility HandleEx
- Display
Loaded Modules v1.5
Resources
Temp stuff
AddressOf
StrConv
StrPtr
VarPtr
BSTR
__cdecl, __stdcall
FnPtr(AddressOf DLLPrnt)