Liberty Basic is develeopped by Carl Gundel
Original Newsletter compiled by Alyce Watson and Brosco
Translation to HTML: Raymond Roumeas

The Liberty Basic Newsletter - Issue #50 - SEP 99

"Knowledge is a gift we receive from others." - Michael T. Rankin

In this issue:

  1. What is thunking?
  2. Why thunk?
  3. Calling 32-bit DLLs with call32.dll
  4. What else do you need to know?
  5. Source Code

In future issues:

Message Box Tutorial - by Larry Dunham


*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***

This article assumes that the reader already possesses some knowledge and proficiency in making API calls in Liberty BASIC. For more information, please see LB API calls for Everybody at http://sidebyside.webjump.com/

Also, unfortunately there have been reports that call32.dll does not work on all systems. Most people report success, however.

*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***
What is thunking?

For Liberty BASIC programmers, thunking means calling on 32-bit DLLs from the 16-bit environment of LB. This cannot be done directly, because 16-bit Windows and 32-bit Windows handle memory differently. We can do thunking by using a small DLL that was specifically written for this purpose.

Here is the definition of thunk from ZDNet's Webopedia:

thunk:

(verb) In PCs, to convert a 16-bit memory address to a 32-bit address, and vice versa. Thunking is necessary because Intel's older 16-bit microprocessors used an addressing scheme called segmented memory, whereas their new 32-bit microprocessors use a flat address space . Windows 95 supports a thunk mechanism to enable 32-bit programs to call 16-bit DLLs. This is called a flat thunk.

On the other hand, 16-bit applications running under Windows 3.x and Windows for Workgroups cannot use 32-bit DLLs unless the 32-bit addresses are converted to 16-bit addresses. This is the function of Win32s, and is called a universal thunk.

According to folklore, the term thunk was coined by the developers of the Algol-60 programming language, who realized late one night that the data type of parameters could be known with a little forethought by the compiler. That is, by the time the compiler processed the parameters, it had already thought of (thunked) the data types. The meaning of the term has changed considerably in recent years.

(noun) The operation of converting between a segmented memory address space and a flat address space.

For a more technical explanation, try the following URL, which also explains that "thunk" is the past tense of "think" at two in the morning!

http://star.informatik.rwth-aachen.de/jargon300/thunk.html


Why thunk?

Code should be as simple and straight-forward as possible to get the job done properly. Don't thunk if you don't need to!! Sometimes, it is necessary, though. An example that many people use, is the one written by Michael T. Rankin that disables CTRL-ALT-DELETE. This is not possible in 16-bit Windows, so it must be thunked. Michael has graciously permitted us to include his code with this newsletter.

You also may need functions contained in a third-party DLL, which is only available in a 32-bit version. It is becomming more difficult to find 16-bit DLLs, so thunking can be a real life-saver.

(The authors have successfully thunked a 32-bit third-party DLL, so it can be done!)


Calling 32-bit DLLs with call32.dll

Here is the notice that is published with call32.dll:

***

CALL32.DLL: 32-bit DLL calling library for Visual Basic by Peter Golde

(modified by Rob Lichtefeld 10-Sep-1996)

This program is placed in the public domain. Please feel free to redistribute as you wish. No guarantees are made as to its suitability or usefulness, and no support can be provided [by Peter Golde.]

***

When Brian Pugh first introduced his find of call32.dll to our group, Brosco translated the example provided with the DLL into Liberty BASIC format. The sample code is quite complex, requiring many calls that are unfamiliar to most of us. It is attached here for the adventurous. This article will stick to something simpler to understand; a Windows Message Box call.

Without a doubt, the easiest way to use call32.dll is to convert 32-bit Visual BASIC calls to Liberty BASIC syntax with Brosco's API Converter. (Note that this incredible utility will convert any Visual BASIC calls, 16- or 32- bit to Liberty BASIC format.)

It is attached to this newsletter for your convenience.

The first step in doing this is to have all necessary VB DECLARE statements for the DLL in question saved to disk in a text file. The native Windows 16-bit calls are in the Win31api.txt file, while the 32-bit versions are in the Win32api.txt file. Both of these files are available on Brosco's site:

http://users.orac.net.au/~brosco/

If you need to make calls to a third-party DLL, be sure that you have the VB versions of the calls handy in a text file. A VB call looks like this:

Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hwnd As Long) As Long

The API Converter makes the job of thunking quite a lot easier. You need to OPEN the text file that contains the VB Declares. If you choose the Win32api.txt file, it may take a few minutes to load into the converter.... this is a BIG file!

You can choose to generate 16-bit calls, 32-bit calls, or a routine that contains both. You can also access Constants and Structures. You can choose to save the output to a file. You can choose to have the VB source included in the code. You can even choose to have the code copied automatically to the clipboard.

In the example used here to make a Message Box, you will NOT see ANY of the following:

OPEN "user32.dll" for DLL as #user
CallDll #user, "Messagebox", hwnd as word, Title$ as ptr, _
Message$ as ptr, wType as word, result as short
CLOSE #user

Call32.dll accesses User32.dll for you, so you do not open it, close it, or call it yourself in any way. You only call on the functions of call32.dll. You tell call32.dll the name of the DLL to be used, which function in the DLL will be called, and which paramater types will be passed.

Here is what you WILL see:

First, the VB syntax is listed for reference:

' "user32" Alias "MessageBoxA" (ByVal hwnd As Long, ByVal lpText As String,
ByVal lpCaption As String, ByVal wType As Long) As Long

Next, call32.dll is opened:

' open the DLL
open "call32.dll" for dll as #call32

Now is the time to initialize the DLL. Each call that will be used in your program needs to be initialized with a call to the function "Declare32" This function names the call, lists the parameter types that will be passed into the call, and assigns an ID number to this particular API call. This function will be explained in more detail later in this article. Here is the familiar call to create a message box, but in 32-bit format:

' Define the call specs to Call32
calldll #call32, "Declare32", _
"MessageBox" as ptr, _ 'name of function to be called
"user32" as ptr, _ 'name of DLL
"ippi" as ptr, _ 'parameter types used, in order
idMessageBox as word 'assign an ID# to this function

Having initialized a call, you may use it anywhere in your program. To make a 32-bit message box call, use the API Converter to find the Windows Constants needed to indicate the type of message box. For the example, we'll use:

wType=_MB_ICONASTERISK OR _MB_OK

Then, we need to specify a caption for the message box. This is the text that appears in the top bar of the box:

lpCaption$="Wow!"

Of course, we need to pass a string containing the message that will be placed into the box:

lpText$="This is a 32-bit call"+chr$(0)

The message box call requires a window handle as one of the parameters. We can get the handle of a program window, but we can also have a null parameter, so in the following call, hwnd has a value of 0. And here is the API call that will create a message box:

' Make the API call
calldll #call32, "Call32", _
hwnd as long, _ 'handle of window - can be 0
lpText$ as STRUCT, _ 'string for message
lpCaption$ as STRUCT, _ 'string for titlebar
wType as long, _ 'type of message box
idMessageBox as long, _ 'call32 ID for this function
result as long 'always returns a long

When your program is finished using the call32.dll (probably in your exit routine) you make a call that frees the memory that was used by the DLL, called

"FreeCall32IDs" :
'Free IDs and Close Call32.dll
calldll #call32, "FreeCall32IDs", _
result as word

Then, as always, close the DLL:

close #call32


What else do you need to know?

Look at the "Declare32" example above. Remember that this is the function needed to initialize all 32-bit calls that will be made with the DLL. Note the following line:

"ippi" as ptr, _

What in the world is "ippi" ??? That parameter contains a string that lists the types, in order, of parameters to be passed in the 32-bit Windows function call.

Each letter in the string declares the type of one argument, and should be either:

The corresponding 16-bit call that we make directly from Liberty BASIC

calldll #user, "Messagebox", _
hwnd as word, _ 'translates to i
Title$ as ptr, _ 'translates to p
Message$ as ptr, _ 'translates to p
wType as word, _ 'translates to i
result as short

In making a function call to call32.dll, we name the call first:

 calldll #call32, "Call32", _

Then, we pass the parameters. In this case, we have four that are to be interpreted as "ippi"

hwnd as long, _
lpText$ as STRUCT, _
lpCaption$ as STRUCT, _
wType as long, _

Next, we pass the ID of the 32-bit function call that we set up in the "Declare32" call:

idMessageBox as long, _

The result comes last, and is always a long integer value:

result as long


Source Code:

'This entire program simply creates a message box.

nomainwin
' Visual BASIC information:
' "user32" Alias "MessageBoxA" (ByVal hwnd As Long,
' ByVal lpText As String, ByVal lpCaption As String,
' ByVal wType As Long) As Long
 
' open the DLL
open "call32.dll" for dll as #call32
 
' Define the call specs to Call32
calldll #call32, "Declare32", _
"MessageBox" as ptr, _
"user32" as ptr, _
"ippi" as ptr, _
idMessageBox as word
 
 
' Initialize variables:
hndl=0 'can also be a valid window handle from LB's HWND function
lpText$ = "This is a 32-bit call"+chr$(0)
lpCaption$ = "Wow!"
wType = _MB_ICONASTERISK OR _MB_OK
 
 
' Make the call
calldll #call32, "Call32", _
hndl as long, _
lpText$ as STRUCT, _
lpCaption$ as STRUCT, _
wType as long, _
idMessageBox as long, _
result as long
 
'Free IDs and Close Call32.dll
calldll #call32, "FreeCall32IDs", _
result as word
 
close #call32


Newsletter compiled and edited by: Brosco and Alyce.

Comments, requests or corrections: Hit 'REPLY' now!

mailto:brosc-@orac.net.au

or

mailto:awatso-@mail.wctc.net