Vous êtes sur la page 1sur 35

DLL Tools

Version Windows

1.0

Documentation

1995-1996 ACI SA Tous droits rservs

Introduction
4e Dimension possde un langage procdural trs riche incluant pas moins de 350 commandes. Cependant, il peut arriver que vous ayez besoin d'accder des fonctions spciques non incluses dans ce langage gnrique. Souvent, la fonctionnalit requise existe dj sous la forme d'une "Dynamic Link Library" (DLL). Une DLL est un morceau de code que l'on peut appeler partir de n'importe quelle application, elle est partage par diffrentes applications et le lien est dynamique. Pour appeler une des fonctions de la DLL, il suft simplement den connatre le nom.
NOTE: L'interface de programmation de Windows est elle-mme base sur des DLLs, la plupart des fonctions tant incluses dans les chiers "Kernel32.DLL", "user32.DLL" ou "GDI32.DLL.

Pour appeler une fonction Windows, vous pouvez crire une extension 4D en C ou C++ qui appellera la fonction dsire. C'est une solution envisageable si votre extension excute un traitement complexe en plus de cet appel. En revanche, si vous avez besoin d'appeler une routine simple (par exemple, la fonction API Windows "GetDiskSpace" pour connatre l'espace restant sur le disque dur), lcriture de cette extension risque d'tre complexe et fastidieuse. Le package DLLTools vous propose une manire simple de rsoudre ce problme. Il vous permet d'appeler virtuellement toute DLL 32 Bits, depuis le code de 4D. Avec "DLLTools", vous pouvez charger n'importe quelle DLL 32 Bits, dclarer n'importe quelle fonction contenue dans cette DLL et l'appeler. Vous pouvez passer des paramtres, rcuprer des valeurs Vous avez, de plus, un jeu de commandes trs utiles pour allouer des blocs mmoires Windows ainsi que la possibilit de lire et dcrire des donnes en mmoire. DLLTools est implment uniquement sous Windows, l'architecture Macintosh n'utilisant pas ce type de librairies.

Installation
Ce package est constitu des chiers "DLLTOOLS.4DX" et "DLLTOOLS.RSR" qui doivent tre placs dans un dossier nomm "Win4DX" plac au niveau de la structure de la base. Les "GDI32.TXT", "Kernel32.TXT" et "User32.TXT" sont l pour vous aider trouver une routine particulire, ils ne sont pas utiliss par DLL Tools.

Contenu du package
Le package DLLTOOLS contient 19 routines diffrentes, regroupes en 5 thmes :
s s s s s

Memory management : Gestion des blocs mmoire Windows. Pokes : Ecrire des donnes en mmoire. Peeks : Lire des donnes en mmoire. Libraries : Charger et librer des librairies. Fonctions : Dclarer ou appeler des fonctions.

Initiation
DLL tools vous permet d'appeler n'importe quelle DLL, toute fonction des API Windows est dsormais accessible. Pour vous aider trouver dans quelle DLL une fonction particulire se trouve, DLL tools vous propose des chiers listant le contenu desDLL Windows les plus utilises qui sont :
s s s

"Kernel32.DLL", "User32.DLL", "GDI32.DLL".

Ces chiers textes sont appels "Kernel32.TXT", "User32.txt" et GDI.txt. Ils sont gnrs par la commande "dumpbin" de Microsoft Developper Studio v4.0. Ces chiers textes ont t raliss sur les bases d'une station de travail NT 3.5.1, mais la plupart des fonctions se retrouvent sous Windows 95 et Windows 3.1 avec Win32s install. An de vous familiariser avec DLL TOOLS, nous vous proposons de raliser un exemple simple implmentant un appel la fonction Beep des API Windows.

1. Ouvrez le chier "kernel32.txt" et regardez si le "Beep" est bien rfrenc dans ce chier.

2. Ouvrez une base 4D et crez une nouvelle procdure nomme par exemple "Call_Beep". La fonction "Beep" se trouvant dans le chier "Kernel32.dll", nous devons charger cette librairie. Pour se faire, nous utiliserons la fonction "LoadLibrary" de DLL Tools. 3. La premire ligne de votre procdure sera donc :
Lib:=LoadLibrary("Kernel32.dll")

La variable "Lib" contient dsormais une rfrence la librairie "Kernel32.dll". Nous devons ensuite prciser :
s s s

quelle fonction de la DLL nous voulons appeler, quel type de paramtre cette fonction attend, et quels type de paramtres seront renvoys.

Il faut pour cela une description de l'API 32 bit de Windows que nous trouverons soit dans un manuel de programmation Windows soit dans l'aide en ligne d'un environnement de dveloppement, tel que Visual C++ ou Borland C++. L'aide de Visual C++ donne la description suivante de la fonction "Beep" :

"Beep" est dclare comme une fonction retournant un boolen (BOOL en notation Windows), et reoit deux paramtres DWORD (entiers longs).

4. A ce stade, nous faisons un appel la fonction "DeclareCall" pour indiquer DLL Tools quels sont les paramtres attendus par la fonction et quel type de rsultats seront retourns.
Call:=DeclareCall(Lib;"BOOL Beep(DWORD,DWORD)";0)

Le premier paramtre de DLL est la rfrence de la librairie dans laquelle la fonction se trouve. Dans notre cas, nous passons la valeur Lib retourne par "LoadLibrary".
s

Le second paramtre est une chane dcrivant le type de la valeur retourne par la fonction, son nom et le type de ses paramtres. Cette manire de dclarer est semblable celle utilise en C et suit les mmes rgles. Les types standards du C et de Windows sont grs par DLL Tools, comme CHAR, LONG, DWORD, UWORD et d'autres encore. Vous trouverez la liste complte des types de paramtres avec le descriptif de la commande DeclareCall.
s

NOTE: Pour des paramtres moins courant tel que LPPAINTSTRUCT ou LPCOMMTIMEOUTS, vous devez les dclarer dans un type que DLL tools puisse reconnatre, par exemple la dclaration standard de pointeur LPVOID dans le cas de LPPAINTSTRUCT .

Le dernier paramtre est la convention d'appel de la fonction. La plupart du temps, l'appel est fait en pascal (l'appelant empile les arguments de droite gauche dans la pile, et la fonction appele dpile les arguments de la pile avant de revenir). Passez 0 si vous voulez ce type d'appel, (declar __stdCall, ou WINAPI en interface Windows). Passez 1, si vous voulez utiliser la convention C pour passer des arguments (__cdecl).
s

Une fois la fonction dclare, vous avez une rfrence que vous pouvez maintenant utiliser pour effectuer l'appel. 5. Utilisez la fonction "CallDLL" de DLL tools. N'oubliez pas de crer des variables 4D qui contiendront les valeurs passer en paramtre et y recevoir la valeur renvoye. Pour notre exemple, nous dclarons et initialisons 3 variables de type entier long :
C_ENTIER LONG(ReturnValue;Frequency;Duration) Frequency:=500 Duration:=1000

6. Enn appelons notre fonction :


Err:=CallDLL(Call;Frequency;Duration;ReturnValue) 7

Notez qu'il faut passer la valeur retourne en dernire position. Ensuite, si on n'a plus besoin d'appeler cette fonction, on libre la structure alloue pour sa dclaration. 7. Vous pouvez aussi librer la librairie si vous n'avez plus besoin d'utiliser "Kernell32.dll" pour d'autres fonctions.
FreeCall(Call) FreeLibrary(Lib)

8. Passez ensuite en mode Utilisation directe et excutez votre procdure, votre ordinateur mettra un beep! Si votre procdure doit souvent tre appele dans votre base de donnes, ou si vous voulez loptimiser, vous pouvez charger les librairies et dclarer les fonctions une fois pour toute dans la procdure "debut", et les librer juste avant de quitter la base de donnes. Cette initiation est maintenant termine. La seconde partie vous prsente en dtails les 19 routines du package DLL TOOLS. La suite de ce manuel est en Anglais (une version franaise sera trs prochainement disponible).

LES ROUTINES

Memory management
These functions are designed to give you easy access to basic Windows memory management routines. These routines can be declared and called directly using DLL tools, but it's easiest and faster to use them directly. These routines are :
s s s

GlobalAlloc, GlobalLock, GlobalSize,

s s s

GlobalFree, GlobalUnlock, GlobalReAlloc.

10

GlobalAlloc
GlobalAlloc(Flags;Size ) -> Long Parameters Flags Size Type LongExpr LongExpr Description Object allocation attributes Number of bytes to allocate

This command is mapped on the Windows API GlobalAlloc function. It allocates the requested amount of memory, and returns a handle on the allocated block. Some functions called with DLL tools will request as parameter a pointer to a memory block. You can create this block with GlobalAlloc. DLL tools provides you with the ability to read or write data inside this blocks (see Peek and Pokes themes). The ags parameters specify the attributes of the allocated block. The following values may be used, or added together: 0 2 GMEM_FIXED, allocates fixed memory. The return value is a pointer to the memory block. You don't need to lock or unlock the block before using it. GMEM_MOVEABLE, allocates movable memory. The return value is a handle of the memory object. You need to call GlobalLock to get a pointer to the memory block. GMEM_DDESHARE, the allocated block may be used for a DDE conversation, or clipboard operations. GMEM_DISCARDABLE, the allocated block is discardable. This ag can not be combined with the GMEM_FIXED ag. GMEM_NOCOMPACT, does not compact memory to satisfy allocation request. GMEM_NODISCARD, does not discard memory to satisfy allocation request. GMEM_ZEROINIT, initializes memory content to zero.

8192 256 16 32 64

If the function fails, the return value is zero. See also: GlobalFree
11

GlobalFree
GlobalFree(Handle ) -> Long Parameters Handle Type LongExpr Description Handle to the global memory object

This function frees the memory block allocated by the GlobalAlloc functions. If the function succeeds, the return value is 0. If the function fails, the return value is the handle of the global memory object. See also: GlobalAlloc

GlobalLock
GlobalLock(Handle) ->Long Parameters Handle Type LongExpr Description Handle to the global memory object

This function locks the global memory object and returns a pointer to the rst byte of the object's memory block. Once locked, the memory block will not move or be discarded until you unlock it. You need to call this function only for the objects allocated using the GMEM_MOVEABLE ag. There is an internal counter which is incremented each time you lock the handle, and decreased each time you unlock it. The block will be actually unlocked only when the counter is set to zero. This is usefull because you can have a procedure A which locks the handle, calls a procedure B which locks and unlocks the same handle, and be back in procedure A with the handle still locked. See also: GlobalUnlock

12

GlobalUnlock
GlobalUnlock(Handle) -> Long Parameters Handle Type LongExpr Description Handle to the global memory object

This function unlocks the global memory object. Once unlocked, the pointer on the memory block is no longer valid, and using it may cause an access privilege exeption. You need to call this function only for the objects allocated using the GMEM_MOVEABLE ag. The handle will actually be unlocked only if the internal lock counter is set to zero. If the object is still locked after this call (if the lock counter is not falled to zero) the return value is 1, and 0 if the object is unlocked. See also: GlobalLock

GlobalSize
GlobalSize(Handle) -> Long Parameters Handle Type LongExpr Description Handle to the global memory object

This function returns the current size, in bytes, of the specied memory object. If the specied handle is no longer valid, or if the object has been discarded, the return value will be zero.
NOTE: The size of the memory block may be larger than the size requested when the memory was allocated, so you can't rely on this size to compute by example the number of elements you stored in the block.

See also: GlobalReAlloc

13

GlobalReAlloc
GlobalReAlloc(Handle;Size;Flags ) -> Long Parameters Handle Size Flags Type LongExpr LongExpr LongExpr Description Handle to the global memory object New size of the block How to reallocate object

This function changes the size or attributes of the specied memory object. If the specied handle is no longer valid, or if the object has been discarded, the return value will be zero.
NOTE: The size of the memory block may be larger than the size requested when the memory was allocated, so you can't rely on this size to compute by example the number of elements you stored in the block.

See also: GlobalSize

14

Pokes
These functions allow you to put specic values anywhere in memory . This is useful if a DLL function needs a pointer to a structure containing particular values. With the memory management functions, you can allocate a memory block, and ll the block using these routines. These routines are :
s s s

SetByte, SetLong, SetCString.

s s

SetShort, SetDouble,

15

SetByte
SetByte(Pointer; Value) Parameters Pointer Value Type LongExpr LongExpr Description Memory Address Value of the byte to set (0->255)

This command sets an unsigned byte located at the specied address. An unsigned byte is one byte long (8 bits) and can hold a value in the range 0 to 255.
w

If you want to pass a signed value, in the range -128 to +127, it's up to you to convert your value before to pass it to the routine, using this conversion algorithm:

if ( value<0) value:=256+value end if SetByte(pt;value)

See also: GetByte

SetShort
SetShort (Pointer; Value) Parameters Pointer Value Type LongExpr LongExpr Description Memory Address Value of the short to set (0->65535)

This command sets an unsigned short value at the specied address. An unsigned short is 2 bytes long (16 bits) and it can hold a value in the range 0 to 65535.
w

If you want to pass a signed value, in the range -32768 to +32767, it's up to you to convert your value to a signed short before to pass it to the routine, using this conversion algorithm:

if ( value<0) value:=65536+value end if SetShort(pt;value)

See also: GetShort


16

SetLong
SetLong(Pointer; Value ) Parameters Pointer Value Type LongExpr LongExpr Description Memory Address Signed long value to set

This command sets a long value at the specied address. A long value is 4 bytes long (32 bits) and can hold a value in the range -2147483648 to +2147483647. See also: GetLong

SetDouble
SetDouble(Pointer; Value) Parameters Pointer Value Type LongExpr RealExpr Description Memory Address Double value to set

This command sets a double value at the specied address. A double value is 8 bytes long (64 bits) and can hold a real value. A real value stored on 64 bits may be positive or negative and range from 1.7 E-308 to 1.7 E+308 with 15 signicants digits.
w

Example

SetDouble( pt; 3,5667 )

See also: GetDouble

17

SetCString
SetCString(Pointer; Text) Parameters Pointer Text Type LongExpr TextExpr Description Memory Address Text to copy

This command will copy at the specied address the specied text. This text will be converted in ANSI characters (4D use internally the Mac Ascii code representation). A null character will be added at the end of the text, because most of the DLL functions are waiting Null terminated strings. If your function is waiting a UNICODE string, you will need rst to call a DLL function that handles this conversion, like WideCharToMultiByte, located in Kernel32.DLL.
w

Example :

SetCString( pt; "Hello World" )

See also: GetCString

18

Peeks
These functions help you to read specic values anywhere in memory. They are usefull if a DLL function returns a pointer to a structure or data containing particular values that you need to read.

GetByte
GetByte(Pointer) -> Value Parameters Pointer Type LongExpr Description Memory Address

This command reads an unsigned byte located at the specied address. An unsigned byte is one byte long (8 bits) and it can hold a value in the range 0 to 255.
w

If you want to read a signed value, in the range -128 to +127, it's up to you to convert your value after reading it, using this conversion algorithm:

value:=GetByte(pt) if ( value>127) value:=value-256 end if

See also: SetByte

19

GetShort
GetShort (Pointer) -> Value Parameters Pointer Type LongExpr Description Memory Address

This command reads an unsigned short value at the specied address. An unsigned short is 2 bytes long (16 bits) and it can hold a value in the range 0 to 65535.
w

If you want to read a signed value, in the range -32768 to +32767, it's up to you to convert your value to a signed short after reading it, using this conversion algorithm:

value:=SetShort(pt;value) if (value>32767) value:=value-65536 end if

See also: SetShort

GetLong
GetLong(Pointer) -> Value Parameters Pointer Type LongExpr Description Memory Address

This command reads a long value at the specied address. A long value is 4 bytes long (32 bits) and can hold a value in the range -2147483648 to +2147483648. See also: SetLong

20

GetDouble
GetDouble(Pointer) -> Value Parameters Pointer Type LongExpr Description Memory Address

This command reads a double value at the specied address. A double value is 8 bytes long (64 bits) and can hold a real value. A real value stored on 64 bits may be positive or negative and range from 1.7 E-308 to 1.7 E+308 with 15 signicants digits.
w

Example :

C_REAL(dbl) dbl:=GetDouble(pt)

See also: SetDouble

GetCString
GetCString(Pointer) -> Text Parameters Pointer Type LongExpr Description Memory Address

This command will return a copy of the text stored at the specied address. This text will be converted from ANSI to Macintosh characters (4D use internally the Mac Ascii code representation). If your want to read a UNICODE string, you need to call rst a DLL function to handle the conversion, like MultiByteToWideChar, located in Kernel32.DLL.
w

Example :

C_TEXT(vText) vText:=GetCString(pt)

See also: SetCString

21

Libraries
These functions are responsible for load and freeing a specied DLL. They are directly mapped on the equivallent functions of Windows API.

LoadLibrary
LoadLibrary(DLLle) -> LibraryRef Parameters DLLle Type AlphaExpr Description Name of library to load

This command loads the specied library in memory and returns a reference to it. The name may be a full pathname or only the lename. In this case, the function will try to locate the le in the following sequence: 1. The directory of 4th Dimension 2. The current directory 3. The Windows System directory 4. The Windows directory 5. The directories listed in the PATH environment variable Each time you load the same Library to the same library it increments a counter. The initialization routine of the library will be performed only the rst time the library will be loaded. When you free the library, the library is really disposed only when the counter falls down to zero. The returned value is a handle to the module, and 0 if the function fails.

22

Example:

Lib:=LoadLibrary("Kernel32.dll") if (Lib#0)

...
FreeLibrary(Lib) end if
w

If your database uses intensively DLL calls, or if you want to improve speed of call, it's a good idea to load the libraries you need and to declare the call at startup, and free everything when you quit 4D.
` Libraries initialization ` Libraries initialization ` Libraries initialization

Startup procedure : Kernel32:=LoadLibrary("kernel32.dll") User32:=LoadLibrary("User32.dll") Gdi32:=LoadLibrary("Gdi32.dll")

Call declaration BeepCall:=DeclareCall(Kernel32;"BOOL Beep(DWORD;DWORD)";0)

...
Exit procedure FreeCall(BeepCall)

...
Free Libraries FreeLibrary(Kernel32) FreeLibrary(User32) FreeLibrary(Gdi32) QUIT 4D

See also: FreeLibrary

23

FreeLibrary
FreeLibrary(LibRef ) Parameters LibRef Type LongExpr Description Reference to the loaded library

This command frees the specied loaded library. Once your library is disposed, you can no longer call a function belonging to this library. Most of the time, you will call these functions just before quitting your database. See also: LoadLibrary

24

Functions
These functions are responsible to declare and call functions of the libraries.

DeclareCall
DeclareCall (LibRef; Declaration; Mode ) -> CallRef Parameters LibRef Declaration Mode Type LongExpr AlphaExpr LongExpr Description Reference to the loaded library Function declaration 0 -> "Pascal" call, 1 -> "C" call

This command declares a function belonging to the specied library, and return a reference. This reference will be requested to call the function. If it returns the error code -20, it means you have passed a bad reference to the library. The rst parameter is the Library reference returned by the LoadLibrary function. The second parameter is a string which declares the following in sequence : 1. the function return type (optional if nothing is returned) 2. the function name 3. under parenthesis, the parameters type, separated by commas. This declaration protocol is the same as the C declaration, so in most of the cases, you simply need to pass in this string the declaration as you will nd it in the description of the function. Please notice that parameters declaration and function names are case sensitive.

25

DLL Tools will parse the declaration to know the type of each parameters. DLL tools recognize the followings types: 8 bits: char, BOOL, BYTE, CHAR, UCHAR, BOOLEAN, CCHAR 16 bits: short, WORD, UWORD, SHORT, USHORT 32 bits: long, word, int, short*, word*, long*, int*, void*, DWORD, LONG, LPVOID, UINT, GLOBALHANDLE, HANDLE, HLOCAL, LPDWORD, LPBOOL, LPBYTE, LPWORD, LPLONG string pointers: char*, LPCSTR, LPSTR, LPCTSTR, LPTSTR, NPSTR, PCSTR, PCWSTR, PSTR, PTSTR double values (64 bits): double, GLdouble void return: void, VOID If your function accepts a parameter type which does not belong to this list, you should pass a parameter type compatible. If your function waits for a pointer to a structure, you need to declare it as a 32 bit pointer, like void*. The unsigned C key word is not recognized by DLL Tools, so you should not use it. Particular case: Structure parameters If the function you want to declare receives a structure as parameter (not a pointer to the structure, but the structure content), you will have to reproduce that in passing successivly all the members of the structure.
w

Example : Calling a function which accepts a RECT parameter.

Original declaration void DoSomething( RECT theRect ); RECT is declared in Windows API as a structure containing 4 longs. You need to declare your call as followed: Call:=DeclareCall(Lib;"void DoSomething( LONG, LONG, LONG, LONG )";0) 26

CallDLL
CallDLL (CallRef; Param1; Param2; ....; Return ) -> err Parameters CallRef Param1 Param2 ParamN Return Type LongExpr Variable Variable Variable Variable Description Reference First parameter Second parameter Nth parameter Return value (optional)

This command calls the function declared with the DeclareCall command. The rst parameter is the reference returned by DeclareCall. The others parameters are 4D variables, and you should pass one variable for each declared parameter. If you functions returns a value, you should pass one more parameter to the function, which will hold the returned value. It is not possible to pass a constant value to the CallDLL function:
Call:=DeclareCall(Lib;"void MyCall(long, char*)";0) $err:=CallDLL(Call;15;"MyString") ` WRONG!

It is mandatory to use variables:


C_LONGINT(vLong) C_ALPHA(255;vString) Call:=DeclareCall(Lib;"void MyCall(long,char*)";0) vLong:=15 vString:="MyString" $err:=CallDLL(Call;vLong;vString)

` CORRECT!

See also: DeclareCall

27

You can only pass 4D variables of the right type to the CallDLL command, even if DLL tools can handle automatically some conversions for you, like converting a real to a long. Here are the possible 4D variables type you can pass for each declared type. 8 bits: (char, BOOL, BYTE, CHAR, UCHAR, BOOLEAN, CCHAR) You can pass a Boolean, integer, longint, time or real 4D variable. The most appropriate variable kind is Integer or Longint, or Boolean if your DLL is also waiting a boolean value. Passing a 4D Real variable is possible but slower (a conversion will be performed). If your function is waiting a signed byte, the example of the SetByte function will show you how to convert an unsigned byte in a signed byte.
s

16 bits: (short, WORD, UWORD, SHORT, USHORT) You can pass a Boolean, integer, longint, time or real 4D variable. The most appropriate variable kind is a 4D integer variable. Passing a 4D Real variable value is possible but slower (a conversion will be performed).
s

32 bits: (long, word, int, void*, DWORD, LONG ...) You can pass a Boolean, integer, longint, time or real 4D variable. The most appropriate variable kind is a 4D longint variable. Passing a 4D Real variable value is possible but slower (a conversion will be performed).
s

String pointers: (char*, LPCSTR, LPSTR, LPCTSTR, LPTSTR...) You can pass an alpha or a text variable. If you pass an alpha variable, be sure that the DLL function will returns you a string of an appropriate size. If you declare an alpha variable of 20 chars long, and you call a DLL functions that will return a string of 80 characters long, you will only get the 20 rst characters in your 4D variables. It's faster to use alpha variables, but they are limited to 255 characters. If your DLL is returning bigger strings, you can use a text variable. The limitation for text variable is 32000 characters. Because 4D uses internally Macintosh extended characters, the strings passed to the DLL functions will be automatically converted in ANSI before to call the function, and reconverted in Macintosh Ascii code after.
s

Double values (64 bits): (double, GLdouble) You can pass a Boolean, integer, longint, time or real 4D variable. The most appropriate variable kind is a 4D real variable. Passing an other numeric value is possible but slower (a conversion will be performed).
s

28

The function may return the following values: Error 0 -1 Description No error The command does not belongs to the DLL (check declaration) Bad numeric parameter (pass a longint variable) Bad string parameter (pass an alpha or text variable) Bad real parameter (pass a real variable) Unknown parameter (is the declaration type correct?) No return variable (pass a variable to hold the returned value) Bad numeric return (pass a longint return variable) Bad string return (pass an alpha or text return variable) Bad real return (pass a real return variable) Unknown return (is the return declaration type correct?) Returned text too long (text returned is longer than 32000 characters, you should allocate a memory block of the appropriate size, and declare a pointer (void*) instead of a string pointer (char*) and pass a pointer to this memory block. Returned string too long (string returned is longer than the size declared for the 4D variable. Declare a larger string size, or pass a text variable). Null returned string (the function should return a string pointer, but this pointer is null).
29

-2 -3 -4 -5 -6

-7 -8 -9 -10 -11

-12

-13

Error -14

Description Missing parameter (a parameter is declared, but not passed at the function). Bad call reference (this reference was not created using the DeclareCall command).

-21

FreeCall
FreeCall (CallRef ) Parameters CallRef Type LongExpr Description Reference

This command disposes in memory the structure created to store the declaration of the function. Once disposed, the function can no longer be called with this reference. You will typically call FreeCall before FreeLibrary, just before quitting your database. See also: DeclareCall

30

Samples
CALLING WINDOWS API FUNCTIONS
GetDiskSpace
The following example allows you to determine the total and remaining space on a hard disk.The function GetDiskFreeSpace of Windows API will perform that. Searching this function in the le "kernel32.txt" gives us a GetDiskFreeSpaceA and a GetDiskFreeSpaceW function. This is because Kernel32.dll implements two functions, one receiving a standard Ascii string (GetDiskFreeSpaceA), and the other receiving a wide-character string, (GetDiskFreeSpaceW). When you call GetDiskFreeSpace from a C or C++ source code, the linker knows if you choose to work with Ascii or Wide-Character strings, and calls the appropriate function in the DLL. With DLL Tools, you directly call the DLL, and you have to know which function to call. In our case, 4D works internally with Ascii code, so we will use the GetDiskFreeSpaceA. Visual C++ gives the following information about this function:

31

All the parameters types are known by DLL Tools, so we can easily describe the function.
Lib:=LoadLibrary("Kernel32.dll") $declaration:="BOOL GetDiskFreeSpaceA( LPCTSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD)" GetDiskSpace:=DeclareCall(Lib;$declaration;0)

This function is waiting for four pointers to long values, so we create a buffer to hold these values, and pass the address of the values in the buffer to the function the addresses of the values.
C_LONGINT(Ad;Ad1;Ad2;Ad3;ReturnValue) Ad:=GlobalAlloc(0;16) Ad1:=Ad+4 Ad2:=Ad+8 Ad3:=Ad+12

C_ALPHA(255;vString)
vString:="C:\"

` We need now to create the string holding the diskname.

$err:=CallDLL(GetDiskSpace;vString;Ad;Ad1;Ad2;Ad3;ReturnValue) SectClust:=GetLong(Ad) BytesSect:=GetLong(Ad1) FreeClust:=GetLong(Ad2) TotalClust:=GetLong(Ad3) $err:=GlobalFree(Ad) FreeSpace:=(FreeClust*SectClust*BytesSect)/1024 TotalSpace:=(TotalClust*SectClust*BytesSect)/1024 ` Read the value in the buffer

` Free the buffer once the values are read ` Compute hard disk free space and total space

32

MultiByteToWideChar
To call the MultiByteToWideChar, Visual C++ provides the following information about this function:

The declarator LPWSTR (pointer to a wide-character buffer) is unknown by DLL Tools. You have the choice to cast it as a pointer (void*) or as a string pointer (char*). You can't cast it as a string pointer, because DLL Tools manages only pointers on ANSI, nullterminated, strings. The solution is to declare it as a pointer (void*), and allocate and manage yourself the buffer to store this wide-character string.
Lib:=LoadLibrary("Kernel32.dll") $declaration:="int MultiByteToWideChar( UINT, DWORD, LPCSTR, int, void*, int)" AtoW:=DeclareCall(Lib;$declaration;0)

The last parameter is 0, telling that the function will be called as a pascal function, like all the functions of Windows API.

33

This 4D procedure will receive a 4D text parameter and return a pointer to the widecharacter buffer.
C_TEXT($1) ` Procedure TextToWideChar C_LONGINT(CodePage;Flags;TextSize;WSize;$0;returnValue) CodePage:=0 Flags:=0 TextSize:=length($1) WSize:=64000 returnValue:=0 $0:=GlobalAlloc(0;WSize) ` allocate a buffer to receive wide-char string if($0#0) err:=CallDLL(AtoW;CodePage;Flags;$1;TextSize;$1;Wsize;returnValue) end if

Calling your own DLL


You have already written in "C" our own 32 bit DLL, named "Custom.dll", and you selected in the Project Settings the __cdecl option ( "C" calls ):

Your C source code declares a function as followed:


void GetMaxRange( long Ref, ObjStruct* object, double Value, char* ObjectName );

34

The declarators void, long, double and char* are recognized by DLL tools but ObjStruct* is specic to your source code. You can in this case replace the ObjStruct* declaration by a void* declaration, telling that the function is waiting a pointer. Your declaration, in the startup procedure may looks like that:
Lib:=LoadLibrary("Custom.dll") if ( Lib#0) GetMaxRange:=DeclareCall(Lib;"void GetMaxRange( long, void*, double, char*)";1) else ` Your library may be not there... ALERT("Custom.dll is not present, please check installation.") end if

The last parameter is 1, telling that you have compiled your DLL with the __cdecl calling convention. Now you can call your function with the following procedure:
C_ALPHA(255;vString) C_LONGINT(vObjStruct;vRef) C_REAL(vValue) vValue:=2 ` ll the long value (rst parameter) vObjStruct:=GlobalAlloc(0;124)` allocate a buffer to store ObjStruct structure ` ObjStruct structure size is 124 bytes long ` Structure content may be read or write using ` DLL Tools Peeks and Pokes utilities functions vValue:=56,323 ` set the real value (third parameter) vString:="Hello, DLL" ` set the last parameter $err:=CallDLL(GetMaxRange;vValue;vObjStruct;vValue;vString) if ($err=0) x:=GetLong(vObjStruct) vName:=GetCString(vObjStruct+4) end if

` read rst long of the structure ` read the C string located at offset+4 in the structure

35

Vous aimerez peut-être aussi