---------------------------------------------------------
The Liberty Basic Newsletter - Issue #50 - SEP 99
"Knowledge is a gift we receive from others."
		- Michael T. Rankin
---------------------------------------------------------
In this issue:

What is thunking?
Why thunk?
Calling 32-bit DLLs with call32.dll
What else do you need to know?
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: 
   "i" for a 32 bit integer, word or handle type, 
   "p" for any pointer or struct type, or 
   "w" for an HWND parameter you want to pass a 16 bit HWND to and 
       have be automatically converted to a 32 bit HWND.  

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:brosco@orac.net.au
                       or
           mailto:awatson@mail.wctc.net
---------------------------------------------------------