TRANSLATING 32-BIT VISUAL BASIC API CALLS
- intermediate-advanced level
- by Alyce Watson, copyright 2002

Home

Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner

Brad Moore wrote a detailed article on making API calls for the last newsletter. It isn't possible to include every bit of information on this complex subject in a single article. The subject would fill a good-sized book, and in fact there are quite a lot of books available. For those who cannot spend the small fortune required to purchase many of these books, there are plenty of free, online references available as well. The best starting place is the Microsoft Developer Network, or MSDN. It is notoriously difficult to navigate, but it is free and it is packed with information in the form of references, articles, and sample code. Find it here: http://msdn.microsoft.com/ For an API reference, click the link for the Platform SDK. SDK is another of those ubiquitous three letter acronyms (TLA's!) that stands for Software Developer's Kit.

Besides being very large and difficult to navigate, the MSDN documents API calls in C syntax. It is often easier for Liberty BASIC programmers to understand Visual BASIC syntax. There are many Visual BASIC websites with information of all kinds, including API information. My favorite is "The All API Net."

This article was requested by a reader. It is intended for readers who have some experience making API calls, and for those who have read and understood Brad's fine article in issue #101. It is by no means a comprehensive reference or tutorial on translating Visual BASIC API calls. It is meant to be a starting point. Please remember that argument types may need tweaking. What may be passed "As Long" in Visual BASIC may need to be passed "As Ulong" in Liberty BASIC. If you attempt to call an API function and you get a "key is missing" error from Liberty BASIC, this either means that you have omitted an argument, or that one of your arguments is of the wrong type. In this case, check the MSDN and other sources and do some experiementation. Check Brad's article in issue #101 for a list of types to use with API functions and structs.

Perhaps some kind reader will volunteer an article for a future newsletter on translating API calls from C to Liberty BASIC? It would be most welcome.

And now, we'll move on to the translation from Visual BASIC. (I know, you wondered if we'd ever get here!) For an up-to-date copy of the Windows 32-bit API list in Visual BASIC syntax, visit the All API Net, here: http://www.allapi.net

Download and install the API Viewer. You may also want to get the API Guide as a helpful reference, but it is the API Viewer that contains a comprehensive list of functions, constants and structures.

Open the win32 file in the viewer and choose a function. For explanation purposes, we'll use the MessageBox function. Here it is in Visual BASIC syntax:

Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long

In code, it will appear as a single line, just as Liberty BASIC API calls must be a single line. Let's take it apart and translate it into a form that Liberty BASIC can understand.

We can ignore this part:
Declare Function

This part tells us which DLL contains the function:
Lib "user32"
For us, we change this to
calldll #user32,

This is the name that Visual BASIC gives the function:
MessageBox

Liberty BASIC cannot assume that this is the function name. We must check and see if the function has an "alias" name, which is the real name of the Windows function. In this case, there IS an "alias" name, and this is the one we use:
Alias "MessageBoxA"

We now have, for LB:
calldll #user32, "MessageBoxA",

Now comes the list of arguments, which follows the opening bracket. Hungarian notation is usually used to describe the arguments. See the latter part of this article for more on Hungarian Notation. The "ByVal" modifier means that the argument is passed by value, not as a pointer (by reference). The "hwnd" means handle, and "As Long" is translated "As Long".
(ByVal hwnd As Long,

For LB:
hwnd as long,

A "String" in Visual BASIC is passed "as ptr" in Liberty BASIC. The "lp" in "lpText" stands for "long pointer".
ByVal lpText As String,

For LB:
lpText$ as ptr,

Although it isn't used in this particular API call, if a string is passed "ByRef", it is passed as a memory location that can be altered by the API function. Liberty BASIC automatically adds a null terminator to strings that we pass as pointers. If we want to tell Liberty BASIC to pass a string "ByRef", we add our own null terminator. This is simply a signal to Liberty BASIC. We do not need to pass a string this way for our message box call, but as an example, to pass a string "ByRef":
lpText$=space$(100)+chr$(0)
and then in the call
lpText$ as ptr,

The next argument is similar to the previous one:
ByVal lpCaption As String,

In LB:
lpCaption$ as ptr,

The "wType" argument is passed in VB "As Long". The "w" can signify "word" and it may be possible to pass this value "As Word" in Liberty BASIC. If a function translation gives an error, try changing to a different type for some of the arguments. A "long" is a signed value. A "ulong" is an unsigned value. Both types are 4-bytes, but the type "long" reserves one bit for the sign, either positive or negative. The type "ulong" being unsigned, doesn't reserve a bit for the sign, so it can contain a larger number than a "long", but it can only contain a positive number. Type flags are generally unsigned, so passing as "word" or "ulong" is advised.
ByVal wType As Long

In LB:
wType As Long
or
wType As uLong
or
wType As word

And last, we have the value given after the closing bracket:
) As Long
This is the return from the function. If there is no value after the closing bracket, the API call doesn't return a value. Liberty BASIC always requires a return-type argument, so if there is no value returned, use "result as void". For this one, though, use:

result as long

The entire function

calldll #user32, "MessageBoxA", hwnd as long,lpText$ as ptr,lpCaption$ as ptr,wType As uLong, result as Long

Note that the api call must be all on one line in the code! Here is a working program that uses the line continuation character to list the arguments on separate lines. Please remember that this article is not meant to explain the use of any individual API function, but to give some guidelines for translating from VB to LB syntax. Issue #51 contains a message box tutorial by Larry Dunham. The old tutorial is for 16-bit Liberty BASIC 1.4x or 2.0x, but with the information in this article, I'm sure that you can update the methods for 32-bit LB3 easily!

lpText$="An error has occured!"
lpCaption$="Oh No!"
wType=_MB_ABORTRETRYIGNORE or _MB_ICONHAND

calldll #user32, "MessageBoxA",_
hwnd as long,_
lpText$ as ptr,_
lpCaption$ as ptr,_
wType As uLong,_
result as Long

select case result
    case _IDABORT
    print "Abort button was selected."

    case _IDCANCEL
    print "Cancel button was selected."

    case _IDIGNORE
    print "Ignore button was selected."

    case _IDNO
    print "The No button was selected."

    case _IDOK
    print "OK button was selected."

    case _IDRETRY
    print "Retry button was selected."

    case _IDYES
    print "Yes button was selected."
end select

***********************************
TYPES/STRUCTS

Although we didn't need a struct in the MessageBoxA call, we do need them for some API functions. In Visual BASIC, you will find them called "Type" rather than "Struct". Here is a typical Type in VB syntax as retrieved from the All API Net Viewer:

Private Type POINTAPI
x As Long
y As Long End Type

In Liberty BASIC, we must either list a struct and its members on a single line, or use the underscore line continuation character. The Type above would look like this as a Struct:

struct POINTAPI, x as long, y as long

In LB, we start with the keyword "struct", then include the name we are giving to the struct, followed by a comma, then a comma separated list of struct members, along with their types. We can spread the struct declaration over multiple lines by using the line continuation character:

struct POINTAPI,_
    x as long,_
    y as long

When referring to Type members in Visual BASIC, use this syntax:
POINTAPI.x = 47

In Liberty BASIC syntax:

POINTAPI.x.struct = 47

The method above assigns a value to a struct member. To retrieve a value that has been placed there by an API function, do this:

print POINTAPI.x.struct 'print the value
    'or
    x1 = POINTAPI.x.struct 'assign value to a variable
    'or 
    print 2 * POINTAPI.x.struct 'use in a calculation

To pass a struct into an api call:

POINTAPI as struct,

Earlier we discussed the difference between passing a string by reference and by value. "By value" passes the contents of the string to the function. "By reference" passes the actual memory address of the string so that the function can modify the value. When we need to pass a numeric value by reference, rather than by value, we place it in a struct. The function can then modify the number contained in the struct. For an example of this at work, look at the piano.bas program that ships with Liberty BASIC.

***********************************
CONSTANTS

Liberty BASIC recognizes many Windows constants and will supply the proper value when they are preceded by an underscore. For instance, the constant _MB_OK is recognized by Liberty BASIC and can be used as such. If LB gives you an "undefined Windows constant" error, then use the API Viewer to look up the value of the constant. It will be given as a hexadecimal number. The API Viewer output will look like this:

Private Const MB_ABORTRETRYIGNORE = &H2&
Private Const MB_OK = &H&
Private Const MB_YESNOCANCEL = &H3&
Private Const MB_YESNO = &H4&
Private Const MB_USERICON = &H80&
Private Const MB_USEGLYPHCHARS = &H4
Private Const MB_TYPEMASK = &HF&
Private Const MB_TOPMOST = &H40000&

To determine a value, you can set up a constant of your own using the hexdec() function:

MB.ABORTRETRYIGNORE = HEXDEC("&H2&")

Be sure to put the hex string within quote marks. You may determine the decimal value like this:

print HEXDEC("&H2&")

OOOPs. LB has a slight bug in the hexdec function. The "&" character following the "2" is perceived to be a number (since it isn't, LB incorrectly supplies a zero in this spot), and printing the above will give you a value that is incorrect by a power of 1, assuming that the "2" is in the "16's" column, it will give you "32" for an answer. Be sure to remove trailing characters, like this:

print HEXDEC("&H2")

The value for this one is 2. You may then substitute the decimal value

MB.ABORTRETRYIGNORE = 2

To discover if LB recognizes a constant, try printing it:

print _MB_ABORTRETRYIGNORE

The above will print
2

***********************************
VISIT THESE WEBSITES FOR MORE ON HUNGARIAN NOTATION
http://www.gregleg.com/oldHome/hungarian.html
http://web.umr.edu/~cpp/common/hungarian.html


Home

Liberty BASIC News
Safe Registry and Ini File Alternative
Deleting and Renaming Disk Files
Segments and Flushing
Flat Toolbar with Toolips
Translating 32-bit VB API Calls
Event-Driven Programming Concepts
Spotlight on the Community!
ODBC in Liberty BASIC
Hex Viewer
Listing Files Recursively
Registering Hot Keys
Preventing more than 1 instance
Multi-Coloured Text Input Boxes
Images on Buttons and Statictext
Two Demos by David Conner