api学习

那么要调用一个陌生的API,基本上遵循以下步骤
1、找到相关API、结构体、常数的声明
2、到MSDN阅读这个API的网页指南
3、按照MSDN写代码

好吧看起来很简单,不过这样说了也是白说,实战一下吧

这次实战的目标是:GetOpenFileName

首先介绍一下这个API吧,这个API会显示一个打开对话框,给用户选择一个文件打开
这个跟CommonDialog里面的打开对话框是一样的(那干嘛不直接用那个控件?教程用来做演示嘛,而且用API也有他的好处)

第一步:找到声明

找声明主要有两种方法
第一种是通过软件找,例如API Viewer 2004,这类软件内置有绝大部分常用的声明,直接复制即可,方便快捷
第二种是去MSDN找到API的页面,然后复制声明。MSDN是微软的网站,声明肯定是准确的,但是对于VB开发者的劣势是,绝大部分声明都是按照C语言的格式的(至今没见过一个API的页面有VB声明),所以如果不懂C语言的话要转换成VB的声明难度就大了
还有其他方法,例如dump dll文件之类的
本文主要讨论第一种方法,使用的软件是API Viewer 2004,其他同类软件操作大同小异

打开API Viewer 2004,打开Win32api.apv文件,然后选择Declarations一栏,然后选择Subs and Functions,在文本框输入GetOpenFileName,然后就找到这个API的声明了,复制下来,扔进VB的代码里面

好了,现在来仔细看一下这个声明:
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (ByRef pOpenfilename As OPENFILENAME) As Long
可以看到这里有一个陌生的参数类型OPENFILENAME,这明显不是VB的基本数据类型,所以我们需要这个OPENFILENAME的声明

于是回到API Viewer 2004,选择Types一栏,在文本框输入OPENFILENAME,找到声明了,复制下来,扔到VB代码里面
Private Type OPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
继续仔细看这个结构体的声明,可以发现成员都是VB的基本数据类型,说明不需要在找其他声明了
好吧找声明这里就搞定了

第二步:阅读MSDN对于这个API的解释 & 第三步:按照MSDN写代码

这里说的MSDN不是按F1出来那个MSDN,而是MSDN网站msdn.microsoft.com。这个是微软的官方开发者网站,里面资料齐全绝对是开发者的天堂
网站有中文版本和英文版本,不过强烈建议大家看英文版本,中文版的翻译质量不好(这就是为什么要求有一定的英文阅读能力)

好吧进入了这个官网之后,在最上面的Bing搜索里面打GetOpenFileName,然后搜索
出来的结果,一般选择xxxx function这种页面,这里选的就是第一个结果GetOpenFileName function
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646927(v=vs.85).aspx

页面打开了,可以看到这个页面分成几大节:
开头:对API的简单介绍
Syntax:语法,也就是API的声明
Parameters:API的参数
Return Value:返回值
Remarks:一些附加的说明
Examples:示例代码,一般都是用C语言写的
Requirements:API对系统的要求等等
See Also:与此相关的API等
Community Additions:其他人对此文章的评论
网页左栏:是整个站点的分类目录

好吧,英文不好的同学要加油了,混国外网站英文是必须要会的
不要觉得一个API能有这么多内容,很多信息都是很有用很关键的,耐心从上往下一节一节读完

开头:
这个嘛,自己看就是了,对API的介绍和描述,不是很重要的部分(不过有时会有很重要的批注,例如此API不再被微软支持建议用xxx代替之类的)

Syntax:
这个就是API的语法,也就是声明啦,C语言的,所以对我们没什么用,可以跳掉不看
如果要根据这个C语言的声明自己写出VB的声明,还是需要一定的C语言数据类型的知识

PS:这里为什么返回值是BOOL,但是我们的声明是Long呢?是不是应该把我们的VB声明改成Boolean?不需要的。BOOL在C里面的定义就是long型(unsigned long?具体忘了,差不多这类东西),占用4字节,所以应该对应VB的Long型。当然,你闲着蛋疼也可以把返回值声明成Single型,同样也是4字节,不过没什么意义

Parameters:
API的参数部分啦,整个网页最重要的部分之一
按照这里的解释,填写参数就可以调用API了

好吧这里只有一个参数,网页写的是
lpofn [in, out]
Type: LPOPENFILENAME

这个[in, out]是什么意思呢?in表示这个是个输入参数,这个参数的值会作为输入对API的结果进行影响。out表示这个同时也是个输出参数,API会把部分数据返回到这个参数里面。(除了in和out,有些还会出现optional,表示这是个可选参数)

LPOPENFILENAME说的就是参数的类型,等等,我们的声明不是写的类型是OPENFILENAME吗,怎么这里多了个LP?这个是C语言里指针的意思(long pointer?),意思是当调用API的时候,不是把这个整个OPENFILENAME结构体的数据传过去,而是只把这个结构体的指针传过去。同样的写法还有xxx*,例如OPENFILENAME*

接下来看他对这个参数的描述,大致是这个参数装载着启动这个API的参数,当API返回的时候会把结果放到这个结构体里面
说的基本都是废话,这个结构体有这么多成员,我们还是不知道怎么填,那么就点进去这个OPENFILENAME的链接

点进去之后,发现这个OPENFILENAME文章结构也差不多

Syntax可以跳过,我们已经从API Viewer 2004里面找到声明了(PS:后面这个#if和#endif中间的是什么东西呢?这个是C的预编译指令,具体可以自己去看,在这里没什么用)

Members,终于在讲解这些成员的意思了,好吧可以开始写代码了,首先在VB里面写
Dim ofn As OPENFILENAME
With ofn
End With

那么接下来就一个一个看成员,看他的解释,是什么意思,应该怎么填
需要注意的一些东西是,不像API的参数,并没有告诉你每个成员是作为输入还是输出的作用,需要自己认真读解释

lStructSize,Type: DWORD
结构体的字节大小,用sizeof(OPENFILENAME)获得
sizeof其实就是C语言里面获得结构体大小的函数,那VB里面我们就用LenB吧(Len也行,不过按照MSDN的说法还是用LenB吧)
(PS:DWORD对应VB的Long)
代码:.lStructSize = LenB(ofn)

hwndOwner,Type: HWND
这个对话框的父窗体的句柄,可以设置成NULL
那我们就做成父窗体是我们的Form1吧
(PS:HWND也是对于VB的Long,NULL则是0)
代码:.hwndOwner = Me.hWnd

hInstance,Type: HINSTANCE
如果要指定对话框的模板,那么这个需要填上模板所在的程序句柄
我们没兴趣用什么模板,windows自带的那个已经够好看了,不理他填个NULL
代码:.hInstance = 0

lpstrFilter,Type: LPCTSTR
文件类型过滤器,格式为 描述文字 \0 *.xxx \0 描述文字 \0 *.xxx \0 ....... \0\0
所谓文件类型过滤器,其实就是那个下拉框,例如选择文本文件*.txt就只显示txt文件
C语言中\是转义字符,\0其实就是VB中的chr(0)
那么我们这里做一个简单的吧,用户可以选择文本文件或者是任意文件
(PS:LPCTSTR对应VB的String,详细一点应该这样解读,LP C T STR,LP表示这个是字符串的指针,C表示是常量字符串,就是API执行前后不会被修改,T表示是根据程序设置选择是ANSI还是Unicode编码,STR表示是个字符串)
代码:.lpstrFilter = "文本文件" & Chr(0) & "*.TXT" & Chr(0) & "所有文件" & Chr(0) & "*.*" & Chr(0) & Chr(0)

lpstrCustomFilter,Type: LPTSTR
大概就是如果选的是文本文档txt的过滤器,但是用户强制输了个不是txt后缀,API就会分析这个后缀然后返回到这里
这里有一点必须要读到的是,这个是个缓冲区,API会把数据返回到这里。其实从数据类型也可以看到,这个并不像lpstrFilter一样,这个是LPTSTR而不是LPCTSTR,少了个C意味着这个不是一个常量,可能会被API改变,说明是充当一个缓冲区的作用
我们貌似也对用户选怎么后缀没兴趣,所以按照他的要求,填NULL
但是这个是个String类型,NULL表示一个0指针,VB中String类型的0指针就要填vbNullString
代码:.lpstrCustomFilter = vbNullString

nMaxCustFilter,Type: DWORD
lpstrCustomFilter的缓冲区大小
反正我们对这个没兴趣,按照要求填个0就可以了(实际上,只要lpstrCustomFilter填了NULL,这个填什么都没关系)
代码:.nMaxCustFilter = 0

nFilterIndex,Type: DWORD
Filter的序号,作为输入时是默认过滤器的序号,作为输出时是用户选择了哪个序号
我们就让默认是文本文档的过滤器好了,所以序号是0
代码:.nFilterIndex = 0

lpstrFile,Type: LPTSTR
文件路径,作为输入时是默认选择的文件,作为输出为用户选择的文件路径
可以读到这个是一个输出成员,而且从数据类型LPTSTR也可以看到是非常量的字符串,所以我们需要给他做个缓冲区,让API填数据
按照要求,做缓冲区的话最小大小为256,不过我这里就采用MAX_PATH常量值(表示文件路径的可能的最大长度),260
同时他说,如果要避免成为默认选择的文件,最好给缓冲区全部填\0
代码:.lpstrFile = String(260, 0)

nMaxFile,Type: DWORD
lpstrFile的缓冲区大小
这个不必废话了,lpstrFile我们的缓冲区用的是260,自然就填260了
代码:.nMaxFile = 260

lpstrFileTitle,Type: LPTSTR
返回的文件名,作为输出成员(例如C:\a\b\c\1.txt,文件名就是1.txt)
我们不关心这个文件名,即使关心我们也可以用VB的函数自己获得,不需要,填NULL
代码:.lpstrFileTitle = vbNullString

nMaxFileTitle,Type: DWORD
lpstrFileTitle的缓冲区长度
代码:.nMaxFileTitle = 0

lpstrInitialDir,Type: LPCTSTR
初始文件夹
可以指定一个路径,不过直接填NULL好了,打开对话框有路径记忆功能,会自动设置为上次选择的文件的路径
代码:.lpstrInitialDir = vbNullString

lpstrTitle,Type: LPCTSTR
打开对话框的标题
随便搞个标题上去吧,看个人心情
代码:.lpstrTitle = "选择一个文件来打开"

Flags,Type: DWORD
打开对话框的一些性质
下面列了一堆可选的性质,名字下面是十六进制值,右边是解释
我们大体选择了以下几个我们想要的性质:
OFN_EXPLORER:使用系统自带的对话框模板,win7和vista下看起来会很漂亮
OFN_FILEMUSTEXIST:选择的文件必须存在
OFN_HIDEREADONLY:隐藏只读的多选框
OFN_PATHMUSTEXIST:用户在输入框输入的路径必须存在
这些常数可以在API Viewer 2004里面查到他们的值,当然一般来说网页都会给出来,复制就是了
使用多个常数的时候,用Or连接
代码:.flags = &H80000 Or &H1000 Or &H4 Or &H800

nFileOffset,Type: WORD
文件名在lpstrFile中的偏移,输出成员
我们对文件名没什么兴趣,而且这个是个输出成员,那我们就不用写代码了
代码:无

nFileExtension,Type: WORD
文件后缀在lpstrFile中的偏移,输出成员
同没兴趣,无代码
代码:无

lpstrDefExt,Type: LPCTSTR
默认的后缀名,当用户没有输入后缀名的时候自动加上去
对此没什么兴趣,按照要求填个NULL
代码:.lpstrDefExt = vbNullString

lpTemplateName,Type: LPCTSTR
打开对话框使用的模板名称
我们使用系统默认的模板,所以这个也没必要,填NULL
代码:.lpTemplateName = vbNullString

好吧终于搞定这些Members了!!
这个网页的其他几节意义都不大,没什么重要信息,我就不说了

好吧回到GetOpenFileName这个网页,我们填完参数了,继续忘下看

Return value:
Type: BOOL
这个是对返回值的解释,也是挺重要的部分
一般返回值会确定API是否执行成功,虽然大部分人调用API都不管这个返回值,但是按照规范应该是判断返回值看是否调用成功
如果用户成功按了确定按钮,那么返回值就是非0,lpstrFile成员包含了用户选择的文件路径;如果点了取消,那么就是0
这样的话,我们把调用和判断返回的代码写出来吧:
If GetOpenFileName(ofn) Then
Else
End If
现在只是调用了GetOpenFileName,但是调用完什么都不做
好吧,既然说了用户选择的文件路径是在lpstrFile里面,那么我们就可以直接拿来用了
但是,有一点必须注意,lpstrFile里面包含了我们分配缓冲区时候多出来的chr(0)
如果不把这些删掉的话,那么出来的路径就有问题了,后面跟着一大堆的chr(0)
声明一个String型变量szPath,用来保存我们处理完之后的文件路径
Dim szPath As String
szPath = Left(ofn.lpstrFile, InStr(ofn.lpstrFile, Chr(0)) - 1)
MsgBox szPath
搞定了用户按确定的代码,现在来做用户点取消的代码,直接一个msgbox显示就好了
MsgBox "没有选择文件"

Remarks:
这部分通常包括很详细的API调用说明,一般有很重要的信息
不过在这里没什么有意义的东西

Requirements:
Minimum supported client/server是这个API对Windows系统版本的最低要求,这里都是Windows 2000
Header就是VC6里面的头文件,这里是Comdlg32.h,如果你有装Visual C++ 6.0的话,找到这个头文件,就可以找到这个API及相关的C语言声明了
Unicode and ANSI names这个是不同编码版本的API名称,这个编码的问题不在本文的讨论范围



好啦经历千辛万苦终于按照步骤做完了,整个窗体的代码就是这个样子(窗体有一个按钮Command1):

Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (ByRef pOpenfilename As OPENFILENAME) As Long

Private Type OPENFILENAME
    lStructSize As Long
    hwndOwner As Long
    hInstance As Long
    lpstrFilter As String
    lpstrCustomFilter As String
    nMaxCustFilter As Long
    nFilterIndex As Long
    lpstrFile As String
    nMaxFile As Long
    lpstrFileTitle As String
    nMaxFileTitle As Long
    lpstrInitialDir As String
    lpstrTitle As String
    flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    lpstrDefExt As String
    lCustData As Long
    lpfnHook As Long
    lpTemplateName As String
End Type

Private Sub Command1_Click()
    Dim ofn As OPENFILENAME
    Dim szPath As String
    With ofn
        .lStructSize = LenB(ofn)
        .hwndOwner = Me.hWnd
        .hInstance = 0
        .lpstrFilter = "文本文件" & Chr(0) & "*.TXT" & Chr(0) & "所有文件" & Chr(0) & "*.*" & Chr(0) & Chr(0)
        .lpstrCustomFilter = vbNullString
        .nMaxCustFilter = 0
        .nFilterIndex = 0
        .lpstrFile = String(260, 0)
        .nMaxFile = 260
        .lpstrFileTitle = vbNullString
        .nMaxFileTitle = 0
        .lpstrInitialDir = vbNullString
        .lpstrTitle = "选择一个文件来打开"
        .flags = &H80000 Or &H1000 Or &H4 Or &H800
        .lpstrDefExt = vbNullString
        .lpTemplateName = vbNullString
    End With
    If GetOpenFileName(ofn) Then
        szPath = Left(ofn.lpstrFile, InStr(ofn.lpstrFile, Chr(0)) - 1)
        MsgBox szPath
    Else
        MsgBox "没有选择文件"
    End If
End Sub

运行测试,一切正常!

好了本文就到这里结束了,希望能帮助到大家的API学习
最后说一句,API不能整天靠网上百度下来的例子代码复制粘贴,自己去MSDN看来写代码,收获更多
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值