Most DLL routines are written in C. Developers using Visual Basic have to translate the syntax of a typical API routine into a Visual Basic DECLARE statement. Doing this requires some knowledge of how arguments are passed in both C and Visual Basic. The following information is helpful in determining how to set up DECLARE statements in the Global Module of a Visual Basic application.
In C, numeric arguments are usually passed by Value; a copy of the value of the argument is passed to the routine. Sometimes C arguments are pointers, and these arguments are said to be passed by reference. Passing an argument by reference allows the called routine to modify the argument and return it to the calling routine. C strings (null terminated strings) and arrays are always passed by reference.
By default, Visual Basic passes all of its arguments by reference. In effect, when arguments are passed to a Visual Basic procedure, they are actually passed as "far" (32 bit) pointers to those values. To pass arguments to a C routine expecting arguments to be passed by value, you have to use the ByVal keyword with the argument in the Declaration statement.
To complicate matters, Visual Basic strings do not use the same format as C strings. Visual Basic uses the ByVal keyword to mean, "pass a C string by reference," when it is used with a string argument in a Declare statement. The table in Figure 10 describes how selected arguments in an API call should be passed.
FIGURE 10: Visual Basic arguments and appropriate declarations Argument Declaration ----------------------------------------------------------------- A standard C string (LPSTR, char far *) ByVal S$ A Visual Basic String (see note) S$ An integer (WORD, HANDLE, int) ByVal I% A pointer to an integer (LPINT, int far *) I% A long (DWORD, unsigned long) ByVal L& A pointer to a long (LPDWORD,LPLONG,DWORD far *) L& A standard C array (A) Base type of Array A Visual Basic array A() A structure (user-defined TYPE) S As Struct ----------------------------------------------------------------- End of Figure 10
Never pass a Visual Basic string or array to a DLL routine unless the DLL was written specifically for use with Visual Basic. Visual Basic strings and arrays are represented in memory by descriptors, not pointers. These descriptors are useless to DLL routines that were not written with Visual Basic in mind.
Visual Basic also allows arguments to be passed AS ANY. The AS ANY declaration tells Visual Basic not to do any type checking for that argument. The developer can pass the function any parameter, as long as it is what the function is expecting. If not, the application can terminate with a UAE (Unrecoverable Application Error). If an argument is declared AS ANY, the call must specify how the argument will be passed to the calling function. To do this, use the ByVal keyword for strings and for arguments that should be passed by value, and omit ByVal keyword for arguments that should be passed by reference.
For example, using Btrieve, if the key buffer parameter must be passed differently depending on the operation that is to be performed, you would declare the Key Buffer parameter AS ANY in the Global Module and set up the Btrieve call as shown in Figure 11.
FIGURE 11: Visual Basic Key Buffer declaration and Btrieve call 'Global Module Declare Function btrcall Lib "wbtrcall.dll" (ByVal Op%, ByVal Pb$, Db As Any, DL As Integer, Kb As Any, ByVal Kl%, ByVal Kn%) As Integer 'Open File OPEN%=0 PosBlk$=space$(128) FileName$ = "f:\data\file.btr " DL%=Len(DataBuf) KLen% = Len(FileName$)
Status% = btrcall(OPEN%, PosBlk$, DataBuf, DL%, ByVal FileName$, KLen%, 0)
End of Figure 11
Notice that the key buffer parameter (FileName$) is specified to be passed by Value. Later in the code, if you wanted to pass a user-defined type for the key buffer on a GET EQUAL operation, you would pass the structure by name for the key buffer as shown in Figure 12.
FIGURE 12: Passing structure by name 'Global Module Type DateStruct Day As String * 1 Month As String * 1 Year As Integer End Type Global Birthdate As DateStruct
'Main Module 'Get Equal GE%=5 DLen% = Len(DataBuf) Birthdate.Day = Chr$(3) Birthdate.Month=Chr$(6) Birthdate.Year=1966 KbLen% = Len(Birthdate) KeyNum% = 1
Status% = btrcall(GE%, PosBlk$, DataBuf, DLen%, Birthdate, KbLen%, KeyNum%)
End of Figure 12
To call Btrieve for Windows from a GFA-Basic Windows application, the declaration shown in Figure 3, Part A, must be made in the global section of your code. Since the Position Block, Data Buffer, Data Buffer Length, and Key Buffer parameters need to be FAR pointers, the "l" argument means LONG for the four-byte FAR address. The "w" argument stands for WORD, or two-byte addresses.
FIGURE 3: Declaration and Btrieve call for GFA-Basic for Windows
Part A: Declaration DLL #10,"C:\WINDOWS\SYSTEM\WBTRCALL.DLL" DecL Word btrcall (w,l,l,l,l,w,w) Pascal EndDLL Part B: Btrieve Call Status& = ^btrcall(opcode&, V:Posblk$, V:DataBuf, V:DataBufLen, V:KeyBuf$, KeyBufLen&, KeyNum&) END of FIGURE 3
The actual Btrieve call to the DLL should look like the call shown in Part B of Figure 3. The "^" character before the btrcall function name tells the GFA compiler that the next variable name is an external function name. The "&" character after the variable name means "integer" in GFA-Basic, just as the "%" sign would in Microsoft Basic. The "V:" designation is equivalent to VARPTR in Microsoft Basic, which stands for "variable pointer."
In Visual Basic for Windows, there are only two accepted methods for passing the key buffer parameter:
One method is to use the user-defined TYPE structure. First, pass an integer key value on a Get Equal operation as shown in the following code segment:
Type Index3Search Age As Integer End Type Dim SearchOnKey3 As Index3Search
Then, make a Btrieve call similar to the following:
SearchOnKey3.Age = 38 KeyBufLen = LEN(SearchOnKey3) KeyNum = 3
status = btrcall(BGETEQUAL, PosBlk$, DataBuf, DataBufLen, SearchOnKey3, KeyBufLen, KeyNum)
Another method of handling integer key types is to write an MKI$ Function equivalent to the one provided with the Microsoft QuickBasic compilers. One example of such a function call is shown in the following code segment.
Function MKI$ (I%) TempI& = I% If TempI& < 0 Then TempI& = TempI& + 65536 End If Byte1% = TempI& / 256 Byte2% = TempI& Mod 256 C1$ = Chr$(Byte1%) C2$ = Chr$(Byte2%) MKI$ = C2$ + C1$ End Function
The parameter setup and Btrieve call you would issue next would look like:
SearchOnKey3$ = MKI$(38) KeyBufLen = LEN(SearchOnKey3$) KeyNum = 3
status = btrcall(BGETEQUAL, PosBlk$, DataBuf, DataBufLen, SearchOnKey3$, KeyBufLen, KeyNum)
Copyright © Madis Kaal 2000-