You can access external DLLs from Visual Basic by using the Declare statement to declare the name of the function you want to call and the DLL that it resides in. VBScript, however, doesn't support the Declare statement. This article presents an OLE automation object that lets VBScript (or any other environment that can access automation objects) dynamically declare and access functions in external DLLs.
Using the DynamicWrapper Object
The name of the automation object I created is DynamicWrapper, and you can declare it just like any other object in VBScript:
Dim UserWrap As Object Set UserWrap = CreateObject("DynamicWrapper")
Initially, the only method the DynamicWrapper object supports is Register(). You invoke the Register() method to describe an external DLL function before calling it. DynamicWrapper is an unusual automation object in that it dynamically adds new methods at runtime. The basic idea is that you first invoke DynamicWrapper.Register() to declare some DLL function named (for example) "SomeFunc", and the DynamicWrapper object suddenly supports a method called SomeFunc() that you can invoke to access the external DLL function. You can register and then invoke any number of external functions with a single DynamicWrapper object.
You have to call Register() to tell the DynamicWrapper object all the details about the external DLL function you want to call, including the name, calling convention, number and type of parameters, and type of return value. The following syntax is used to register a procedure:
[result = ] object.Register <dllname>, <procname> [,<tag>,...]
For example, the standard Win32 function MessageBox() resides in the DLL user32.dll and has the following C prototype:
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
To register this function, you would call Register() like this:
UserWrap.Register "user32.dll", "MessageBoxA", _ "i=hssu", "f=s", "r=l"
The first two parameters are obviously the name of the DLL and the name of the function to call. If you're not certain that the DLL resides in a directory in the current command search path, then you should use a fully qualified pathname. Also note that the function named here is "MessageBoxA" and not "MessageBox". Win32 (and some third-party DLLs as well) often supports both an ANSI and a Unicode version of the same function, so there is no actual user32.dll export called "MessageBox", but there is a "MessageBoxA" and a "MessageBoxW". You must know the exact details of the external DLL function you want to call in order to invoke it correctly. Using a command like dumpbin /EXPORTS target.dll can be helpful in verifying the exported name of a DLL function.
After the function name comes three optional tag parameters that describe the function's calling convention, input parameters, and return type. You can list these optional parameters in any order, but they must be separated by commas.
The tag that describes the input parameters of the function takes the following form:
where <flag> is one of the flags shown in Table 1, and each flag describes (in order) the type of a parameter that the function takes. The function MessageBoxA() takes a window handle, two strings, and an unsigned integer, which can be described with the string "i=hssu".
A function's calling sequence is the specification for exactly how it expects parameters to be pushed on the stack and returned, who is responsible for adjusting the stack pointer, and so on. Most exported DLL functions use a common calling sequence, but there are important exceptions, and DynamicWrapper can handle most of them. The syntax for the optional argument that details a function's calling sequence is:
where <flag> is one of the flags shown in Table 2. If you omit this optional argument, Register() uses "f=ms" as the default. Some flags are mutually exclusive as noted in Table 2. The default is correct for most DLL functions.
Finally, if the function you want to call returns a value, you must specify the type with an argument of the form:
where <flag> is one of the characters described in Table 1. If the function returns no value, simply omit this parameter when you call Register().
After you call Register() to declare the function, you can then call it using the syntax:
Using the previous example, you would invoke MessageBoxA() (the ANSI version of MessageBox()) like this:
UserWrap.MessageBoxA Null, "Hello World", "VBScript", 3