Using Win32 functions in Visual FoxPro Image Gallery
Passing parameters to Win32 functions
Oct 15, 2003. News2News
Summary: Learn how to pass parameters to Win32 functions in Visual FoxPro versions 3 to 8, including passing by value and by reference, populating and passing structures and more.
Passing parameters by value
Passing parameters by reference
Allocating memory with API functions
Passing NULL for LPCTSTR parameter
Calling Win32 functions with different interfaces
Populating structures
Structures with pointers
Callback function as an input parameter
Passing parameters by value
Pass either variable or direct value.
DECLARE INTEGER FindWindow IN user32;
    STRING lpClassName, STRING lpWindowName

LOCAL hWnd, lcWindowName
lcWindowName = "Calculator"

hWnd = FindWindow (.Null., lcWindowName)  && a variable
hWnd = FindWindow (.Null., "Calculator")  && a direct value
Many API functions require null-terminated strings as parameters. You don't really need to end string parameters with Chr(0), but if you want to -- it does not harm.
Passing parameters by reference
Pass parameter as a reference if:

a) Win32 function is going to change it
b) This is a FoxPro string variable used as a buffer for a Win32 structure

It is not complicated to find which parameter should be passed by reference. If you still are not sure, check MSDN page for the function. Usually it contains [in], [out], or [in/out] before each parameter's description.

An example for type (a) is the
ReadFile function, which is declared as
DECLARE INTEGER ReadFile IN kernel32;
    INTEGER   hFile,;
    STRING  @ lpBuffer,;
    INTEGER   nNumberOfBytesToRead,;
    INTEGER @ lpNumberOfBytesRead,;
    INTEGER   lpOverlapped

Note that lpNumberOfBytesRead is declared as a reference, because the ReadFile will populate this variable with actual number of bytes read from the file.

Before calling this function you must initialize lpNumberOfBytesRead with a numeric value. It's a very common mistake when a reference to uninitialized variable is passed to external function.
LOCAL lnBytesRead, lcBuffer
lcBuffer = SPACE(250)
lnBytesRead = 0
= ReadFile(hFile, @lcBuffer, Len(lcBuffer), @lnBytesRead, 0)

On return from the ReadFile, if no error occured, lcBuffer and lnBytesRead contain new values.

* * *
Here is an example for type (b). The
GetClipCursor function retrieves screen coordinates of the rectangular area to which the mouse cursor is confined.
BOOL GetClipCursor(
   LPRECT lpRect  // address of structure for rectangle

This function requires RECT structure already allocated in memory and fills it with coordinates of a rectangle.
typedef struct _RECT { 
   LONG left; 
   LONG top; 
   LONG right; 
   LONG bottom; 

As you can see the structure consists from four LONG (4-byte) values, so the total number of bytes is 16.

The easiest way is to create a VFP string of 16 chars length and use it as a buffer for the structure. The way you pass the RECT structure exactly defines how this function is declared:
DECLARE INTEGER GetClipCursor IN user32 STRING @lpRect

LOCAL lcBuffer
lcBuffer = Repli(Chr(0), 16)
= GetClipCursor (@lcBuffer)

You may even use SPACE(16) instead of REPLICATE, though some other Win32 function require real empty strings stuffed with zeroes not with spaces.
Allocating memory with API functions
Memory can also be allocated with API functions GlobalAlloc, LocalAlloc, HeapAlloc.

An important difference between them is corresponding Free function releasing allocated memory: GlobalFree, LocalFree, and HeapFree. In most cases you have to release allocated buffer as soon as you don't need it, to prevent memory leak.

Some functions require global memory objects only. For example, an address of a buffer allocated in memory passed to the SetClipboardData function must be a global address. Otherwise Microsoft recommends using heap functions as faster ones and with more features available.

Here is another example. Notice that now GetClipCursor function is declared in a different way. The parameter is now passed as a value. This is an address of allocated memory block. This address is not going to be modified by the function. The GetClipCursor function will write some data at this address instead. Your task is providing sufficient amount of memory.
#DEFINE GMEM_FIXED  0  && the memory block is not movable

DECLARE INTEGER GetClipCursor IN user32 LONG lpRect
DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER wFlags, INTEGER dwBytes

LOCAL lnBuffer
lnBuffer = GlobalAlloc(GMEM_FIXED, 16)
= GetClipCursor(lnBuffer)
. . .

= GlobalFree(lnBuffer)

Passing NULL for LPCTSTR parameter
An example:
HDC CreateDC(
   LPCTSTR lpszDriver,        // driver name
   LPCTSTR lpszDevice,        // device name
   LPCTSTR lpszOutput,        // not used; should be NULL
   CONST DEVMODE* lpInitData  // optional printer data

Two ways of passing a NULL value:

a) declare this parameter as a STRING and pass empty string or Chr(0)
b) declare this parameter as an INTEGER and pass zero

Calling Win32 functions with different interfaces
The RtlMoveMemory (or CopyMemory) function is used for copying data from an address in memory to VFP string and in opposite direction.
VOID CopyMemory( 
   PVOID Destination,   // copy destination 
   CONST VOID* Source,  // memory block 
   SIZE_T Length        // size of memory block 

The memory address is always a numeric value, whether it is used as a source (MemToString) or a destination (StringToMem).

A VFP string, when a source, can be passed by value or by reference. When used as a destination it has to be passed strictly by reference.

That's how there are at least two declarations for this function:
DECLARE RtlMoveMemory IN kernel32 As StringToMem;

DECLARE RtlMoveMemory IN kernel32 As MemToString;

Note that any new declaration for a Win32 function discards the preceding one. That means you have to declare such Win32 function before using with a different interface.

Correction: VFP8 supports more than one declaration per external function. So for example,
CopyMemory can be declared one time to copy data from memory address to FoxPro string, and at the same time with different alias and parameters to copy data from FoxPro string to memory address.
Populating structures not an ordinary job. There is no direct way, but sideways. I could only dream of something like TYPE...ENDTYPE.

First create an empty string and keep appending substrings to it, one after another until it reaches or exceeds the structure's required size. Here is an example - the PRINTDLG structure used as a parameter in the
PrintDlg call:
typedef struct tagPD { 
   DWORD           lStructSize; 
   HWND            hwndOwner; 
   HGLOBAL         hDevMode; 
   HGLOBAL         hDevNames; 
   HDC             hDC; 
   DWORD           Flags; 
   WORD            nFromPage; 
   WORD            nToPage; 
   WORD            nMinPage; 
   WORD            nMaxPage; 
   WORD            nCopies; 
   HINSTANCE       hInstance; 
   LPARAM          lCustData; 
   LPPRINTHOOKPROC lpfnPrintHook; 
   LPSETUPHOOKPROC lpfnSetupHook; 
   LPCTSTR         lpPrintTemplateName; 
   LPCTSTR         lpSetupTemplateName; 
   HGLOBAL         hPrintTemplate; 
   HGLOBAL         hSetupTemplate; 

Passing a string of 66 spaces is not enough.
LOCAL lcBuffer
lcBuffer = Repli(Chr(0), 66) && will not work

Several fields in this structure must be populated, starting with lStructSize, which has to be set to 66 -- the structure's size.

Now let's talk about DWORDs. The DWORD (same is applicable to HWND, HDC, HINSTANCE etc.) occupies 4 consecutive bytes in memory with lower bytes stored at the left. This is how lStructSize is assembled (note again that the lowest byte comes first):
lcBuffer = Chr(66) + Chr(0) + Chr(0) + Chr(0)    && creates DWORD buffer

The following two functions can be used for converting numeric values to 4-byte and 2-byte string buffers:
FUNCTION  num2dword (lnValue)
#DEFINE m0       256
#DEFINE m1     65536
#DEFINE m2  16777216
    LOCAL b0, b1, b2, b3
    b3 = Int(lnValue/m2)
    b2 = Int((lnValue - b3 * m2)/m1)
    b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
    b0 = Mod(lnValue, m0)
RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)

FUNCTION  num2word (lnValue)
RETURN Chr(Mod(m.lnValue,256)) + Chr(Int(m.lnValue/256)) 

The PRINTDLG is now populated using num2dword and num2word functions:
lcBuffer = num2dword(66) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
    num2dword(PD_RETURNDC) +;
    num2word(65535) +;
    num2word(65535) +;
    num2word(1) +;
    num2word(65535) +;
    num2word(1) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;
        num2dword(0) +;

or even more compact version
lcBuffer = num2dword(66) +;
        Repli(Chr(0), 16) +;
    num2dword(PD_RETURNDC) +;
    num2word(65535) +;
    num2word(65535) +;
    num2word(1) +;
    num2word(65535) +;
    num2word(1) +;
        Repli(Chr(0), 36)

Structures with pointers
Sometimes a structure member is an address of allocated memory block. An example is the OPENFILENAME structure:
typedef struct tagOFN { 
   DWORD         lStructSize; 
   HWND          hwndOwner; 
   HINSTANCE     hInstance; 
   LPCTSTR       lpstrFilter; 
   LPTSTR        lpstrCustomFilter; 
   DWORD         nMaxCustFilter; 
   DWORD         nFilterIndex; 
   LPTSTR        lpstrFile; 
   DWORD         nMaxFile; 
   LPTSTR        lpstrFileTitle; 
   DWORD         nMaxFileTitle; 
   LPCTSTR       lpstrInitialDir; 
   LPCTSTR       lpstrTitle; 
   DWORD         Flags; 
   WORD          nFileOffset; 
   WORD          nFileExtension; 
   LPCTSTR       lpstrDefExt; 
   LPARAM        lCustData; 
   LPCTSTR       lpTemplateName; 
#if (_WIN32_WINNT >= 0x0500)
   void *        pvReserved;
   DWORD         dwReserved;
   DWORD         FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)

lpstrFilter, lpstrCustomFilter, lpstrFile and some other are not strings but 4-byte pointers to strings. Prior to assembling the structure several memory buffers must be allocated. And then the appropriate OPENFILENAME members are "stuffed" with these addresses.
LOCAL lcFilter, lnFilter
lcFilter = 'Text Files' + Chr(0) + '*.txt;*.bak' + Chr(0)+Chr(0)

DECLARE INTEGER GlobalAlloc IN kernel32;
    INTEGER wFlags, INTEGER dwBytes

DECLARE RtlMoveMemory IN kernel32 As Str2Mem;

* allocating memory block
lnFilter = GlobalAlloc(GMEM_FIXED, Len(lcFilter))

* copying string data to the memory block
= Str2Mem(lnFilter, @lcFilter, Len(lcFilter))

Now lnFilter contains proper memory address. Remember to release it after the external function returned (GlobalFree).
Callback function as an input parameter
Many Win32 functions require a callback function as an input parameter. The CopyFileEx function is an example.
BOOL CopyFileEx(
   LPCTSTR lpExistingFileName,           // name of existing file
   LPCTSTR lpNewFileName,                // name of new file
   LPPROGRESS_ROUTINE lpProgressRoutine, // callback function
   LPVOID lpData,                        // callback parameter
   LPBOOL pbCancel,                      // cancel status
   DWORD dwCopyFlags                     // copy options

You may want to use a callback function for displaying a progress bar while copying files.

In languages like C, Delphi and VB this part is comparatively easy: you just create a function with a predefined interface and obtain a reference to it. It is different in Visual FoxPro: there is no documented way of doing that. In other words you can not pass a reference to a FoxPro function when calling the CopyFileEx routine, unless you create separate DLL or FLL module.
MSDN article: DECLARE - DLL Command.
A class library created by Christof Lange. Converts structures into Visual FoxPro objects. Supports simple structures, and also pointers, arrays, included structures (substructures), and of course a combination of all.

APIStructure topic on FoxPro Wiki.
Oct 15, 2003. News2News

Copyright 2001-2017 News2News, Inc. Before reproducing or distributing any data from this site please ask for an approval from its owner. Unless otherwise specified, this page is for your personal and non-commercial use. The information on this page is presented AS IS, meaning that you may use it at your own risk. Microsoft Visual FoxPro and Windows are trade marks of Microsoft Corp. All other trademarks are the property of their respective owners. 

Privacy policy
Credits: PHP (4.4.9), an HTML-embedded scripting language, MySQL (5.6.37), the Open Source standard SQL database, AceHTML Freeware Version 4, freeware HTML Editor of choice.   Hosted by Korax Online Inc.
Last Topics Visited (
1 sec.Example: 'How to print FoxPro form'
3 sec.Example: 'How to enumerate terminal servers within the specified Windows domain'
5 sec.Function: 'NetGetDCName'
Function group: 'Network Management'
6 sec.Function: 'JetEndSession'
8 sec.Function: 'waveOutSetVolume'
11 sec.Example: 'Displaying dimmed window behind VFP top-level form'
14 sec.Example: 'How to ping a remote site using ICMP API calls'
17 sec.Solution: 'Extended MessageBox Library (assembly) for .NET'
19 sec.Example: 'Winsock: sending email messages (SMTP, port 25)'
23 sec.Example: 'Validating the heap of the calling process'
Advertise here!