VFP向Win32函数传递参数
来源:互联网 发布:服装搭配网站知乎 编辑:程序博客网 时间:2024/05/16 08:18
VFP向Win32函数传递参数
2003年10月15日 News2News
摘要:学习如何在VFP3到8里向Win32函数传递参数,包括值传递和引用传递,生成和传递结构,和更多的内容。
目录
值传递
引用传递
用API函数分配内存
传递NULL的LPCTSTR参数
用不同的接口调用Win32函数
生成结构
使用结构的指针
回调(CallBack)函数作为输入参数
值传递
传递变量或值
DECLARE INTEGER FindWindow IN user32; STRING lpClassName, STRING lpWindowNameLOCAL hWnd, lcWindowNamelcWindowName = "Calculator"hWnd = FindWindow (.Null., lcWindowName) && a variablehWnd = FindWindow (.Null., "Calculator") && a direct value
很多Api函数要求以“/0”结尾的字符串作为参数,你不需要真的用chr(0)结束字符串参数,但如果你想这样做,也不会有问题。
引用传递
如果下面情况以引用传递参数:
a) Win32函数要修改参数的值
b) 用作Win32结构缓冲的Foxpro字符串
要知道那个参数将要用引用传递是不难的。如果你还是不肯定,就在MSDN的网站查一下那个函数。通常在每个参数描述前包含了[in],[out]或者 [in/out]。
类别(a)的例子是ReadFile函数,它的声明如下:
DECLARE INTEGER ReadFile IN kernel32; INTEGER hFile,; STRING @ lpBuffer,; INTEGER nNumberOfBytesToRead,; INTEGER @ lpNumberOfBytesRead,; INTEGER lpOverlapped
注意:lpNumberOfBytesRead是声明为一个引用的参数,因为ReadFile将用从读取文件的实际字节数赋给这个变量。
在调用这个函数前必须用一个数值初始化lpNumberOfBytesRead参数。把没有初始化的变量的引用传递到外部函数是非常普遍的错误。
LOCAL lnBytesRead, lcBufferlcBuffer = 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.
如果没有错误发生,ReadFile返回后,lcBuffer和lnBytesRead包含了一个新的值。
下面是类别(b)的例子。GetClipCursor函数重新得到限制鼠标移动范围的矩形区域的屏幕坐标。
BOOL GetClipCursor( LPRECT lpRect // address of structure for rectangle);
这个函数要求RECT结构已分配内存和用矩形的坐标填充它。
typedef struct _RECT { LONG left; LONG top; LONG right; LONG bottom; } RECT, *PRECT;
你能看到这个结构包含了4个LONG(4字节)的值,所以它总的字节数是16。
最容易的方法是生成一个16个字符长度的VFP字符串,并用它作为这个结构的缓冲。这种正确传递RECT结构的方法的定义了这个函数的如何被声明:
DECLARE INTEGER GetClipCursor IN user32 STRING @lpRectLOCAL lcBufferlcBuffer = Repli(Chr(0), 16)= GetClipCursor (@lcBuffer)
你甚至可以用SPACE(16)代替REPLICATE。可是有些其他Win32函数要求用填满零的真空串而不是空格。
用API函数分配内存
内存也可以用API函数GlobalAlloc,LocalAlloc,HeapAlloc分配的。
它们之间的重大差别是相应释放分配了的内存的释放函数:GlobalAlloc, LocalAlloc, HeapAlloc和HeapFree。很多情况里当你不要需要它时你必须释放缓冲去防止内存漏洞。
有些函数只要求全局的内存对象。例如,一个缓冲在内存的分配的地址传递到SetClipboardData函数必须是一个全局的地址。另外,微软推荐使用堆(heap)函数因为是较快速的函数和可得的较多的特征。
下面是另外一个例子。注意现在用不同的方法声明GetClipCursor函数。这个参数现在是作为值传递,这是一个分配了的内存块的地址,这个地址将不被子函数修改。GetClipCursor函数将在这个地址写一些数据来代替,你的任务提供了充够数量的内存。
#DEFINE GMEM_FIXED 0 && the memory block is not movableDECLARE INTEGER GetClipCursor IN user32 LONG lpRectDECLARE INTEGER GlobalAlloc IN kernel32 INTEGER wFlags, INTEGER dwBytesDECLARE INTEGER GlobalFree IN kernel32 INTEGER hMemLOCAL lnBufferlnBuffer = GlobalAlloc(GMEM_FIXED, 16)= GetClipCursor(lnBuffer). . .= GlobalFree(lnBuffer)
传递NUL的LPCTSTR参数
实例:
HDC CreateDC( LPCTSTR lpszDriver, // driver name LPCTSTR lpszDevice, // device name LPCTSTR lpszOutput, // not used; should be NULL CONST DEVMODE* lpInitData // optional printer data);
两种传递NULL值的方法:
a)声明参数为STRING并传递空串或Chr(0)
b)声明参数为INTEGER并传递零值
用不同的接口调用Win32函数
RtlMoveMemory (或者CopyMemory)函数是用来从一个内存中的地址复制数据到VFP字符串和在相反方向的操作。
VOID CopyMemory( PVOID Destination, // copy destination CONST VOID* Source, // memory block SIZE_T Length // size of memory block );
内存地址总是一个数值,它是用作一个源(MemToString)或一个目标(StringToMem)。
VFP字符串,当是一个源时,可以值传递或引用传递。当用作一个目标时,它必须严格被引用传递。
这个函数至少有两种声明:
DECLARE RtlMoveMemory IN kernel32 As StringToMem; INTEGER, STRING @, INTEGERDECLARE RtlMoveMemory IN kernel32 As MemToString; STRING @, INTEGER, INTEGER
注意:一个Win32函数任何新的声明丢弃前面声明的一个。那意味你必须在使用一个不同的接口之前声明如此的 Win32函数。
修正:VFP8支持每个外部函数多于一种声明。所以例如,CopyMemor可以一次声明用来从内存地址到FoxPro字符串复制数据,同时用不同的别名和参数用秋从FoxPro字符串到内存地址复制数据。
组装结构
组装结构不是个普通的工作。没有直接的方法。我只能梦想一些类似TYPE…EDNTYPE。
首先生成一个空的字符串和继续向它追加子串,陆续地,直到它到达或者超过结构的必需大小。下面有一个例子——在调用PrintDlg里的作为参数使用的PRINTDLG结构:
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;
传递一个66个空格的字符串是不足够的。
LOCAL lcBufferlcBuffer = Repli(Chr(0), 66) && will not work将不工作
在这个结构里有几个字段必须被组装的,开始的lStructSize它必须设为66——结构的大小。
现在,让我们讨论DWORD,DWORD(同样可用于HWND,HDC,HINSTANCE等等)在内存占用4个连续的字节,用低字节存贮在左边。LStructSize是如何装配的(再次提醒它最低的字节是来自开始):
lcBuffer = Chr(66) + Chr(0) + Chr(0) + Chr(0) &&创建DWORD缓冲
接下来两个函数可以用来转换数值到4字节和2字节的字符串缓冲:
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))
PRINTDLG正被用num2dword和num2word函数组装:
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)
乃至更精简的版本:
lcBuffer = num2dword(66) +; Repli(Chr(0), 16) +; num2dword(PD_RETURNDC) +; num2word(65535) +; num2word(65535) +; num2word(1) +; num2word(65535) +; num2word(1) +; Repli(Chr(0), 36)
使用用指针的结构
有时一个结构成员是一个分配了的内存块地址。一个例子是OPENFILENAME结构:
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和一些其他不是字符串而是4字节的字符串指针。先组成这个结构的几个内存缓冲必须分配。然后适当的OPENFILENAME成员“填满”这些地址。
LOCAL lcFilter, lnFilterlcFilter = 'Text Files' + Chr(0) + '*.txt;*.bak' + Chr(0)+Chr(0)DECLARE INTEGER GlobalAlloc IN kernel32; INTEGER wFlags, INTEGER dwBytesDECLARE RtlMoveMemory IN kernel32 As Str2Mem; INTEGER, STRING @, INTEGER * allocating memory blocklnFilter = GlobalAlloc(GMEM_FIXED, Len(lcFilter))* copying string data to the memory block= Str2Mem(lnFilter, @lcFilter, Len(lcFilter))
现在lnFilter包含适当的内存地址。记得在外部函数返回后释放它(GlobalFree)。
回调(CallBack)函数作为输入参数
很多Win32函数要求一个回收函数作为一个输入参数。CopyFileEx函数是一个例子。
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 复制选项);
你可能想在复制文件时用一个回调函数显示一个进度条。
在类似C的语言里,Delphi和VB这部分是相当容易的:你只创建一个带有一个预先确定接口和获得一个引用给它的函数。在Visual Foxpro里是不同的:没有资料说明做这个的方法,换句话说,当调用CopyFileEx例程时你不能传递一个FoxPro函数的引用,至少你要创单独的DLL或FLL模块。
- VFP向Win32函数传递参数
- python 向函数传递多个参数
- 向基类构造函数传递参数
- 向基类构造函数传递参数
- 向jQuery函数传递多个参数
- c++向main函数传递参数
- C++函数的数组参数—向函数传递数组
- C++函数的数组参数—向函数传递数组
- C++函数的数组参数—向函数传递数组
- 向sqlplus传递参数
- 向脚本传递参数
- 向脚本传递参数
- 向报表传递参数
- 向Fragment传递参数
- 向脚本传递参数
- 向awk传递参数
- 向RDLC传递参数
- 在VB中实现向函数传递不定个数参数
- 移动会扼杀独立wap吗
- javascriot学习-第五章 DOM编程
- javascriot学习-第六章 脚本编程的相关技术
- 如何优化JAVA程序开发,提高JAVA性能
- 真是气死我了
- VFP向Win32函数传递参数
- onbeforeunload事件
- 手机动画进入三国时代
- 听同学谈有中国特色的软件营销模式
- 创业
- HelloWorld--JAVA程序
- Java & .Net再回顾
- 国产语音卡大比拼
- OutPutAsExcel