感悟VB细水长流话API
发表时间:2024-02-24 来源:明辉站整理相关软件相关文章人气:
[摘要]出处:电脑爱好者编写VB程序时,经常遇到的问题就是VB给我们准备的东西我们会用,控件组装就是一个程序,然而一旦想要实现VB没有直接提供的功能,就会不知所措。其实Windows操作系统本身就给我们准备了许多东西,VB没有的,或许Windows有。我们当然希望少花力气,多得效果。这里要讲的内容就是——...
出处:电脑爱好者
编写VB程序时,经常遇到的问题就是VB给我们准备的东西我们会用,控件组装就是一个程序,然而一旦想要实现VB没有直接提供的功能,就会不知所措。其实Windows操作系统本身就给我们准备了许多东西,VB没有的,或许Windows有。我们当然希望少花力气,多得效果。这里要讲的内容就是——学会利用Windows给我们的东西:API。
然而,学会一种东西是需要付出相当的努力的,API也一样,它可以给我们带来很大的方便,但想要掌握它,就不是使用几个控件那么轻松的事了。所以在看这篇文章时,希望读者可以抱一个正确的态度,就是学习编程不是为好玩,而是为使用; 不要以自己对这方面是否有兴趣而看,而要为API是否能为你的程序带来效果而看。我并不是说一切都是那么严肃和困难,只是API对VB来说,已经可以算高级方面的应用了,所以“认真”和“仔细”是需要的。好了,放松一点,让我们从现在起一步步领略API的好处吧。
前言
1.API
API全称为Application Programming Interface,直译的话可叫它“应用程序接口”。从意义上来说,API是一个操作系统或某个程序本身提供给其他程序使用的函数。在Windows操作系统中,有成千个Windows的函数提供给应用程序使用,本文所说的API,就是指这些函数。
2.VB与API
之所以写这篇文章(而不写VC或其他语言),是因为VB对API的支持不是直接的,而且是不完全的; 在使用上,Windows的API编写时是假设调用者是C或C++语言,因此VB调用API不是很方便,也经常有不必要的错误或不明白如何使用的情况出现。本文的对象主要还是对API没有很深研究的读者,如果你不想了解太多细节,你可以把一个合适的函数用法搬过去,或者你完全不知道API,或者只知道少数,对许多函数还不清楚如何使用,或者你希望可以从本文学到更多使用API的技巧甚至VB的技巧(但愿我可以让你学到),我想你都应该看这篇文章。但还是有个大前提,你必须是已经会使用VB的读者,因为以后讲到的内容不会有一个完整工程从头到尾教你做,有可能是一段简短的声明与调用代码,也可能是几个函数的组合,如果必要的话,也会讲述相关内容的VB技巧,但一定不会有完整的实例示范。
3.本文原则和约定
由于API中有的用法简单有的复杂,有的可单独使用有的却不行,加上各个API的主要用途不同,很难判断先说哪个再说哪个可以让人更容易理解,因此本文尽量从比较常用的说起,从可以对程序产生较大作用的说起。为了能让多数人理解,如果需要涉及到其他方面的知识,也将尽量讲述,让读者可以学到使用API的知识,并能够利用本文中的知识应付新的API。如果你对某个API有什么疑问,欢迎来信(webmaster@neocactus.com),但由于时间有限,不能对来信一一回复,如果有需要,将会在文中讲述。
基础知识
在讲API之前,让我先讲解一些与API相关的VB基础知识,后文如有涉及将不再详述。此处未提及的,将在本文中第一次接触时再做解释。
1.自定义类型
VB中可以使用Type关键字将已有的数据类型进行组合,成为一个新的类型,该类型就称为用户自定义类型。如:
Type NewType
sName As String
lNumber As Long
End Type
定义了一个名为NewType的自定义类型。以后可以用Dim MyType As NewType来定义一个NewType类型的变量。
sName As String类型的变量有两种,一种是变长,即运行时的字符串长度是可变的,另一种是定长,运行时字符串的长度是固定的。平常我们定义一个字符串变量: Dim strA As String 即定义了一个变长的字符串,但在使用API时经常要用到定长的字符串,应该这样定义: Dim strB As String * 30,即定义了一个可容纳30个字节字符的变量。
2.声明
VB中使用API之前,需要先对API进行声明,声明的方法是使用Declare关键字,如:
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
声明了一个名为SendMessage的API函数。许多API的声明可以在API浏览器中找到,而且本文在讲述一个API时也会给出声明,更深入的知识将在以后讲述。
3.句柄
API中使用得最多的一个词大概就是“句柄”了。如果要说得复杂些,句柄的确可以说上一大堆,不过作为VB的应用,我们可以更简单地去理解它。可以这么说,句柄是Windows系统赋予内存中每一个对象,包括窗口、按钮(其实也是一种窗口)或者文件、图标、菜单等等所有东西的标识。所谓标识就如身份证一样,是不会重复并且和实际对象是一一对应的。它的作用是让Windows知道将被操作的对象是谁。许多VB控件都提供了一个长型的hWnd属性,一般情况下,这个属性就是这个控件的句柄,用API控制这个控件时就需要用到这个属性了。
4.设备上下文
其实我觉得“设备上下文”这个词读起来很奇怪,不过就其字面来看,Device Context(DC,可不是直流电或DreamCast哦)就是这个意思,许多人也这么称它。不过我想翻译为“设备中介”大家应该更容易理解吧。它的作用是作为计算机设备和程序之间的中介,比如显示器和程序之间,或者打印机和程序之间。在对这些设备操作的时候,是需要通过这个中介操作的(与句柄相似),一些控件,如 Picture,想在上面画图时,就要用到hDC属性了。
5.显式声明与自动保存
在默认情况下,Visual Basic会把未声明的变量认为是新变量(即使是你不小心打错字了),这样很容易出现错误,而且要找出这样的错误往往很不容易。加上API的操作基本上都会涉及到系统本身,一旦出错就有可能出现Visual Basic崩溃甚至系统崩溃。所以到Visual Basic的选项设置中选上Require Variable Declaration(需要变量声明)。在 Enviroment(环境)页中的When a program starts(当程序启动时)处选上Prompt To Save Changes(提示保存)或 Save Changes(自动保存)。这样Visual Basic会检查变量是否已经声明,不再允许没有声明的变量出现了。
6.API浏览器
前面讲“声明”的时候提到了API浏览器,这里也说一说它。在安装完VB时,安装程序会把API浏览器复制到你的计算机里。启动后界面如图1(以VB6为准)。可以看到,从API浏览器里我们可以得到API的声明、常量值以及与API相关的自定义类型的定义。其中Declare Scope(声明范围)是指该声明是公有的还是私有的。对于在标准模块中的声明,如果声明为私有,则只对该模块有效,如果为公有,则对整个程序都有效。在窗体模块中只能声明为私有。
7.MSDN
MSDN是微软发布的一套完整的Windows开发者技术文档(如图2)。里面不仅有VB、VC++、VFP、MSDEV、VSS等开发工具的完整帮助,而且包含了Windows平台开发的几乎所有的技术资料,并不断地更新。我们需要的API资料这里都有很详细的说明,包括使用平台、参数类型、参数作用等(当然它并非完全正确,错误的地方也时有出现)。不过作为以C为基础的API,这里的资料是英文的,而且格式也是C语言格式。想要读懂,那你的英文水平和C语言就要有两把刷子了。不过不必担心,它只是我建议一定要有的参考文档,最重要的还是我接下来要讲的内容,它不仅是中文的,还是VB的,又有使用示例,还有相关知识讲解。记住MSDN只是参考文档,作用就好像字典,可千万不要买了一套MSDN就跑去跟别人说你已经变得多厉害了,不然……
顺便说一说,以前的MSDN是双CD的,现在已经变成3CD了。如果买的话应尽量买最新的(但没有必要每次更新都换一套),因为更新的版本把一些错误改正了,并增加了新的内容,比如最新的MSDN已经增加了许多Windows XP的内容。你可以从微软的中国网站订到这套文档,不过一年的价钱从一万几到三万几,买不起的话……自己想办法吧。
好了,开篇写了这么多,无非也是想让读者在以后可以更容易理解所讲的内容。这些是基础,是一定要记住的。下面我们就先介绍一个比较简单的API,开始我们的API之旅吧!
第一话 从消息说起
由于这是《细水长流话API》的第一话,我必须注意到所讲的内容要简单,并且让你有耐心可以看到往后的文章,所以我希望可以通过一个比较特别的例子来引起你的注意(这样的情况不会总是有的)。让我们想想,VB里的CommandButton控件让我们可以做什么?按下、弹起,还有呢?请看看图3,这样的情况在你的程序运行时出现过吗?
Windows是以消息来传递信息的。当出现某个操作,比如按钮被按下,就产生按钮被按下的消息。消息被传送到被操作对象(按钮),事件就产生了。应注意不是按钮产生消息,而是Windows知道这个操作的发生,向按钮发送这个消息,按钮收到后再做相应的处理——如改变外观成为按下的状态。
Windows允许第三者向某个对象发送消息,因此当某个操作没有发生时,我们是可以让对象如同收到消息一样产生效果的,这就需要用到API函数——SendMessage了。
SendMessage的声明前面已经说过(注意以Public开头应放在标准模块中,否则用Private开头),它的各个参数中,hwnd是对象的句柄,wMsg是消息的值(具体什么消息),另外两个参数根据不同消息和不同应用有不同的值。
你看到的图3的情况,是由于我的程序向Command Button控件发送了WM_NCLBUTTONDOWN消息。这个消息发生在鼠标在窗口的非客户区域上按下时。所谓非客户区域,你可以理解成一个窗口的边缘和标题栏(当然是指一般情况,这种情况是可以被程序改变的)。
在我这个按钮的MouseDown事件中,只写了短短的几句:
Private Sub cmdResize_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim nParam As Long
With cmdResize
'之所以在0和100之间以及下面 .Width-100 和 .Width 之间,是让鼠标只在按钮边缘才可以拉动按钮
If X > 0 And X < 100 Then
nParam = HTLEFT
ElseIf X > .Width - 100 And X < .Width Then
nParam = HTRight
End If
If nParam Then
Call ReleaseCapture
Call SendMessage(.hwnd, WM_NCLBUTTONDOWN, nParam, 0)
End If
End With
End Sub
可以看到,我让鼠标拉动按钮时,拉按钮左边是用 HTLEFT做参数,拉右边是用HTRIGHT做参数。这两个都是常量,可以从API浏览器中得到值。同样的,若想拉按钮的上面和下面,可用HTTOP和HTBOTTOM做参数,而 HTTOPLEFT和HTBOTTOMRIGHT则分别是左上角和右下角。
在发送消息之前有一个ReleaseCapture的API。这个API是让Windows释放对鼠标的捕捉以便使鼠标位置的信息不能被收到,CommandButton不知道鼠标在哪里,也就不会发生按钮在这时被按下的情况。当然,可以放心,Windows释放对鼠标的捕捉只是暂时的,当你放开鼠标再次发生移动时,Windows又会捕捉鼠标了——它是时时都在发生的。
你可能希望如同我的程序一样在按钮边缘光标会变化,下面是我写的程序段:
Private Sub cmdResize_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim NewPointer As MousePointerConstants
With cmdResize
If X > 0 And X < 100 Then
NewPointer = vbSizeWE
ElseIf X > .Width - 100 And X < .Width Then
NewPointer = vbSizeWE
Else
NewPointer = vbDefault
End If
If NewPointer <> .MousePointer Then
.MousePointer = NewPointer
End If
End With
End Sub
作用很明显,而且很简单,所以我就不对这段代码作解释了。
这个例子很简单,但相信起的作用是不小的。SendMessage可以发送很多消息,当然我不会对这些消息一一作解释,但以后还是会经常接触到的,所以更多的知识就等慢慢再学吧。
文中程序在Windows2000+VB6环境下调试通过。