admin管理员组

文章数量:1531349

2024年2月6日发(作者:)

VFP调用Windows API函数正式开始:0 0

我想你可能经常看过如下这种语句,我不得不在这里重复地说一遍

DECLARE INTEGER SetWindowText IN user32;

INTEGER hWnd,;

STRING lpString 0

Hwnd=

customtext=space(250)

lnlen=len(customtext)

SetWindowText(Hwnd,customtext, lnlen)

0

第一个语句就是一般的api定义,意思就是注册一个动态库中的函数SetWindowText ,接受参数 integer类型hwnd, string 类型h的sWindowText 参数,,返回值为intger ,这是参数按值传递的一部分,第三个语句就是调用注册的api函数了,看起来和我们用普通的foxpro函数并无区别,只是多了一步注册的步骤. 0

我们再看看另一种定义,按引用传递的的方式,看到什么不同了吗?

第一个语句就是一般的api定义,意思就是注册一个动态库中的函数SetWindowText ,接受的参数是integer类型hwnd, string 类型h的sWindowText , INTEGER 类型的cch,返回值为intger类型 0

DECLARE INTEGER GetWindowText IN user32;

INTEGER hwnd,;

STRING @lpString,;

INTEGER cch

Hwnd=

Hwnd=

Stext =space(250)

lnlen=250

SetWindowText(Hwnd,@customtext, lnlen)

没错,多了一个伊妹儿的符号:@,注意调用的时候也得加入该符号,此符号的意思是说参数sWidowText是按引用传递的,为什么要这么用呢,原因是我们要用函数GetwindowText 的得到一个窗体(Form)标题.GetwindowText 的职责就是将我们要的值填入sWidowText中,如果调用成功你就会看到sWidowText的值已经改变.此处你要明白所谓的按引用传递有如C中的指针,我们只是该内容的地址为参数传给GetwindowText,它直接在地址指向的内存单元上修改数据.所以我们才可能看到sWidowText值在调用GetwindowText()函数就发生了改变。 0 0 0

0以上两种就是最基本的windows api定义了.对于简单的函数一般都可以这样解决.

也许此时你有疑问,你是在哪里知道这些函数的详细信息的?很好很好,有问题是好的.那么请你打开msdn,什么?你不知道MSDN,我倒..^_^简单而说msdn是涵盖了大量内容的帮助文档,大部分的api在其中都有讲述,有些还有小实例.在这里并不要求你要记住所有windows的api函数,这不可行也不可能,只要知道有它的存在,大概的功能,用时查msdn就可以,更重要的是知道怎么去把它纠出来,然后理解它. 如果你现在没有安装MSDN,我强烈建议你马上下载一个msdn2005.该帮助文档大部分都是E文,你得有点心理准备.

0

键入SetWindowText查询,你就会看到所有相关的函数原型,参数及返回值的解释.此时查询后你看到一些莫名其妙的返回值类型和参数类型.如:

DWORD,LPTSTR 0

为什么不是integer,string呢? 0请听我说,由于window api 是基于c的,而C中有一种叫宏定义的东西,而DWORD,LPTSTR就是一种宏罢了,宏定义时一般以大写出现,只不过是类型的另一种叫法而已再查询DWORD,LPTSTR你就可以看到它们的真面目,DWORD<=>无符号的32位的整型,

LPTSTR<=>字符串指针

注:<=>符号在此代表等价的意思 0 0 0

0

原来DWORD与integer指的同一种数据类型.这就好比有一天在大街上你可能看到一个漂亮的女孩,很是心动,你可能称她为美女或者天使,但最终美女或天使指向的都是这个女孩,不过就是这个女孩的代名词而已.

0

下面我以C为例说明以不同类型来读取相同内存区域后会得到怎么样的内容,我希望你以内存的角度来看。这些原理是相通的,和语言无关,只是C来讲比较方便罢了,所以我选择它来让问题简单化.此步将有助于你理解怎么在foxpro处理含有结构参数的一些复杂 API 函数,虽然这一部分比较枯燥,但我还是希望你努力看下去.如果这道坎过了,下来也就容易许多先来看看简单的变量声明:int icount=0x11ff; //假设你的系统上 int类型 占4个字节,

0 0

0

那么该语句将为你开辟一个四字节的内存空间,假设0x11ff存入内存单元:0x000420000之处,那么内存中是这样的 0

内存地址 内存单元的内容

0x00420000:0xff

0x00420001:0x11

0x00420002:0

0x00420003:0

如果我们现在定义一个字符串指针指向该区域,会是怎么样的呢?

char * cValue= (char *)0x00420000; 0 0

C中的字符串是以chr(0)结尾的,所以当你用* cValue取值的时候,得到的将是这样一个字符串chr(0xff)+chr(0x11)+chr(0)位的整数读取的情况

char * sHello="hello world"; 0 0

现在你应该明白,以整数存放后的内存,后以字符串读出会是什么样的.下面再讲以字符串存入后再以32 0

0连chr(0)在内12个字符长,一字节一个字符,也就是12个字节了.在内存里面它到底是怎么样呢?

这十二个字符将依次放到内存区域当中,不过他不是放的"H" "E" "L" ....chr(0),而是将每个字符转为ascii码后放入

假设以上"hello world"存在内存单元:0x00420000之处,那么hello world在内存中将如下所示:

0

0

内存地址 内存单元的内容

0x00420000:"h"的ascii

0x00420001:"e"的ascii

0x00420002:"l"的ascii

0x00420003:"l"的ascii

0x00420004:"o"的ascii

0x00420005:" "的ascii

0x00420006:"w"的ascii

0x00420007:"o"的ascii

0x00420008:"r"的ascii

0x00420009:"l"的ascii

0x00420010:"d"的ascii

0x00420011:NULL值的ascii,即foxpro中的chr(0)

我们现在声明一个int 指针指向0x00420007之处,int * theValue=(int *)0x00420007;0x00420007:"o"的ascii

0x00420008:"r"的ascii

0x00420009:"l"的ascii

0x00420010:"d"的ascii

那么我们用*theValue得到的值将是:

"d"的ascii向左位移24位+"l"的ascii向左位移16位+"r"的ascii向左位移8位+"o"的ascii所构成的32位整数的值

再说一个结构:Struct

{

int ndvalue;

int nJvalue;

} testStruct;

//size 8 byte

testStruct testResult;

e=0x11

e=0x22 0 0 0 0 0 0 0

0

0而此时0x000420007到0x000420010是"orld",四个内存单元存的分别是

同样假设testResult结构从内存0x00420000开始,下面就是它在内存存储的样子:

内存地址 内存单元的内容

0x00420000:0x11

0x00420001:0

0x00420002:0

0x00420003:0

0x00420004:0x22

0x00420005:0

0x00420006:0

0x00420007:0

0x00420008:0

我们同样也可以用字符串,或32位整数,还有其它类型都可以,来访问该段内存,得到你想要的数据,方法和上面的一样,这里我就不再重述了. 0 0 0

我举这些例子,是要你明白所谓的整型数据,字符串,结构,只是不同的数据表示方法罢了,在内存中已经存在的数据要以什么表示方式来读取完全取决于你的所需.即便你是以字符串存入的,你也可以将它视为数值读出来,反之亦然.

很多api 函数并不是像上面说的函数那么简单,它可能由一些结构组成,抓取一个最简单的示例来说:

0

0

0windows定义了一个名为POINT结构来存放一个座标的信息由有两个分别是32位整型成员组成,如下:

Struct

{

int x;

int y;

}Point; 0

//size= 8 byte

0而api 函数GetCursorPos()恰好就是接收POINT这种结构.它的功能是为你填取其中传递过去地址所指向的结构,让你知道当前鼠标的座标.由于我们要得到参数在调用后的结果,我们得用引用的方式传递参数,这个到现在你要知道.可在foxpro里面没结构类型,你是不是有点抱怨了为什么不提供结构.不过没关系,我们还有办法,主要的就是用字符串来开辟内存,然后将该内存区域当作结构来使用,基本就是如此理解,不过中间得进行一些转换,转换的原理就是上面所讲的以不同类型读取相同内存的内容。下面我再说明

0

首先知道Point结构占八个字节长,由两个四字节的成员组成. 0

那么定义一个长度八个字节的字符串区域,将该区域的地址告诉GetCursorPos, 而GetCursorPos就会对该内存操作,为你老老实实填好它,我们的工作嘛就是将取出来的字符串的值还原成我们想要的成员x和y的整数值. 0

lcPosition = repl(chr(0),8)

lnXCoord = 0

lnYCoord = 0

GetCursorPos(@lcPosition )

LEFT(lcPosition,4) &&就是X的值

right(lcPosition,4) &&就是Y的值 0 0

把原来内存中的内容读成我们想要的32位的整数.请不要说用str()不就可以了.NO,你会这么说,证明你还没看懂我上面说的用不同类型读取相同内存区域的部分,请折回看了再继续.

只要将这些字符取ascii,移位后组成一个32位的数值就达到目的.希望到此你已经明白为什么要如此转.虽然FOXpro8以上都提供了ctobin的函数可以达到相同的功能,但这里我们还是自己来写一段函数来实现4字节字符串到到32位整型的转换

FUNCTION API_STRTOINT(tcSrcString )

RETURN Asc(SUBSTR(tcSrcString, 1,1)) + ;

BitLShift(Asc(SUBSTR(tcSrcString, 2,1)), 8) +;

BitLShift(Asc(SUBSTR(tcSrcString, 3,1)), 16) +;

BitLShift(Asc(SUBSTR(tcSrcString, 4,1)), 24)

ENDFUNCTION

好了,完整的实现就是如下这样了,理论的东西比较多,先有了基础才能高楼筑起lcPosition = repl(chr(0),8)

lnXCoord = 0

lnYCoord = 0

GetCursorPos(@lcPosition )

API_STRTOINT(LEFT(lcPosition,4))

API_STRTOINT(right(lcPosition,4))在这里我小结一下:

从结构中获取内容的步骤,先用字符串分配相应的内存区域,让API函数填取其它内容,根据我们得到的字符串及成员的类型进行相应转换

此处写个32位整数到四字节字符串的函数,就是一个逆转的过程.下面我们要用到

0 0 0 0 0 0 0 0

FUNCTION api_inttostr (tnValue)

#DEFINE mbase 2^8 -1

ch0=BITAND(mbase, tnValue)

ch1=BITAND(bitrshift(tnValue,8),mbase)

ch1=BITAND(bitrshift(tnValue,16)mbase) FDAFDAF

ch1=BITAND(bitrshift(tnValue,24mbase)

ch1=BITAND(bitrshift(tnValue,24mbase)

ENDFUNC

这些就是四字节字符串与32位的整数的相互转换了,在这里我有必要问你个问题?。假如你用字符串的形式把原来内存中16位的整数读出来后,你是否也懂得用相同的操作来逆转显示成16位整数呢,如果你已经知道,并且懂得举一反三了,我将为你感到高兴。倘若还不知道也不要紧,毕竟技术的学习是要时间的,我不能那么苛刻要你马上懂。

下面我再举一个API函数SetLocalTime。和调用GetCursorPos函数刚好相反,GetCursorPos()函数是写结构的内容,然后我们转换结构的内容得到我们要的成员值。而SetLocalTime则是变成我们来写结构,这里用初始化可能恰当些,然后SetLocalTime根据结构的内容来设置当前计算机的时间。同样用字符串的方式来构建一个结构了,不过得先转换每一个成员的值,然后传给SetLocalTimeBOOL SetLocalTime(

const SYSTEMTIME* lpSystemTime

); 0 0 0 0

这是msdn的一函数原型,如果对SYSTEMTIME比较陌生,那么试着用上面查DWORD类型的方法查询该结构

*|* typedef struct _SYSTEMTIME {

*|* WORD wYear; //2 Byte

*|* WORD wMonth; //2 Byte

*|* WORD wDayOfWeek; //2 Byte

*|* WORD wDay; //2 Byte

*|* WORD wHour; //2 Byte

*|* WORD wMinute; //2 Byte

*|* WORD wSecond; //2 Byte

*|* WORD wMilliseconds; //2 Byte

*|* } SYSTEMTIME, *PSYSTEMTIME; -> 16 bytes 0

在这里你应该试着想象一下它在内存是怎么存储的,这里的成员都是16位的整数,有别于上面我们讲的。我们转换它成为两字节的字符串,其实和32位整数到字符串的没多大差别。方法类似

0FUNCTION api_shorttostr (tnValue)

#DEFINE mbase 2^8 -1

ch0=BITAND(mbase, tnValue)

ch1=BITAND(bitrshift(tnValue,8),mbase)RETURN Chr(ch0)+Chr(ch1)

ENDFUNC

下来用该函数让系统根据当前的时间加上300秒 0 0 0

Declare INTEGER SetLocalTime In Win32API STRING lpSystemTime 0

tdate=DATETIME()+300

cYear = api_shorttostr (Year(tdate))

Cmonth = api_shorttostr (Month(tdate))

cWeek=api_shorttostr(DOW(tdate))

cDay = api_shorttostr(Day(tdate))

cHour = api_shorttostr(Hour(tdate))

cMinute = api_shorttostr(Minute(tdate))

cSecond= api_shorttostr(Sec(tdate))

cMsec = api_shorttostr(0)

Local tcresult

tcresult=cYear+Cmonth +cWeek+cDay +cHour +cMinute +cSecond+cMsec

SetLocalTime(tcresult)

==================

终于到了最后了,可能你都看得眼困了。为了让你对于一个复杂的API调用有一个认识,我找一个相对有难度的API函数GetOpenFileName来打开"open"对话框,以此来结束该篇文章。此对话框将有别于getfile()函数所呈现的,他不仅可以多选,还可以设置初始化打开对话框时指定的目录,最难的部分在于结构中含有字符串指针成员,所以在构建该结构的时候,你必须设法得到一个字符串的内存地址,要不无法继续,这里需要用到一些内存堆操作的函数。我并不准备详细说明API函数GetOpenFileName,同样我也相信你也有这种学习能力来读取msdn查阅到你不明白的参数,返回值的作用及类型、我只给出粗略的注释及重要的代码实现部分来加以解释。 0 0

0下面这些函数是为我们的结构的指针成员所准备的,我只讲指针成员实现的部分,其它的就没什么分别

为了得到一个字符串的地址,这里采取的方式是,先分配内存堆,得到指向该内存堆的地址,然后使用RtlMoveMemory将原来字符串的内存块移动到新分配的堆上。那么该堆地址就是我们要的内存地址了。暂时我还无法用文字来告诉你内存原理的能力,文笔实在过于艰涩。如果你对内存堆的原理没有多大认识,我建议你看看windows核心编程的内存管理章节,它会让你受益良多。完整的代码我已经放在文件,你可以下载借鉴运行效果图:

此主题相关图片如下:

0 0

0

HeapCreate() //创建堆对象

HeapAlloc() //在堆上分配内存

HeapFree() //释放分配的内存

HeapDestroy() //释放堆对象

RtlMoveMemory()//移动内存块

对于RtlMoveMemory有以下两种定义,两者的用意如下所示,在此处都要用到

*=======================================

*--移动指定内存区域至指定地址上

*=======================================

DECLARE RtlMoveMemory IN kernel32 As CopyMemory;

Integer Destination,;

STring @Source, INTEGER nLength 0 0

*=======================================

*--移动指定内存区域的内容至到字符串所在的地址

*=======================================

DECLARE RtlMoveMemory IN kernel32 As CopySTRMemory;

String @Destination,;

integer Source, INTEGER nLength

0

*—函数原型

BOOL GetOpenFileName( LPOPENFILENAME lpofn

); 0

*--结构注释

*!* typedef struct tagOFNA {

*!* DWORD lStructSize; 4 //结构大小

*!* HWND hwndOwner; 4 //句柄值

*!* HINSTANCE hInstance; 4 //实例值

*!* LPCSTR lpstrFilter; 4 //过滤器值

*!* LPSTR lpstrCustomFilter; 4 //指针指向自定义的过滤器缓冲区

*!* DWORD nMaxCustFilter; 4

*!* DWORD nFilterIndex; 4 //指定显示过滤器的索引值,以1开始计

*!* LPSTR lpstrFile; 4 //指针指向目录和文件名的路径的字符串

*!* DWORD nMaxFile; 4 //nMaxFile缓冲区的大小

*!* LPSTR lpstrFileTitle; 4 //指针指向文件标题栏的标题栏

*!* DWORD nMaxFileTitle; 4 //文件标题栏的最大宽度

*!* LPCSTR lpstrInitialDir; 4 //初始化时的目录

*!* LPCSTR lpstrTitle; 4 //指针指向标题字符串

*!* DWORD Flags; 4

*!* WORD nFileOffset; 2

*!* WORD nFileExtension; 2

*!* LPCSTR lpstrDefExt; 4 //指针指向一个默认的扩展名字符串

*!* LPARAM lCustData; 4

*!* LPOFNHOOKPROC lpfnHook; 4 //一个勾子的例程,这里忽略它

*!* LPCSTR lpTemplateName; 4 //

*!* #ifdef _MAC

*!* LPEDITMENU lpEditInfo;

*!* LPCSTR lpstrPrompt;

*!* #endif

*!* } OPENFILENAMEA, *LPOPENFILENAMEA;

*!* //Size=76

0

0

本文标签: 内存字符串函数结构类型