keywords:
DLL, wrapper, INLINE, DECLARE
Hi, and wellcome to something veeery sophisticated, which will turn out to be easy as sending an email, later: Wrapping an external DLL library to be used with GLBasic.
First, we must descide which DLL we might use. As I don't have any other one here, I suggest we take a look at some built in Windows(R)(tm) dlls, and in order to see something quickly we wrap the MessageBoxA function.
OK, first we need to know a few things:
- which dll contains that functionFor our case, that's easy. Just look here:
http://msdn.microsoft.com/en-us/library/ms645505.aspxWhich says:
MessageBox Function
Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message, such as status or error information. The message box returns an integer value that indicates which button the user clicked.
Syntax
int MessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
...
Function Information
Minimum DLL Version: user32.dll
Header: Declared in Winuser.h, include Windows.h
Import library: User32.lib
Minimum operating systems: Windows 95, Windows NT 3.1
Unicode: Implemented as ANSI and Unicode versions.
- what are the parameters and the return valueWe have a set of parameters here like:
HWND , LPCTSTR and UINT.
You can google for them (search for "typedef HWND"), and will find that all parameters can be limited to a few basic types:
strings: char* or const char*. "const char*" means a string, that's contents will not be changed inside the dll function.
integers: 8 bit(char), 16 bit(short), 32 bit(long or int - it's the same), [optional: unsigned]
floating points: 32bit (float), 64 bit(double)
pointer to something: mostly (void*)
We will learn more about pointers, later. No worries, just easy basics.
So we can reduce this parameter list to the basic types:
void*, const char*, const char*, unsigned int
and the return value is an "int".
Aces.
- The function name in the DLLDid you notice
Unicode Implemented as ANSI and Unicode versions.
? Microsoft names their functions with "A" at the end for ANSI and "W" for Unicode. We need the ansi version. Sometimes functions can look totally different, though. So in order to be safe, we download the DependencyWalker from here:
http://www.dependencywalker.com/and open the "user32.dll" from the system32 directory.

At the left side, they cyan box informs us, that this function has a "C" linking (as oposed to C++ linking)., thus we should wrap our "DECLARE" statement in an
extern "C"{ DELCARE... }
later.
It's not obvious if the calling convention is "cdecl" or "stdcall" from the dependency walker. I _know_ that all Microsoft DLLs are stdcall, and if you can load a DLL from VisualBasic, it _must_ be stdcall, so try this first. If it crashes, try with a cdecl convention later.
So, fine. We now have everything we need to get started!
Loading that functionOpen your GLBasic project, and insert a new source file in the file tabs. Make sure you use a separate file for each dll you wrap, to make things a bit more modular.
Now type this code in the new, 2nd file of your project:
// A MessageBox wrapper
INLINE
extern "C" { // it's a C linking, as dependency walker told us
DECLARE_ALIAS(exportMessageBoxA, "user32.dll", "MessageBoxA", (void*, const char*, const char*, unsigned int), int);
} // close the extern "C"
ENDINLINE
The DECLARE_ALIAS statement (notice to write it all capital letters) takes the name of the function to be used in the GLBasic context, then the dll name, then the name of the function in the dll. This can be something complicated like "_kungfu@12" for other calls - just take the name from the dependency walker.
The next argument is the parameter list
in braces!. Last parameter is the return value.
For beginners, please use DELCARE_ALIAS instead of DECLARE.
Wrapping itNow that we loaded the function, we should urge to call it. Therefore, we need a GLBasic function to conveniently call it from our program. Thus we make the wrapper function:
FUNCTION Win32MessageBox: text$, caption$
ENDFUNCTION
Make sure, that the function name does
not equal the first parameter of the DECLARE instruction, or you will have quite some fun with the compiler.
Now we must fill that function with our wrapped dll.
INLINE // of course, GLBAsic does not know about "exportMessageBoxA" - only INLINE does
if(exportMessageBoxA)
return exportMessageBoxA(0, text_Str.c_str(), caption_Str.c_str(), 0);
ENDINLINE
Whoa! Waitaminute!
This is a lot of new stuff for you, so we see ein detail:
INLINE
well, GLBasic does not know about "exportMessageBoxA", but the INLINE C++ part does, so we must go there.
if(exportMessageBoxA)
exportMessageBoxA is a pointer to a function that you created with the DECLARE statement above. GLBasic does the implementation and loading automatically for you. However, if you have a typo, the function cannot be loaded. Then the pointer has the value "0", which means, if you call the function this pointer is pointing at your program will sort of "inform" you about it.

So, to be sure that the function was loaded correctly, we check if it's a valid pointer and then call the function with
exportMessageBoxA(
Last step is to provide the arguments.
text_Str.c_str()
OK, this is a bit hard to explain now. The GLBasic string "text$" is in INLINE called "text_Str". The $ gets "_Str". If you have a number, there's no such problem. Next, the GLBasic string is of type "DGStr", which is a class needed to have you write things like:
a$= "test" + 5 + "foo:" +foo().
Very convenient for you, but in order to get a const char* to the first character, you need to call the "c_str()" function of that class. Just do it, K?
Another thing is, that if you need the char* to this string, you should do:
my_Str.Alloc(1024); // make sure that string has space for 1024 bytes
GetTempPathA(my_Str.GetStrData() );
my_Str.CalcLen(); // have GLBasic find the '\0' character and internally set the string length -> if you manipulate with GetStrData, this must be called!
The MessageBoxA function takes a HWND as the first parameter, which is a pointer to the parent window of that message box. You can use 0 here to say the desktop is the parent. If you want to refer to the GLBasic window, the HWND pointer is gained by calling:
void* hwnd = GLBASIC_HWND();
exportMessageBoxA(hwnd, "test", "test", 0);
The last parameter is the MessageBox appearance. You need a constant integer for this, which you can get my
googling for: "#define MB_OK", which turns out to be 0.
Make sure you end the call with a ';', but don't do a ';' after the "if" statement.
So, now we can call that wrapper from our program:
Win32MessageBox("Test\nText", "Yippieh!")
I think that should be enough to get you started. When you experience trouble, the forum's full of people willing to help you out.
If someone might translate this into the German forum, I'd be very thankful.