VB API教程

分类:VB
 标签:VB程序,VBApi,VB教程
   修改 | 阅读(294)| 评论(0)

一、API是什么?

  Win32 API即为Microsoft 32位平台的应用程序编程接口(Application Programming Interface)。所有在Win32平台上运行的应用程序都可以调用这些函数。

  使用Win32 API,应用程序可以充分挖掘Windows的32位操作系统的潜力。Mircrosoft的所有32位平台都支持统一的API,包括函数、结构、消息、宏及接口。使用 Win32 API不但可以开发出在各种平台上都能成功运行的应用程序,而且也可以充分利用每个平台特有的功能和属性。

  
  以上为API的相关介绍,不过有些新手看了以后可能还是不怎么明白API到底有什么用?这里请不要着急,如果你有足够耐心的话,请慢慢往下看。

二、如何使用API?

  估计这才是大家真正关心的,那么如何使用API呢?在了解API之前,先打开你的VB书,翻到过程函数这章来,在搞清楚API之前应该先搞懂过程函数是怎么一回事!如果你还不知道过程的工作方式,那么请先不要急着往下看,那样容易走很多弯路。

  好了,当你理解了过程函数时,也就是你可以使用API的时候了,别把API看得太难,你就像使用过程函数一样使用API就可以了。首先,让我们看看一个简单的API,以下:

  Private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

  以上这个API的呢是起一个延时作用。你如果是刚接触API的话可能会感到API的书写及其复杂,而且会感到很不适应。其实这没什么的,慢慢习惯就好了。至于API这些复杂的书写你就不用操心了写你就不用操心了,在你安装VB的时候微软已经帮我们带上了API浏览器,这些全部都可以利用API浏览器帮我们自动生成。API浏览器的位置位于[开始菜单-程序-Microsoft Visual Basic 6.0 中文版-Microsoft Visual Basic 6.0 中文版工具-API 文本浏览器]。打开API浏览器,在最上面的一个文本框中输入Sleep,这时下面列表框中就会自动显示相应的API函数,然后点右边添加按钮即可,接着点击复制按钮,这时你就可以用Ctrl+V把声明的API添加到VB代码窗口中了。

  这里我要说一下,有些新手可能还弄不明白。API的声明范围一般有两种模式,一种是Private(私有的),一种是Public(公用的)。一般Private是声明在类模块或窗体类中,Public声明在模块中。你在添加API的时候,添加按钮下面就有API的声明范围,可以根据自己的需要进行添加。这里我们一般选择私有的(Private)就可以了。

  经过上面,我们知道如何添加API,接着我们分析一下API声明,这是你了解API必备的。首先看第一个单词Private,很显然,我上面刚刚讲过,这是申明一个私有的API变量。再看第二个Declare,这个单词帮我们告诉VB是在申明API函数,一般申明外在的API函数时都必须带上这个单词。第三个Sub,别告诉我你不知道什么意思?这就是我叫你先学习VB中过程函数的意思,这个说白了就是没有反回值,一般如果不是Sub而是Function都带有反回值的。第四个Lib,这个是告诉VB我们要声明哪一个DLL中的API函数,也就是告诉VB我们要申明第五个单词kernel32.dLL中的API,一般写DLL名称时都要用双引号括起来,如"user32"、"shell32.dll"等,至于后面的.dll这隹梢源 刹淮 T倮纯吹诹 鯝lias,这个也是需要同后面一个一起用的,我们应该把第六个和第七个连起来一起看Alias "Sleep",这个意思表示将被调用的过程在DLL中还有另外的名称,这个是可选的。最后括号里面的,也就是和过程函数一样,你传入相应的值就可以了。

  上面我们分析完API函数声明以后,接着我们就要自己动手写代码了。先把这个API复制到Form1代码窗口中,然后写如下代码:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Form_Load()
         Sleep 2000
 End Sub

  解释一下,也就是在窗体启动时使用Sleep API进行延时2秒,后面的参数dwMilliseconds是表示你要延时的秒数,基本上和设置Timer中的秒数一样。你再看一下Sleep 2000的使用方式,是不是和使用VB过程函数一样呢?好了,我们的第一个VB API程序写完了,可以看到使用API并不是一件很难的事。

三、如何才能提升你对API的学习兴趣?

  API,我常把它看做成过程函数,不过每人都有每人的见解和理解方式,自己的理解方式只要可以帮助自己更好的学习和掌握API,也没必要一定要学习他人的。

  1,自己做MsgBox

  了解API参数的使用方法是很重要的,这里我们不用VB的MsgBox,直接使用API弹出MsgBox消息框。首先,打开API浏览器,选择MessageBox,大家可以用这个API和VB内置的MsgBox比较一下,其实MsgBox也就是MessageBox的缩写,只不过一个是API,一个是VB内置的,但两者都是通过API进行工作的。好了,选择私有声明方式,粘贴到VB代码编辑窗口中,然后新建一个CommandButton,写入以下代码:

Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA"
(ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String,
ByVal wType As Long) As Long
Private Sub Command1_Click()
         MessageBox Me.hwnd, "这里是内容", "标题", 0
End Sub

  先让我们来分析一下,首先看第一个参数Byval hWnd As Long,很显然这是一个长整形变量,所以我们这里需要传递的是数字,你可能会发现我们传递的并不是数字啊,而是 Me.hwnd??很奇怪是吗?如果你真的有此疑问说明你是真心想要学习好API的,现在就让我们来看看Me.hwnd到底是什么东西?以下摘自VB帮助文档:
  hWnd 属性:返回窗体或控件的句柄。
  句 柄:是由操作环境定义的一个唯一的整数值,它被程序用来标识或者切换到对象,如窗体或控件等。

  现在估计你差不多就已经明白了,我们调用的hwnd其实是一个句柄整数值,你可以用 Msgbox Me.hwnd 看一下就知道了。至于Me这是一个关键字,代表当前Form窗体对象。如:Me.Caption="标题"、Me.BackColor=vbRed等。

  接上面的,首先我们传入了Me.hwnd,表示是当前窗口调用MessageBox,这里告诉大家一个技巧,也就是以后凡是看到Byval hwnd As Long,一般都是需要传入句柄的,至于传入哪个对象句柄,那就要看你是怎么实现的了。
  ByVal lpText As String,这个是字符串变量,标识着叫我们需要传入字符串进去,可以看里面的变量字符lpText,属于文本的意思,也就是说是用来显示MsgBox中的消息文本的。
  ByVal lpCaption As String,也是字符串变量,还是传入字符串进去。在看里面的变量字符lpCaption,其实就是显示MsgBox标题的。
  ByVal wType As Long,这是一个整形变量,需要传递整形数字,还是看里面的变量字符wType,标识着显示MsgBox类型,这里可以像VB的MsgBox一样使用,如这里可以传入:vbYesNo,vbOkCancel等,如果忽略那就传入0即可。

  好了,按F5启动程序,点击Command1,接着就会弹出一个消息框,这里我们制作以及分析MsgBox已经完成了。希望你能在这段学习到一些知识。

  2,来点实用的吧

  就拿隐藏Windows任务管理器来说吧,这里只能隐藏任务管理器中的窗口,不能隐藏进程。(问:有没有隐藏进程的?答:你想干什么?),当程序运行后你无法从任务管理器的窗口中关闭程序,只能从进程中进行终止。好了,还是老规矩,打开API浏览器,输入GetWindow和ShowWindow两个API,声明范围还是私有的,复制粘贴到Form代码窗口中,嗯,好了?别急,还是API浏览器,选择Combox中的常数,输入GW_OWNER和SW_HIDE这两个API常数,然后粘贴到代码窗口中,问我这两个是干什么的?那就接着往下看吧。写入以下代码:

Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long,
ByVal wCmd As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long,
ByVal nCmdShow As Long) As Long
Private Const GW_OWNER = 4
Private Const SW_HIDE = 0
Private Sub Form_Load()
         Dim lphWnd As Long
         lphWnd = GetWindow(Me.hwnd, GW_OWNER)
         ShowWindow lphWnd, SW_HIDE
End Sub

  又到了分析的时候了,这对刚入门的新手可谓是最激动的时候了。好了,还是老子,看看两个API的表面意思和传递值变量。

  先看GetWindow,表面意思:获取窗口。传递值变量:hWnd整形句柄,wCmd整形命令值。
  再看ShowWindow,表面意思:显示窗口。传递值变量:hWnd整形句柄,nCmdShow整形命令值。

  然后是使用代码,先看lphWnd = GetWindow(Me.hwnd, GW_OWNER)这句,这句意思是获取当前窗口的所有者窗口句柄,可以看到GetWindow是Function过程函数,执行以后会返回相应的窗口句柄值,这个值为Long整形(同句柄)。接着调用ShowWindow lphWnd, SW_HIDE,这句意思是显示lphwnd这个句柄的窗口,关键一句是最后的SW_HIDE,这是API函数的常量。通过设置常量能让系统知道API到底应该怎么执行显示窗口,是显示?还是隐藏?Hide当然是隐藏的意思。好了,编译成Exe,运行后打开任务管理器,查看程序窗口,还有吗?

  我又要说一下了,有些人可能不懂为什么要用GW_OWNER这些常量,这些到底有什么用?还有就是我怎么知道哪些API对应哪些的常量?其实这些常量你只要稍微注意一下就知道它们是怎么回事了,如在GetWindow中我使用GW_OWNER,在ShowWindow中我使用SW_HIDE这些常量都有一个共同的特点,就是他们都是以API的单词第一个字母为标准。如GetWindow相对应的常量就是Get(G)Window(W)=GW,ShowWindow相对应的常就是Show(S)Window(W)=SW,这些常量可以自己在VB的API浏览器中找找看。

3,继续往下学吧。。

        上面两个我们讲到了一般API的使用方法,和一些API常量的使用方法,接着我们来看看API类型的使用方法,在了解这一小节前请先搞懂VB中的自定义类型(Type)这章,否则你可能会稀里糊涂的,到时别怪我没提醒你哦!

        这次让我们来获取一下鼠标指针的位置。这里教大家一个技巧,当你想用API去实现某一特定的功能时,却又不知道该用哪个API,这时你可以就表面的意思到API浏览器找找,有70%以上的机率可以找到哦!现在就拿这个API开刀,那我们应该如何找?别着急,往下看:

        如我们现在要获取鼠标指针位置,可以这样翻译一下:Get(获取)Cursor(指针)Pos(位置),组合起来:GetCursorPos,呵呵,一条API就这样出来了,到API浏览器输入这个组合单词,呵,有吧?见以下:

Private Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint As POINTAPI) As Long

        好了好了,高兴一下就算了,现在让我们分析一下这个API,看其它的没啥不同的,其中只有一个参数,就是最后一个变量有些不懂?在VB中好像没有见过这个变量?不明白么?那就再继续往下看。

        lpPoint As POINTAPI,POINTAPI?很显然,在VB中并没有此类型,一般都是String、Integer、Long、Byte等变量类型,那么这个也就理所当然的是自定义类型(问:什么是自定义类型?答:不知道,自已不会看书啊)。既然是自定义类型,那么我们如何才能知道它是如何定义的呢?这里也就不用你操心啦,还是API浏览器,在最上面的Combox中选择类型,这时下面List中也就自然的把API的相关类型显示出来了,现在我们开始在Text文本框中输入我们需要的自定义类型,POINTAPI,点击添加,出来了吧?如下:

Private Type POINTAPI
            x As Long
            y As Long
End Type

        好了,现在开始写代码,添加一个Timer控件,设置属性见以下:

        Interval = 100
        Enabled      = True

        双击Timer控件,转到代码环境中写入以下代码:

Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Type POINTAPI
            x As Long
            y As Long
End Type
Private Sub Timer1_Timer()
        Dim lpPoint As POINTAPI
   
        GetCursorPos lpPoint
   
        Me.Caption = "X = " & lpPoint.x & " Y = " & lpPoint.y
End Sub

        好了,分析开始,紧张不?别紧张,没啥值得紧张的!见以下:

        Dim lpPoint As POINTAPI,申明一个POINTAPI类型变量,我们学过自定义类型的朋友都知道,一般使用自定义类型时都需要先申明一个相关的类型变量方可使用。

        GetCursorPos lpPoint,这一步我不说你都知道,调用API呗。通过这个API获取鼠标指针的相关信息。这里我们使用了自己声明的lpPoint变量,那为啥要使用这个变量呢?这里我们回过头来就前两节我们所分析的那样进行分析,可以看到GetCursorPos所需要传递的值,如果是Long,我们就传入整形数字,如果是String,我们就传入字符串,这里是POINTAPI,所以理所当然是要传入POINTAPI类型,但是!VB中的自定义类型不可以直接使用,所以我们需要先声明一个相同类型的变量。不知道说了这么多你懂了没?

 
        Me.Caption = "X = " & lpPoint.x & " Y = " & lpPoint.y,最后一句,也就是用来显示当前鼠标的坐标值的,我们通过声明的lpPoint变量来获取相应的鼠标坐标值,如果你不懂,那就请你先把VB自定义类型这章学完再说。


接上面第四节“如何慢慢提升自己的API功力?”

       提升自己的API功力?如何提升?怎么个提升法?这一点有待讨论,不过目前咱们需要做的是多多接触一下API,这样长久以后你就自然会对API产生一种亲切感,慢慢的你会觉得自己用API写程序是多么正常的一件事情。呵呵这个亲切感我喜欢!

       1,试着自己从小程序开始写起。

       写小程序?对!在你写小程序时应该拣你最感兴趣的程序写,否则有可能你写到一半以后会觉得自己这个程序写得毫无价值,简直是在浪费时间,最后到头来还是功亏一篑。这里我拿什么当题材呢?我在这里也想了很久,最后还是决定选择一个注销Windows程序来做题材(其实这是我当初学API最想实现的功能)。

       注销Windows也就是退出Windows(重启,关机等都一样,不都是退出的意思吗?),根据表面意思在API浏览器中输入Exit(退出)Windows,看看有没有这个API?这里提醒一下,你在查找这个API的时候还会看到ExitWindowsEX这个API,其实这两个API实现的功能一样,前者是用在16位操作系统上,只不过在Win32位操作系统上一般都使用ExitWindowsEX。所以这里就使用后者。API见以下:

 
     Private Declare Function ExitWindowsEx Lib "user32" Alias "ExitWindowsEx" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long

       看看里面的两个参数,ByVal uFlags As Long?这里我们需要传入一个整形数字,可是应该传入什么数字呢?这里说下,API中的参数可以传入不同的值,不同的值从而导致产生不同的结果。分析API中参数应该传递哪些值其实是有技巧的,以后大家只要是看到参数字符中包函Flags字符的话那就说明该参数可以被传入一个或多个标志,并且大部分都是传入API常数(什么是API常数就不用我说了吧)。说白话点,就是我们可以传入多个API常量,并且可以在API浏览器中找到,当然,不一定所有的API常数都可以在API浏览器中找到,不过大部分都可以。

 
       在API浏览器查API常量时我前面就教过大家技巧,现在该是我们实践的时候了,分析如下:

 
     Exit      :头一个大写字符 E
     Windows:头一个大写字符 W
     Ex        :头一个大写字符 E
     组合      :EWE_
 

       好了,现在在API浏览器的中常数中找找,咦?发现好像没有以EWE开头的常数??只发现以EWX开头的?现在先别着急,咱们回过头来再分析下,咱们是失败在最后一步Ex上,这里我不得不否决我前面教过大家的技巧,但是又不能完全否决,出现这种情况时就需要大家灵活运用API常数的分析法,可以看到EWX最后一个X是以Ex的X作结尾的,以这种方法做API常数开头的不止这一个,所以这里我特意留了一个陷阱,希望给大家带来一些经验将来能够灵活运用。现在我把关机uFlags所能用到的相关常数发上来,如下:

 
     Private Const EWX_FORCE = 4
     Private Const EWX_LOGOFF = 0
     Private Const EWX_REBOOT = 2
     Private Const EWX_SHUTDOWN = 1

       怎么样?看得懂吧?英语稍微好一点基本上没问题。不过这里我还是要解释一番,照顾新手嘛!

 
       EWX_FORCE 前面的 EWX_ 我就不说了,关键是看 _ 符号后面的,Force 单词翻译:强制,强迫。人工在翻译一下(我英文不好,翻译错了请别见怪,呵呵 ^_^ ),意思是说:强制执行ExitWindowsEx API关机函数。不知道这样解释你能不能明白。那到底这个常数有什么用呢?这里我们先回忆一下以前关机的时候,当Windows无法关闭某些窗口的时候就停止继续关机了,最后还得把无法关闭的窗口手动关闭方可,现在,如果我们使用这个常数进行关机,那Windows不管你窗口能不能关闭,直接强制关闭。希望你懂了。
 
     EWX_LOGOFF 这个嘛,貌似组合单词,不可直接翻译,那样就不是那个意思了。Logout Off,是这样写吗?注销的意思。
 
     EWX_REBOOT 不浪费时间了,直接说明意思:重新启动。
 
     EWX_SHUTDOWN 关机。

   
       至于第二个ByVal dwReserved As Long,为保留整形,一般为0即可。至于为什么为0,大家可以到网上下载一些专门讲解API函数的电子书看看,里面有大部分API函数的详细讲解。或者下载VS.MSDN看看,在MSDN中说Windows 2000/95/98/Me中此参数忽略,XP中是指定关机消息说明。

 
       最后看看这个API为Function声明,说明该函数有返回值,返回值为Long,MSDN中说:如果执行成功,则返回非零,否则为零。

 
       现在上面已经把这个关机API和相关参数常量都给你分析透了,你可别告诉我你还不知道怎么写?好了,这里我们做一个定时注销程序,呵呵,虽然很简单,不过很多时候用得上哦!在Form窗口上添加Timer控件,Interval 设置为1000,Enabled 设置为 True。好了,代码如下:

 
     Private Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long
     Private Const EWX_LOGOFF = 0
     Private Sub Timer1_Timer()
         Static i As Integer
   
         i = i + 1
   
         Me.Caption = i '这一步纯粹是想看看当前已经执行到几秒了?可不要
   
         If i = 10 Then '秒数判断,可以根据自己的需要进行运算
             ExitWindowsEx EWX_LOGOFF, 0
         End If
     End Sub

 
       其实我都有点不想分析了,不过为了照顾大众,不得不说下,Static i As Integer 静态变量(问:啥叫静态变量?答:我晕!),i = i + 1是每执行Timer一次i就加1,Timer的interval设置为1000,1000为一秒,2000为二秒。。。。后面一个If i = 10 Then是判断当i=10以后,也就是10秒,就执行注销,这个时候你可别忘了保存好你的其它没有保存的文件哦,如果没保存资料丢失的话偶不承担任何法律责任的。其实这里我们可以自己做一个,如可以写成这样:ExitWindowsEx EWX_LOGOFF Or EWX_FORCE, 0,其中用了Or运算,整体的意思是强制Windows注销。这样理解就够了,只要能让你明白。

 
       现在我又要说一下了,不说不行的!就是在API中使用 Or 运算,关于Or运算符VB书中都有详细解释的,别告诉我你没看?没看马上去看!上面EWX_LOGOFF Or EWX_FORCE 的使用是把 注销 和 强制 进行Or位运算,对两个数值执行按位析取,这里涉及到二进制运算,说多了你可能不明白(如果你还是想追根到底的想知道到底是怎么一回事的话,我也没办法,给个网址你慢慢看
http://book.csdn.net/bookfiles/110/1001103366.shtml),我就说简单点的吧,以后如果你想组合两个API常数的功能,一般都是用 Or 进行运行的。如上面写的。

 
       好了,保存其它文件,然后F5运行之,看着Form标题的数字慢慢添加,当为10时,Windows开始注销。。。

 
       小提示:在使用EWX_SHUTDOWN的时候你可能会感觉没有作用,主要是NT系统的安全性提高,需要用其它API进行提升自己的权限才可以。关于如何提升应用程序权限请百度一下。

 
       2,先从一些最简单的API开始

 
       无疑自己试着写程序是最好的提升方法,学完一些知识以后自己试着写写,这样能让你理解的更快更好,好了不说废话了,接着往下看。

 
       最简单的API,呵呵,哪些最简单呢?这个我也说不好,这样吧,咱们就从Get(获取)开始,那Get什么呢?Window(窗口),还是从窗口下手吧,这样更接近我们日常的编程,谁叫这是一个Windows操作系统呢?先列几个常用的API:

 
     GetWindow、GetWindowDC、GetWindowLong、GetWindowRect、GetWindowRgn、GetWindowsDirectory、GetWindowText、GetWindowThreadProcessId
 

       还有很多,我就先列举几个简单点的,咱们就从这几个中间随便抽几个来讲讲吧。

 
       先从GetWindowText下手,大家就表面的意思进行理解下,Get(获取)Window(窗口)Text(文本),Very Good!这个API以前不错的,可以获取密码框中的密码,呵呵,说到这里,我估计有些人开始兴奋起来了!那好,Follow Me!

 
       新建一个Form窗口,然后添加一个CommandButton,Caption设置为:显示密码。接着添加两个TextBox,Text1属性设置:PasswordChar=*;Text=123456789,Text2的属性基本上没有什么需要设置的,只需要把Text属性为空就可以了,它主要是用来帮助咱们显示出密码的。好了,在Form1代码框中填入以下代码:

 
     Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
     Private Sub Command1_Click()
         Dim sBuffer As String
   
         sBuffer = Space(255)
         GetWindowText Text1.hwnd, sBuffer, 255
   
         Text2.Text = sBuffer
     End Sub

 
       OK,F5运行,点击Command1,怎么样?Text1中的密码字符显示在Text2中了吧?你可以再更改下Text1中的密码,然后再点击Command1试试。也许你觉得会多此一举,为何不Text2.Text=Text1.Text这样?如果真的这样的话看似简单,那你就学不到API了。

 
       又到了开始分析的时候了,打起精神来,先看第一句:Dim sBuffer As String,不用说,声明一个字符串变量呗!接着看第二句:sBuffer = Space(255) 那这一句呢?有些人可能不知道了,没事,我会仔细讲的。Space是VB内置的字符串处理函数,VB中的帮助文件中有说明:
 
 
     开始{
 
     本示例使用 Space 函数来生成一个字符串,字符串的内容为空格,长度为指定的长度。
     Dim MyString
     ' 返回 10 个空格的字符串。
     MyString = Space(10)
     ' 将 10 个空格插入两个字符串中间。
     MyString = "Hello" & Space(10) & "World"
 
     }结束
很显然,我这一句是要分配255个空格字符串内存,为啥要用分配?这都是为后面所要用到打定的基础。接着往下:

 
     GetWindowText Text1.hwnd, sBuffer, 255 这一步是关键,通过它来获取咱们想要的窗口文本,看第一个参数,我前面讲过hwnd一般都是需要传入句柄的,这时咱们传入了Text1.hwnd(Text1控件的句柄),第二个参数,lpSting为字符串变量,所以这里咱们传入sBuffer字符串变量。最后一个cch为Long整形,所以理应传入数字,这里我们传入了255。现在又有人想问了,为什么需要这么传入值?貌似和以前的传入不一样?确实!一刚开始你可能搞不懂,这时候我先讲讲大概的意思,我们用GetWindowText来获取窗口中的文本,当获取成功以后,理所当然会返回窗口中的字符串,但是当我们用这个API进行获取时,必须需要一个缓冲来保存我们所获取的字符串,你如果不信去试试把sBuffer = Space(255)去掉,后面的255其实就是告诉这个API我们缓冲字符串的大小,这里再告诉大家一个技巧,以后只要是看见包函有cch字符时,大部分都是输入相关类型的大小。
 

     再附加一点,就里我说过,hwnd是用来传句柄的,你也可以传入其它窗口句柄,只要其它窗口有文本,都是可以通过这个API获取的。还有Text2.Text = sBuffer其实是可以先把sBuffer处理一下再传给Text2.Text的,关于字符串处理这里不讲。

 
     好了,分析结束,来个小提示:在Windows操作系统中,任何有句柄的东东都可被看作为一个窗口。另外你可能会去试试QQ的密码框,^_^ 这里我要告诉你一下,无法成功,为什么无法成功呢?这是一个技术问题目前不提!

 
     接着再来试试GetWindowsDirectory,大家看表面意思吧!Get(获取)Windows(就是Windows目录)Directory(目录),也就是获取咱们那个系统目录,如:C:\Windows。可能我的Windows目录中在C盘,而其它人的可能在D盘、E盘也说不定,所以有的时候软件需要这个API进行获取操作系统具体的Windows目录。

 
     好了,还是新建一个标准EXE,添加一个CommandButton,属性Caption=显示Windows目录,OK,写入以下代码:

 
   Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
   Private Sub Command1_Click()
       Dim sBuffer As String
   
       sBuffer = Space(255)
       GetWindowsDirectory sBuffer, 255
       MsgBox "Windows目录在: " & sBuffer
   End Sub
 

     分析!第一个Dim sBuffer As String字符串变量,sBuffer = Space(255)缓冲字符串,GetWindowsDirectory sBuffer, 255这个和上面所讲的一样,最后一个参数nSize为Long整形,所以传入数值,那传入什么数值呢?Size???当然是缓冲字符串大小了,以后遇到这个nSize一般也是传入相关类型的大小的。MsgBox "Windows目录在: " & sBuffer,是用MsgBox消息框显示出Windows目录的位置。

 
     OK,恭喜你,你又会使用了一个API,还要继续吗?(问:当然还要啦!答:最后一次哦!)

 
     GetWindowThreadProcessId,这次玩玩窗口进程,我估计有些人只要看见与进程有关的东东也会变得兴奋,呵呵!好了,先看看这个API是什么样的?如下:

 
   Private Declare Function GetWindowThreadProcessId Lib "user32" Alias "GetWindowThreadProcessId" (ByVal hwnd As Long, lpdwProcessId As Long) As Long

 
     看表面意思:Get(获取)Window(窗口)Thread(线程)Process(程序)Id(ID),组合:获取当前线程的窗口进程ID。至于进程ID要着有什么用,自己以后深入32编程就知道了。

     看看参数,ByVal hwnd As Long,哈哈,熟悉吧,一个hWnd句柄。lpdwProcessId As Long这个就是咱们需要的进程ID,老规矩,新建标准EXE,添加一个CommandButton,属性:Caption=获取窗口进程ID。代码如下:

 
   Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
   Private Sub Command1_Click()
       Dim PID As Long
   
       GetWindowThreadProcessId Me.hwnd, PID
   
       MsgBox "窗口进程的ID是:" & PID
   End Sub
 

     我已经习惯了给大家分析了。首先看看第一个参数,ByVal hwnd As Long,又是句柄来的(问:废话!答:教会了你也别这样啊),lpdwProcessId As Long,这个就要注意了,看看这个参数的传递方式,是以ByRef进行传递的(问:呵呵,不懂什么意思?答:不懂?转回去看过程函数这章),也就是说ByRef是以地址进行传递的,过程中可以改变传递的参数值。明白了吗?还不明白的话回去乖乖看书吧!现在明白了传递方式,也就是说我们声明的PID是用来获取窗口进程ID的,厉害啊。

     F5,运行之,点击Command1,PID出来了吧?没出来我马上从十楼跳下去。

 
     温馨小提示^_^:hWnd可以传入其它窗口句柄,同样可以获取其它窗口进程ID。

 
     接下来我们再来看看Set(设置),Set什么呢?当然还是Window(窗口)容易些,先列出几个常用的API:

 
     SetWindowLong、SetWindowPos、SetWindowRgn、SetWindowText
首先咱们先看SetWindowText,咱们在上面讲过GetWindowText这个API,GetWindowText是用来获取窗口文本的,而这个正好相反。现在可以看看表面意思Set(设置)Window(窗口)Text(文本),好了这样理解就够了,我们已经知道这个API是设置窗口文本的,接着咱们就到API浏览器中找找这个API,如下:

 
      Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long

      接着咱们看里面所需要传递的参数,一共有两,第一个ByVal hwnd As Long我就不用说了,传入句柄呗,第二个ByVal lpString As String,其中声明的lpString是字符串变量,可想而知,这里需要传入字符串,好了,开始实践。新建一个标准EXE,然后添加一个TextBox控件,然后再添加一个CommandButton,写入以下代码:

 
      Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long

      Private Sub Command1_Click()
         SetWindowText Text1.hwnd, "这是咱们设置的文本"
      End Sub

 
      呵呵,这个看似比前面的更简单,不过我还是要罗嗦一下,首先把Text1的句柄传入第一个参数,这样API知道咱们需要操作哪个翱冢 诙 鍪且桓鲎址 淞浚 哉饫锞褪俏颐切枰 氲奈谋尽:昧耍现5运行,点击Command1,OK。
 

      再看SetWindowPos,可以说这个API可以看成设置窗口位置,但是最终的实现效果取决于咱们传递的参数,好了,在API浏览器中找到这个API,如下:

 
      Private Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

      呵!好家伙,这个API看起来有些复杂啊?不过别担心,有我在嘛,我会帮你好好分析的,这里还请大家别光我一个人分析,必须把自己融入进来,咱们一起分析这样不更有趣?好了,废话少说,先看第一个参数:
 

    ByVal hwnd As Long    这里我就不讲了,传入窗口句柄
 

      ByVal hWndInsertAfter As Long 好了,看看这个!hwndInstrAfter,可以看到里面包函有hwnd字符,这时你可能会说我前面不是已经说过嘛,只要看见包函有hwnd字符的都应该传入句柄嘛?呵呵,没错,你很聪明,记得我说的话呢!在这里夸一下你,别骄傲啊!现在咱们好好分析一下这个地方应该传入哪些参数!打开MSDN,不好意思是英文,这里我就把翻译过来的说明放上来,如下:

 
    hWndInsertAfter -    Long,窗口句柄。在窗口列表中,窗口hwnd会置于这个窗口句柄的后面。也可能选用下述值之一:

 
    HWND_BOTTOM       将窗口置于窗口列表底部

 
    HWND_TOP          将窗口置于Z序列的顶部;Z序列代表在分级结构中,窗口针对一个给定级别的窗口显示的顺序

 
    HWND_TOPMOST      将窗口置于列表顶部,并位于任何最顶部窗口的前面

 
    HWND_NOTOPMOST    将窗口置于列表顶部,并位于任何最顶部窗口的后面

 
      可以看到这个地方有四个参数供我们选择,一般我们会使用第三个API常数和第四个API常数,这几个API常数都可以在API浏览器中找到,至于具体实现什么功能我相信大家都知道吧,后面有写呢!

 
      再看看后面的几个 x,y,cx,cy 分别为Long变量,我上面讲过,SetWindowPos可以看成设置窗口位置嘛,所以这里理所当然是传入相关的坐标值,如果忽略则为0,自己可以试下。

 
      ByVal wFlags As Long,这个参数,我又说过,看看字符Flags,呵呵,熟悉吧,所以这里咱们需要传入相关的标识常数,利用咱们以前学过的常数分析法进行分析,Set(S)Window(W)Pos(P)=SWP_ ,可以看到相关的常数了吧?这里我把相关常数的说明发上来大家看下,如下:

 
    SWP_DRAWFRAME      围绕窗口画一个框
 
    SWP_HIDEWINDOW     隐藏窗口
 
    SWP_NOACTIVATE     不激活窗口
 
    SWP_NOMOVE         保持当前位置(x和y设定将被忽略)
 
    SWP_NOREDRAW       窗口不自动重画
 
    SWP_NOSIZE         保持当前大小(cx和cy会被忽略)
 
    SWP_NOZORDER       保持窗口在列表的当前位置(hWndInsertAfter将被忽略)
 
    SWP_SHOWWINDOW     显示窗口
 
    SWP_FRAMECHANGED 强迫一条WM_NCCALCSIZE消息进入窗口,即使窗口的大小没有改变

      所以我说过,一个这样的API他具体实现的功能取决于你所传递的参数。假设这里咱们需要实现一个窗口永远置前的功能,首先新建一个标准EXE,输入以下代码:

 
      Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
 Private Const HWND_TOPMOST = -1
 Private Const SWP_NOMOVE = &H2
 Private Const SWP_NOSIZE = &H1
 Private Sub Form_Load()
       SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
 End Sub

      现在咱们开始分析,第一个参数传入句柄,第二个我上面讲过,实现什么功能传入什么参数,这里咱们是实现的窗口永久置前的功能,所以传入HWND_TOPMOST常数,现在看看其实坐标,如果你不想改变窗口的具体位置的话,这里可不设为0,再看看后面的wFlags,我传入了两个常数,这两个常数的相关说明请大家看看上面就知道,主要是不改变窗口位置和不改变窗口大小的前提下把窗口置前,其它常数如果大家有兴趣可以自己试试。

 
      最后一个,看看SetWindowRgn,这里我要解释一番,这个API所实现的功能呢就是改变窗口外观,也就是咱们所说的异形窗口等,通过这个API咱们可以把窗口改变成任何形状,在API浏览器找到这个API,如下:

 
      Private Declare Function SetWindowRgn Lib "user32" Alias "SetWindowRgn" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long

      好了,第一个参数,句柄。第二个参数,Long变量,这里需要传入什么咱们下面会讲到。第三个,Boolean变量,可以说明这里需要传入布尔值,Redraw为重画的意思,所以如果我们用这个API改变窗口形状,这里需要为True,表示重画窗口。

 
      现在新建一个标准EXE,然后把Form的ScaleMode设置成3-Pixel,我们知道Windows是以像素为单位的,所以使用这个API进行设置的时候是以像素为单位进行处理窗口外观。然后把BorderStyle设置为0-None,这样看得更明显。好了,写入以下代码:

 
    Private Declare Function SetWindowRgn Lib "user32" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
    Private Declare Function CreateRoundRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal X3 As Long, ByVal Y3 As Long) As Long
    Private Sub Form_Load()
        Dim hRgn As Long
   
        hRgn = CreateRoundRectRgn(0, 0, Me.ScaleWidth, Me.ScaleHeight, 10, 10)
        SetWindowRgn Me.hWnd, hRgn, True
    End Sub

      我不得不说一下这里我又用了一个API,主要是因为使用SetWindowRgn API是需要和其它API一起进行工作的,首先让我们先看看CreateRoundRectRgn这个API。分析如下:

 
      整体的意思是:创建圆角矩形。这里提示大家一个技巧,一般API中包函Rgn字符的都是代表可以改变对象外观的。可以看看我们使用的两个API,一个是SetWindowRgn(Rgn),一个是CreateRoundRectRgn(Rgn),希望你能明白其中的共同点。

    参数:x1,y1,x2,y2,x3,y3这些都是坐标值,具体说明见以下:
 
    X1,Y1 ----------    Long,矩形左上角的X,Y坐标
    X2,Y2 ----------    Long,矩形右下角的X,Y坐标
    X3 -------------    Long,圆角椭圆的宽。其范围从0(没有圆角)到矩形宽(全圆)
    Y3 -------------    Long,圆角椭圆的高。其范围从0(没有圆角)到矩形高(全圆)

      所以上面的代码具体是先通过CreateRoundRectRgn创建一个圆角矩形对象,然后通过SetWindowRgn来改变窗口的外观。
 
      小提示:使用CreateRoundRectRgn可以创建圆角矩形,也可以使用CreateEllipticRgn创建椭圆形,CreatePolyPolygonRgn创建多边形,CreateRectRgn矩形等,细心观察它们最后三个字符 Rgn 呵呵,明白了吧。

3,获取其它窗口的句柄
 
     这个我本来打算不讲的,不过网友们既然提出来了,我也只好详细说说。一般获取其它窗口的句柄使用以下API:

 
   FindWindow,FindWindowEx,WindowFromPoint
 

     这两个API就足矣,先看看第一个API的原型:

 
     Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

     里面一共有两个参数,先看第一个:ByVal lpClassName As String,字符串变量,所以这里需要传入字符串,第二个ByVal lpWindowName As String,同样一个字符串变量,这里也需要传入字符串。再看这个API为Function,有返回值的,那返回值就是我们需要的句柄了。好了,现在了解了两个参数的具体传递类型,那我们现在就要知道这两个参数中到底应该传入哪些值?如下:

 
   ByVal lpClassName As String,lpClassName:类名。指窗口类名,如果忽略则传入vbNullString。
 

   ByVal lpWindowName As String,lpWindowName:窗口名称。指窗口文本,如果忽略则传入vbNullString。

 
     现在明白了两个参数需要传入哪些值就好办了,一个窗口的类名咱们有可能不知道,但是一个窗口的名称就好办了。如:咱们打开记事本程序,可以看到窗口标题显示为“无标题-记事本”。好了这就是咱们需要的,现在咱们就要通过这个窗口标题来获取记事本的句柄。新建一个标准EXE,然后输入以下代码:

 
   Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
   Private Sub Form_Load()
       Dim WindowHandle As Long
   
       WindowHandle = FindWindow(vbNullString, "无标题 - 记事本")
       
       MsgBox WindowHandle
   End Sub
 

     好了,F5运行,显示MsgBox消息框,如果不为0,那么咱们就获取成功了,如果为0,那么表示获取失败,这个时候你有必要检查一下你所要获取的窗口文本是否符合你所要获取的那个窗口文本(呵,这句话还真长!)。具体代码意思我就不讲了,大家可以自己分析下。

 
     小提示:这个时候咱们已经得到句柄了,具体得到这个句柄干什么?那就看你了。给个例子,如下:

 
     SetWindowText WindowHandle, "哈哈"

 
     看看把这个代码放在上面代码中试下,呵呵!注意,SetWindowText你要先声明这个API。别忘了。

 


     再看第二个FindWindowEx,这个API是在窗口列表中寻找与指定条件相符的第一个子窗口,原型如下:

 
     Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

     看里面的参数,第一个和第二个:ByVal hWnd1 As Long,ByVal hWnd2 As Long,这里都需要传入句柄,再看第三个和第四个:ByVal lpsz1 As String, ByVal lpsz2 As String,这里所要传入的是字符串。具体意思如下:

   hWnd1 ----------   Long,在其中查找子的父窗口。如设为零,表示使用桌面窗口(通常说的顶级窗口都被认为是桌面的子窗口,所以也会对它们进行查找)

   hWnd2 ----------   Long,从这个窗口后开始查找。这样便可利用对FindWindowEx的多次调用找到符合条件的所有子窗口。如设为零,表示从第一个子窗口开始搜索

   lpsz1 ----------   String,欲搜索的类名。零表示忽略,注意一般传入vbNullString

   lpsz2 ----------   String,欲搜索的类名。零表示忽略,注意一般传入vbNullString

     用实践帮我们分析,这里还是拿记事本开刀。打开一个记事本,新建一个标准EXE,接着新建一个CommandButton,Caption设置为:设置文本。OK,写入以下代码:

 
   Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
   Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
   Private Declare Function EnableWindow Lib "user32" (ByVal hwnd As Long, ByVal fEnable As Long) As Long

   Private Sub Command1_Click()
       Dim WindowHandle As Long, ChildWindowHandle As Long
   
       WindowHandle = FindWindow(vbNullString, "无标题 - 记事本")
       
       If WindowHandle Then '如果获取句柄成功
               
           ChildWindowHandle = FindWindowEx(WindowHandle, 0, "Edit", vbNullString)
       
           If ChildWindowHandle Then '如果成功获取子句柄
               EnableWindow ChildWindowHandle, False '禁用子窗口
           Else
               MsgBox "无法获取子窗口"
           End If
       End If
   End Sub
 

     好了,帮大家分析。看第一行:Dim WindowHandle As Long, ChildWindowHandle As Long,用于储存获取的句柄的。WindowHandle = FindWindow(vbNullString, "无标题 - 记事本")这个就不用讲了,上面已经讲过。

 
     ChildWindowHandle = FindWindowEx(WindowHandle, 0, "Edit", vbNullString),这一段是通过我们已经获取的记事本句柄获取其中的子窗口句柄。大家可以用Spy++查看到记事本的TextBox类,然后根据类名写入即可。

 
     EnableWindow ChildWindowHandle, False 这又是一个新的API,虽然前面我没有前过,但是这个API使用起来及其简单。这个API中有两个参数,第一个理所当然是传入窗口句柄,第二个为Long变量,其实这里应该设为Boolean变量好些,主要是用来处理当前窗口是否可用。True可用,False禁用。

 
     现在F5运行,记得打开记事本哦,然后点击Command1,看看能不能在记事本的文本框中输入字符串?是否被禁用了?

 
     小提示:EnableWindow之所有讲出来,是希望提高大家使用API的兴趣,有些被禁用的窗口你可以使用这个API把它激活,至于怎么使用就看你自己了,这里给大家布置一个作业,呵呵,自己去完成吧。

 

 
     最后一个API,WindowFromPoint,这个API主要是获取当前坐标的窗口句柄,不是有人想知道当前鼠标指针位置的窗口句柄吗?用这个是不错的选择,原型如下:
 

   Private Declare Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal xPoint As Long, ByVal yPoint As Long) As Long

     两个参数,一个是xPoint(x坐标值),一个是yPoint(y坐标值),现在你可以在这个两个参数分别传入其它窗口的坐标值就可以获取其它窗口的句柄了。可以看到为Function声明,返回值就是咱们需要的句柄。

 
     咱们想实现的功能是获取当前鼠标指针位置的句柄,所以这里当然需要用到GetCursorPos了,结合前面所讲的,新建一个标准EXE,添加一个Timer控件,Interval设置为100,Enabled=True,OK,写如以下代码:

 
   Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
   Private Type POINTAPI
           x As Long
           y As Long
   End Type
   Private Sub Timer1_Timer()
       Dim lpPoint As POINTAPI
       Dim WindowHandle As Long
   
       GetCursorPos lpPoint '获取当前鼠标指针坐标
       WindowHandle = WindowFromPoint(lpPoint.x, lpPoint.y)
   
       Me.Caption = "当前鼠标指针位置句柄:" & WindowHandle
   End Sub

 
     好了,最后一次给大家分析了,至于GetCursorPos的使用与说明前面已经讲过,这里不再分析。看看WindowHandle = WindowFromPoint(lpPoint.x, lpPoint.y)这句,它是通过GetCursorPos获取的鼠标坐标值获取当前鼠标坐标位置的句柄。最后一句我就不用说了,在程序窗口显示获取的句柄。


 
 
     好了,API入门已经告一段落,其实我还想写下去,不过似乎看的人多,响应的人少,很是打击我写下去的心情。不过还是希望大家能从上面学到一些知识。具体的API应用我就不多说,大家可以自己慢慢体会。如果你把以上我讲的全部都搞懂的话,那么证明你已经基本了解API的使用方法了,那下面就靠你自己了。至此,我希望我带了一个好头帮助你了解API。
这次咱们来深入了解API在VB程序中的运用,并且有些复杂的API使用可能会使你感到很悲观,不过我会尽量用最容易让人理解的方式表达出来。注:如果你是一个刚入门API的初学者,那么请你先看看关于我写的初级API入门教程,也许会对了解API有帮助,地址:
http://www.vbgood.com/viewthread.php?tid=50241&extra=page%3D1


           一、API的类型结构。


               API的类型结构与VB中差不多,一般声明时使用Type定义类型。如果你不懂的话麻烦你先打开你的VB入门教程书看看。好了,文字理论咋不多说,用实例证实理论(偶喜欢这句话)。


           1,在Form窗体上用API画文字,最初了解类型结构填充


               ;Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long

           ;Private Const DT_CENTER = &H1

           ;Private Type RECT
                       Left As Long
                       Top As Long
                       Right As Long
                       Bottom As Long
           End Type


           Private Sub Form_Load()
                   Dim lpRect As RECT

                       Me.AutoRedraw = True
                   Me.ScaleMode = 3
                               '填充结构
                   With lpRect
                       .Left = 0
                       .Top = 0
                       .Right = Me.ScaleWidth
                       .Bottom = Me.ScaleHeight
               End With

                       DrawText Me.hdc, "这是文字效果", -1, lpRect, DT_CENTER
           End Sub


               好了,咱们开始分析,首先看Form_Load里面的代码。


               Dim lpRect As RECT。这一句是声明一个RECT自定义类型,这个类型可在VB浏览器的类型中找到。


               Me.AutoRedraw = True。这一句其实就是设置当前窗体的AutoRedraw属性,设为True,表示持久输出图像。不懂查帮助。


               Me.ScaleMode = 3。设置当前窗体的像素模式。至于为啥要设置为3,下面将会讲到。


               With lpRect...End With。从With 到 End With为填充咱们声明的lpRect类型结构。具体看里面的。


               .Left=0。这里相当于x坐标的初始值。


               .Top=0。这里相当于y坐标的初始值。


               .Right = Me.ScaleWidth。Right表示从Left开始的宽度。这里赋值为Me.ScaleWidth表示当前窗体像素的宽度。


               .Bottom = Me.ScaleHeight。同上。Bottom表示从Top开始的高度。Me.ScaleHeight表示当前窗体像素的高度。


               关键的就是下面一句,是它帮助我们在窗体中画出文字的。这里说一下为什么需要把当前窗体的坐标度量单位(ScaleMode)改成3(Pixel像素),因为Windows不管画什么都是以像素为单位,所以我们为了确定咱们所画的文本显示在正常位置,就必须使用像素为单位!明白了么??(问:还是不明白?答:默默无语两眼泪啊~~)


               DrawText Me.hdc, "这是文字效果", -1, lpRect, DT_CENTER


               现在分析这条API。看看里面需要传入的参数:ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long


               ByVal hdc As Long。hdc为Long整形,所以应该传入数值,不过给大家一个技巧,以后凡是看到hdc这个变量字符,表示需要传入的为一个hdc句柄,注意可不是hwnd句柄哦!这个句柄窗体和Picture控件都有,大家注意看就是了。


               ByVal lpStr As String。传入字符串。这里就是咱们需要画到窗体上的文本。


               ByVal nCount As Long。传入数值。看看里面的声明字符nCount,可以看出来这与数目有关,与什么数目呢?当然是文本罗。也就是说要显示的字符个数,一般如果需要全部显示出来可设为-1即可,表示显示所有字符。


               lpRect As RECT。一个Rect类型,这里需要使用Rect类型,上面我们已经在API浏览器找到了这个类型并声明了,所以只需要传入相应的类型声明就可以了。不过这次与我上一次讲的有所不同,上次是通过API类型结构获取相关的信息,而这次需要你把API类型结构填充好以后再传入进去。希望大家在这里注意下。可能有人要问了,那为什么这次就要这么做?我的回答是:因为API并不是万能的和灵活的,有的时候需要我们人为的设置一些参数来完成自己所需要这个API的功能,大家可以通过上面的结构填充就可知道,我们所要画文本的整个范围就是整个Form窗体的范围啊!


               ByVal wFormat As Long。传入数值,不过可以看看nFormat声明字符,可以想像这里可能需要传入这个API的使用格式,就如我们前面所讲的那样。现在打开API浏览器,在常数中找找,输入这个API的开头,Draw(D)Text(T)=DT_,可以看到有很多吧。具体这些都是什么意思可以查查相关的API资料。这里我们只传入了一个DT_CENTER常数,意思是居中显示。默认可以为0,因为这里为文字显示格式,所以你什么格式也不想要的话可设为0以后文字显示在左上角。


               OK。F5运行之。。。窗体中间正常显示“这就是文字效果”的几个文字。


               至此这里API相关结构的填充与获取我不想再多说了,不懂的话建议把我以前发的API入门帖子与这里的第一小节一起看看,或许你会明白些什么??

二、Windows 消息


              可以说这节是本文中的重点,当你能理解该节中的所有内容时,我相信你已经可以用该方法写出不错的程序功能了,好了,不说多了,接着往下来看。


              在了解消息之前,先让我们看看Windows 消息到底是什么?


              Windows系统是一个消息驱动的OS,所以操作都是基本消息驱动的,这就好比我用鼠标按下一个按钮,这时Windows会先发送该鼠标的左键按下消息,也就是WM_LBUTTONDOWN到你按下的那个CommandButton,这时就会激发按钮的CommandButton_MouseDown事件,然后松开鼠标,Windows这时会发送WM_LBUTTONUP消息,激发CommandButton_MouseUp事件,说明该鼠标按键已经弹起(松开),这时就会激发咱们VB中的 CommandButton_Click 事件,所以你点击某个按钮以后就会执行相应的操作。这里我不想说得太深太复杂,只是想以这种简单的理解方式让你明白Windows消息到底是什么,也许说得太含糊,但是对你第一次理解这东西已经足够了!


          实践1:


              现在就让我们以消息来写一个入门程序,先是打开VB(问:废话。答:……),然后打开API浏览器(问:早打开了。答:……),然后在API浏览器找到 SendMessage ,再然后在API 常数中找到 WM_CLOSE,好了,在VB工程中新建一个标准EXE,添加一个Command1按钮,写入以下代码:

              Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

              Private Const WM_CLOSE = &H10

              Private Sub Command1_Click()
                          SendMessage Me.hwnd, WM_CLOSE, 0, ByVal 0&
              End Sub


              好了,先看看 SendMessage 这个API,第一个参数,hWnd 为Long,所以传入一个对象的句柄,第二个参数 wMsg 同样为 Long,这里要说一下,在该API的第二个参数,大多数都是传入以 WM_ 为开关的常数,希望大家注意!第三个 wParam 也是 Long,该参数的意思大多数是取决于第二个参数 uMsg ,这里传入的常数是 WM_CLOSE,所以这里输入 0 即可,最后一个参数,lParam 为 Any,Any是什么意思这里我说一下,也就是是说明该参数可以指定为任何标准数据类型,允许将任意数据类型传递给该参数!希望你明白,该参数的值也是取决于 uMsg。


                      再看看 Command1_Click 事件中的代码,其中使用了SendMessage API,第一个是当前的窗口句柄,至于什么是句柄我在API初级入门时讲过,第二个为 WM_CLOSE 常数消息,也就是说给当前窗口发送关闭消息,第三、四个参数分别为0,具体参数我已经说过,取决于你在 uMsg 传入的常数。

                      现在 F5 运行点击Command1按钮试试。

                      小提示:注意这里的句柄当然也可以输入其它窗口的句柄,执行效果同上面一样,可以关闭你传递的那个句柄窗口!自己试一下,具体怎么获取窗口句柄我在VB初级入门时讲过,自己去试试吧!!!


                  实践2:


                      现在我们开始第二个消息程序,还是使用 SendMessage ,这次我们是要给一个按钮传递 Click(点击)事件,最近貌似有些人在问这个问题?现在就写出来大家实践实践。


                      新建一个标准EXE,添加两个 CommandButton 控件,分别为 Command1 和 Command2 ,然后输入以下代码:

                      Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

              Private Const BM_CLICK = &HF5

              Private Sub Command1_Click()
                          SendMessage Command2.hwnd, BM_CLICK, 0, ByVal 0&
              End Sub

              Private Sub Command2_Click()
                          MsgBox "command2"
              End Sub

                      这里先看看 BM_CLICK 常数,这个常数好像在VB自带的API浏览器中没有,所以大家可以把该常数自行复制到各自的VB程序中,也可以新建一个记事本保存下来,也可以把它添加到VB的API浏览器文本中等等。


                      再来看看 Command1_Click 事件,可见调用了 SendMessage API 向 Command2 中发送了 BM_CLICK 消息,该消息为按钮点击消息,后面的参数取决于 wMsg,所以后面两个为0即可,现在说一个为什么最后一个参数是写成 Byval 0&,写成这样的原因主要是因为最后一个参数变量,大家可以看看最后的参数变量 lParam As Any ,Any 是什么意思我已经说过,0& 后面的 & 其实为 Long 的简写,说白了 & 就是 Long 的意思,当然你可以在你程序写在 Dim ABC& 声明一个 Long 类型,而 Byval 0& 代表着是以传值方式进行传递该参数。不明白意思不要紧,翻开你的VB书多看看过程这章。

                      最后一个 Command2_Click 的 MsgBox "command2" 自然是显示一个消息。

                      好了,F5 运行试试。

                      小提示:同样该 hWnd 参数可以传递其它按钮句柄,实现效果同上面一样。

                              现在让我们看看 GetWindowLong 和 SetWindowLong 这两个“超级”API,为什么说超级呢?因为我们实现子类化少不了它们啊!

       基于vb的ocx和dll属性,代码论文重用性

直接调用这个api吧。

    今天开始,我向大家讲有关API的是实质性内容。我们就从"句柄"开始。
      只要你来到了API的世界,经常碰到的问题之一就是句柄。那么究竟什么是句柄呢?
      如果你从来都没有听说过"句柄"这个词,可能首先觉得句柄当中有很多内容。其实不然,所谓句柄实际上是一个数据,是一个Long (整长型)的数据。在API中,它经常是以一个参数的形式传递给各种API函数。如:
Public Declare Function GetWindow& Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long)

      其中,hwnd就是句柄。在VB里,句柄是一种属性,您打开VB中的对象游览器看一看Form窗体或者PictureBox控件等究竟有没有hwnd属性。是有的。VB中的解释是这样的∶
      Microsoft Windows 运行环境,通过给应用程序中的每个窗体和控件分配一个句柄(或 hWnd)来标识它们。hWnd
属性用于Windows API调用。许多 Windows 运行环境函数需要活动窗口的 hWnd 作为参数。

     如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?

      为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载
(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。
句柄地址(稳定)→记载着对象在内存中的地址————→对象在内存中的地址(不稳定)→实际对象

      但是,必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。
      在VB中获得一个对象的句柄十分简单,如要获取Form1窗体的句柄,就可以这样写∶Form1.Hwnd

      对象的句柄还可以通过API函数来获得,如∶

GetActiveWindow          返回位于最顶部的具有输入焦点的窗口句柄
GetFocus          获得当前线程里补获鼠标输入的窗口句柄
GetForegroundWindow          从位于前台的线程里返回活动窗口的句柄
GetCursor          取得当前指针的句柄
GetDesktopWindow          获取整个桌面的句柄
GetWindow          获得一个窗口的句柄,该窗口与某源窗口有特定的关系
《以上函数说明均可在WinAPI.hlp文件中找到。》

      本教程提供了演示例程——play1.vbp,正是为了说明这些函数的具体用法的。
程序运行后,用鼠标做一些任何你想做的事情,并观察各项目数据的变化。
通过本程序,注意观察以下几点∶
1,线程内与线程外。(VB不支持多线程)。其他应用程序对此程序来说都是线程外。
2,在windows95操作系统下,各个窗体(包括一些控件,如文本框,图片框等,MICROSORT对它们均统称为窗体)拥有各自的鼠标指针。这和win16下各应用程序使用同样一个指针是截然不同的。

3,每次从新启动,各窗体的句柄都有所变化。Text5 的装载和卸载过程中,句柄始终是在变化着的。这说明了上面提的影院售门票中存在的现象是真实的。

 

Q:想请教个问题,我如何知道其它窗体上的一个控件句柄,比如我做的程序只有FORM1窗口,现在我想在已经运行的程序如FORM2窗口上的TEXT1传入“你好”信息,该怎么做?

这次我专门为你开一个小灶,这是第一次,不过也是最后一次!好了,现在让我们看看如何向其它窗口的文本框传入字符串.还是老样子,新建一个标准EXE,接着新建两个Form窗体,分别为 Form1 和 Form2 ,现在我们在 Form1 中添加一个 CommandButton 按钮,然后再在 Form2 中添加一个 TextBox 文本控件和一个 CommandButton 按钮控件,现在在 Form1 中写入以下代码(一会下面有相关的源码下载):


         Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

         Private Const WM_SETTEXT = &HC

         Private Sub Command1_Click()
                 SendMessage Form2.Text1.hwnd, WM_SETTEXT, 0, ByVal "abcdefg"
                 SendMessage Form2.Command1.hwnd, WM_SETTEXT, 0, ByVal "hehe"
         End Sub

         Private Sub Form_Load()
                 Form2.Show
         End Sub


         其它的我不再分析了,大家注意看就是了,现在让我们看看 WM_SETTEXT 这个常数,该常数所代表的意思是向某对象发送设置文本消息,具体可以参考MSDN,其它的参数还是老样子,第一个是对象句柄(也可以说控件句柄),第二个是你给某某对象发的消息,第三个 wParam 参数我上面说过,以 wMsg 的值为定,这里保留为 0,现在关键是看看最后一个,lParam ,该参数为一个 Any 类型,也就是说我们可以传递任何值给任何对象,也就是说我们 wMsg 参数传递的为 WM_SETTEXT 消息,第三个参数为 Long 长整形,所以无法传递字符串,只能看最后一个,而恰好最好一个是可以传递任何类型的参数,所以这里就把我们需要传递的字符串输入即可,注意 lParam 是缺省 ByRef 传递的,ByRef 与 Byval 不同的是,ByRef 是以地址传递,而 Byval 是以参数值传递,所以你把上面的 Byval 去掉看看会产生什么后果?也就是说你传递的字符是一个地址,但是地址必须是整形,所以你去掉以后将会发生重大问题,不信自己试试!!轻则达不到预想的效果,重则 VB IDE(编程环境) 直接崩溃!!!

您的昵称:*
QQ登录(无需注册直接登录可进行回复)
您的邮箱:(填写邮箱,如有回复可进行邮件通知)
验证码:
点击刷新