很多API函数都是很长很长的。想看什么样子吗?如下就是作为例子的API DdeClientTransaction函数∶
Declare Function DdeClientTransaction Lib "user32" (pData As Byte, ByVal cbData As Long, ByVal hConv As Long, ByVal hszItem As Long, ByVal wFmt As Long, ByVal wType As Long, ByVal dwTimeout As Long, pdwResult As Long) As Long
哇!这么长?如果你从来没有接触过API,我想你肯定被吓住了。你也许考虑,该不该继续学下去。不过不要担心,幸运的是Microsoft的设计家们为我们提供了有用的工具,这便是API
文本查看器。
让我们回想一下。在VB中,如何声明函数呢?我想,如果你正在看此文,那么你绝对能够回答得出这个问题。以下便是你应该很熟悉的函数声明∶
Function SetFocus (ByVal hwnd As Long) As Long
即,这行代码定义了名为SetFocus的函数,此函数具有一个Long型数据类型的参数,并按值传递(ByVal),函数执行后将返回一个Long型数据。
2 API入门教程
API函数的声明也很类似,如,API中的SetFocus 函数是这样写的∶
Declare Function SetFocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long
有点复杂了一些。是的,是复杂了点。但我可以告诉你,除了这些多出来的部分,其他部分还是和你以前学到的东西是一样的。函数在程序中的调用也是一样。如:
Dim dl As Long
dl&=SetFoucs(Form1.Hwnd)
但,一点是清楚的。它不象你自己写的程序那样能够看到里面的运行机理,也不像VB
自带的函数那样,能够从VB的联机帮助中查到其用法。唯一的方法就是去学、查VB以外的资料。
那么,别名究竟有什么用途呢?从理论上讲,别名提供了用另一个名子调用API的函数方法。如果你指明了别名,那么尽管我们按Declare语句后面的函数来调用该函数,但在函数的实际调用上是以别名作为首要选择的。如,以下两个函数(Function,ABCD)声明都是有效的,他们调用的是同一个 SetFocus函数∶
Declare Function SetFocus Lib "user32" "SetFocus" (ByVal hwnd As Long) As Long
Declare ABCD SetFocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long
API函数中使用的数据类型基本上和VB中的一样。但作为WIN32的API函数中,不存在Integer
数据类型。另外一点是在API函数中看不到Boolean数据类型。 Variant数据类型在API函数中是以Any的形式出现,如Data As Any。尽管其含义是允许任意参数类型作为一个该API函数的参数传递,但这样做存在一定的缺点。其原因是,这将会使得对目标参数的所有类型检查都会被关闭。这自然会给各种类型的参数调用带来了产生错误的机会。
为了强制执行严格的类型检查,并避免上面提到的问题,一个办法是在函数里使用上面提到到Alias技术。如对API函数 GetDIBits 可进行另外一种声明方法。如下∶
GetDIBits函数的原型∶
Public Declare Function GetDIBits Lib "gdi32" Alias "GetDIBits" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
3 API入门教程
GetDIBits函数的改型∶
Public Declare Function GetDIBitsLong Lib "gdi32" Alias "GetDIBits" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Long, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
通过本课程前面所学到的知识,我们已经可以得知原型 GetDIBits函数也好,改型 GetDIBitsLong函数也好,实际将调用的都是Alias所指定的 GetDIBits原函数。但你应当看到,两者的区别在于,我们在改型的函数中强制指定lpBits参数为Long形。这样就会使得函数调用中发生的错误机率减少到了最小。这种方法叫做"安全类型"声明。
Public Const ABM_ACTIVATE = &H6
Public Const RIGHT_CTRL_PRESSED = &H4
Public Const RPC_E_SERVER_DIED = &H80010007
Private Const RPC_S_CALL_FAILED_DNE = 1727&
在常数的初始化中,有些程序使用Global,如Global Const ABM_ACTIVATE = &H6,但我认为Public完全可以代替它。过去我也用过Global,但现在不大用了。一会儿用这个,一会儿用那个,各程序之间不能保持一致性了,起码看起来别扭。
结 构
结构是C和C++语言中的说法。在VB中一般称为自定义数据类型。想必很多朋友都已经认识它。在API领域里,我更喜欢把它叫做结构,因为API各种结构类型根本不是我定义(
自定义)的。
在VB中,API结构同样由TYPE.......END TYPE语句来定义。如,在API中,点(Point)结构的定义方法如下:
Public Type POINTAPI
X As Long '点在X坐标(横坐标)上的坐标值
Y As Long '点在Y坐标(纵坐标)上的坐标值
End Type
又如,API中矩形(Rect)结构的定义如下∶
Public Type RECT
Left As Long '矩形左上角的X坐标
Top As Long '矩形左上角的Y坐标
Right As Long '矩形右下角的X坐标
Bottom As Long '矩形右下角的Y坐标
End Type
这些内容同样可以从API文本游览器中拷贝过来。这些结构中的变量名可随意改动,而不会影响结构本身。也就是说,这些成员变量都是虚拟的。如,POINTAPI结构可改为如下∶
Public Type POINTAPI
MyX As Long '点在X坐标(横坐标)上的坐标值
MyY As Long '点在Y坐标(纵坐标)上的坐标值
End Type
不过,一般来讲,是没有这种必要的。结构本身是一种数据类型,因此,使用时必须声明具体变量为该结构型,才能在程序中真正使用到该结构。结构的声明方法和其他数据的声明方法一样,如,以下语句把变MyPoint声明为POINTAPI结构类型∶
MyPoint As POINTAPI
引用结构中的成员变量也十分简单,在结构名后面加上一个".",然后紧接着写要引用的成员变量即可。这很象VB中的引用一个对象的某个属性。如,假如我们把上面已经声明的MyPoint结构中的X变量的值赋给变量Temp&
则代码如下∶
Temp&=MyPoint.X
但,特别注意的是,你千万不要认为上例中的MyPoint是一个值。它不是值,而是地址(
指针)。值和地址是完全不同的概念。结构要求按引用传递给WINDOWS函数,即所有API
函数中,结构都是按ByRef传递的(在Declare语句中ByRef是默认型)。对于结构的传递,你不要试图采用ByVal,你将一无所获。由于结构名实际上就是指向这个结构的指针(这个结构的首地址),所以,你也就传送特定的结构名就可以了(参见小结,我用红色字体来突出了这种传递方式)。
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Type POINTAPI '定义点(Point)结构
X As Long '点在X坐标(横坐标)上的坐标值
Y As Long '点在Y坐标(纵坐标)上的坐标值
End Type
Sub PrintCursorPos( )
Dim dl AS Long
Dim MyPoint As POINTAPI
dl&= GetCursorPos(MyPoint) '调用函数,获取屏幕鼠标坐标
Debug.Print "X=" & Str(MyPoint.X) & " and " & "Y=" & Str(MyPoint.Y)
End Sub
Private Sub Command1_Click()
PrintCursorPos
End Sub
输出结果为(每次运行都可能得到不同的结果,这得由函数调用时鼠标指针在屏幕中所处的位置而决定)∶
X= 240 and Y= 151