I've been getting a lot of questions lately about how to export functions from a DLL so that they can be called from any language that supports calling DLLs. Writing a DLL is pretty straightforward and there are many ways to expose DLL functionality. However, most of them involve mangling the names somewhat. I'm going to describe the process of exporting functions with their original names.
First, unless you must absolutely have C++ code, I recommend writing your DLL in C. Most of you are familiar with C++ name mangling. In addition, calls to C++ class members require a "this" pointer be passed as a hidden argument. Probably the only time this is worthwhile is when the routines will be called from C++. What I want to discuss here is making DLL functions available to languages such as Visual Basic.
You may need to implement your own DLL entry point function and you need to make sure your code uses the stdcall calling convention, but these steps depend on the compiler you are using. For example, with Visual C++, you can create your own entry point with something like /entry:"DLLEntry" on the command line. DLLEntry must refer to a routine in the form of the following.
/////////////////////////////////////////////////////////////////////
// DLL initialization and clean-up.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
// Perform any DLL initialization here
break;
case DLL_PROCESS_DETACH:
// Perform any DLL cleanup here
break;
}
return TRUE;
}
To make sure you use the correct calling convention, tell your compiler to use the stdcall calling convention and/or use one of the constants defined in windows.h (and related files) such as WINAPI. A DLL routine might then look like this.
/////////////////////////////////////////////////////////////////////
// Shifts bits right for integers.
WORD WINAPI vbShiftRight(WORD nValue, WORD nBits)
{
return (nValue >> nBits);
}
The next step is contrary to what you'll read in the Microsoft documentation. You need to create a .DEF file. This is the only way you'll prevent the above function from being exported as something along the lines of _vbShiftRight@1. That .DEF file can be as simple as the following.
EXPORTS
vbShiftRight
Next, we need to call the function. In Visual Basic, you can use a declare statement.
Declare Function vbShiftRight Lib "MYDLL.DLL" (ByVal nValue As Integer,
ByVal nBits As Integer)
As Integer
Sub Test()
Dim i As Integer
i = vbShiftRight(4, 2)
Debug.Assert i = 1
End Sub
If you want to make it really easy to call from VB, you can create a type library. This requires that you create and compile an ODL (object description language) file. This file should include the following lines:
module MyModule {
[
helpstring("Shifts the bits of an integer to the right."),
entry("vbShiftRight")
]
short _stdcall vbShiftRight([in] short nValue, [in] short nBits);
};
When VB loads a DLL's type library, function names and arguments will appear in VB's object browser. In addition, the argument types and names appears as the user types the statement and VB will produce an error if the user does not enter the correct type of arguments.