 |
 |
 |
 |
 |
 | | Passing parameters by value ..top |
 |
 | | 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 ..top |
 |
 | 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;
} RECT, *PRECT;
|
 |
 | 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 ..top |
 |
 | 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
DECLARE INTEGER GlobalFree IN kernel32 INTEGER hMem
LOCAL lnBuffer
lnBuffer = GlobalAlloc(GMEM_FIXED, 16)
= GetClipCursor(lnBuffer)
. . .
= GlobalFree(lnBuffer)
|
 |
 | | Passing NULL for LPCTSTR parameter ..top |
 |
 | | 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 ..top |
 |
 | 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;
INTEGER, STRING @, INTEGER
DECLARE RtlMoveMemory IN kernel32 As MemToString;
STRING @, INTEGER, INTEGER
|
 |
 | 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 ..top |
 |
 | ...is 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;
} PRINTDLG, *LPPRINTDLG;
|
 |
 | | 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) +;
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 ..top |
 |
 | | 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;
LPOFNHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
#if (_WIN32_WINNT >= 0x0500)
void * pvReserved;
DWORD dwReserved;
DWORD FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAME, *LPOPENFILENAME;
|
 |
 | | 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;
INTEGER, STRING @, INTEGER
* 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 ..top |
 |
 | | 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.
|
 |
 | | Links ..top |
 |
 | MSDN article: DECLARE - DLL Command.
ftp://ftp.prolib.de/public/vfp/struct.zip
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-2013
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.1.55-log), the Open Source standard SQL database,
AceHTML Freeware
Version 4, freeware HTML Editor of choice. Hosted by Korax Online Inc. |
 |
 |
|
 |
 |
|
|