转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> VB.NET程序 >> 正文
VB5.0与Windows API 间的呼叫技巧         ★★★★

VB5.0与Windows API 间的呼叫技巧

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2223 更新时间:2009/4/23 18:58:23

VB5.0与Windows API 间的呼叫技巧

一般会使用WINDOW API的情况,实在是因为VB本身不提供某些功能,但是,程式所
需又不得不然,例如:读取Registry内的资料,VB只提供SaveSetting、Getsetting 等
系列的指令,但是它只能读取特定地区的值,要读、删、更动其他区域的值时,就无法
使用。再如:仔细看一看Combo Box的Events,其中没有MouseMove,但这是我们经常用
上的一个Event,那该如何呢?是的,那只有透过Winodow API。而VB呼叫Window API一
般不都使用API检视员,直接将相对应的API COPY到我们的程式中就好,那还用什麽技
巧吗?其实不然,因为VB资料格式的问题,又加上VB本身没有指标,在许多地方需要一
些小技巧才能解决,而且我们经常因应不同的需求,将API 检视员的宣告COPY过来後再
做一些修改,最重要的,如果有一个.DLL档,它不在API 检视员中定义,那时,就只有
自己想办法啦。

一、 整数参数

Windows API32位元VB
============================== =============================
Int, INT ByVal Long
UNIT, DWORD ByVal Long
BOOL ByVal Long ture时为1
WPARAM, LPARAM, LRESULT ByVal Long
Handle(如HKEY) ByVal Long
WORD, ATOM, SHORT ByVal Integer
BYTE, CHAR ByVal Byte

Eg.
-----------------------------------------------------------------------------
Windows API 宣告

SHORT GetKeyState( int nVirtKey )

对应的VB宣告

Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
-----------------------------------------------------------------------------

这个API 可用来检视某些KEY (如Insert键、Num Lock、CapsLock等)是on/off。程
式如下:这个例子应该可十分楚的看到各个整数间的宣告对应。

-----------------------------------------------------------------------------
Dim InsertMode as Integer
InsertMode = GetKeyState(vbKeyInsert) And vbShiftMask
If InsertMode = 1 then
Debug.print "表示 Insert Mode"
Else
Debug.print "表示 OverWrite Mode"
End If
-----------------------------------------------------------------------------
二、 指向整数的指标

Windows API 32位元VB
============================ ==========================
LPINT (ByRef ) Long
LPUNIT (ByRef ) Long
LPBOOL (ByRef ) Long
LPDWORD (ByRef ) Long
LPHANDLE (如:PHKEY) (ByRef ) Long
LPWORD (ByRef ) Integer
LPSHORT (ByRef ) Integer
LPBYTE (ByRef ) Byte

VB内定是使用传址呼叫,所以ByRef 可以省略,也就是说
Func(ByRef param1 as type)

Func(param1 as type)
是相同的,使用传址呼叫的方式,不外乎想将参数传给API 後将结果传回来。然而LONG
型态的传址呼叫在VB中又占了相当大的份量,因为32位元的指标都是LONG的型态,而字
串、自定型态的Structure在Windows API中是以指标来传递的,而指标的传递事实上也
是Long值的传递,只不过传过去的LONG值,於WIN API中会将之当成Address,而再配合
指标运作而得指标所指的内容,这个观念在後面会很重要。

例如:
-----------------------------------------------------------------------------
LONG RegOpenKeyEx(
HKEY hKey, // handle of open key
LPCTSTR lpszSubKey, // address of name of subkey to open
DWORD dwReserved, // reserved
REGSAM samDesired, // security access mask
PHKEY phkResult // address of handle of open key
);
相对应的VB 宣告
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" _
(ByVal hKey As Long, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
phkResult As Long) As Long ''''//最後一个参数是ByRef之宣告
-----------------------------------------------------------------------------

我们经常会想要用程式来读取Registry中的资料,例如:我们想得知Win95的Produ
ct ID该如何做呢?这里有几个观念要先清楚:首先:ProductId在何处呢?在

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVerson下的ProductId。

我们要取得的便是

KEY 为 HKEY_LOCAL_MACHINE
SUBKEY 为 SOFTWARE\Microsoft\Windows\CurrentVerson
ValueName 为 ProductId 的value

然而要取得ProductId的value可没那麽直接,要先取得SubKey的KeyHandle而Key
Handle的取得便是利用RegQueryKeyEx的API 。程式部份在介绍Win API字串传递时再一
并介绍。

三、 字串参数

凡是所有字串参数指标都以 ByVal 参数名称 As String 传。如RegOpenKeyEx()的
第二参数 ByVal lpSubKey As String,便是一例。或许会问,这个例子是把subkey值传
给 Win API所以用ByVal,没什麽大不了,其实不然,要Win API传回字串时,也一定要
用ByVal的宣告。这是VB5字串格式(BSTR)与WIN API标准字串格式(LPSTR)不同的因素。
LPSTR 字串格式是NULL Terminate的字串,若有一字串"HaHa !OK!",则格式如下:


-----------------------------------------------------------------------------
Address 0 1 2 3 4 5 6 7 8 9
-- -- -- -- -- -- -- -- -- --
内容 H a H a ! O K ! \0

而BSTR则在字串的前面还有一个LONG值存字串长度,格式如下:

Address 0.. 3 4 5 6 7 8 9 10 11 12 13
------ -- -- -- -- -- -- -- -- -- --
内容 9 H a H a ! O K ! \0
-----------------------------------------------------------------------------

所以了字串以ByVal的方式来传像不像指到BSTR中第4个位置,如此一来,不就和LP
STR 可以相容了吗?我想也正因为如此以ByVal的方式来传String可以取得Win API的传
回值,(就算不是如此,至少这麽想比较记得住String要用ByVal的方式传)。现在又有一
个问题,Window95 API的字串使用的是ASCII Code但VB是用Unicode,Unicode占两个位
元组,那麽能和WinAPI的字串相?所幸我们可以先不用管它,因为vb本身做了转换,即
vb传给api时,转了一次,传回时又转回 Unicode,所以如果我们用的是Byte Array来
传字串,也可以但是要自己去转码。
。然而32位元的VB 中,字串有种格式,一个是BSTR,另一个是HLSTR,如果我们宣告的
串是非固定长度者,就会是BSTR,反之则为HLSTR。

DIM BSTR5 AS STRING   BSTR
DIM HLSTR5 AS STRING(255)   HLSTR

VB5中WIN32 API的呼叫请多多使用BSTR,因为使用HLSTR的结果是,VB还得做HLSTR
-> BSTR的转换来呼叫WIN API若有传回STRING而後再做BSTR->HLSTR的工作。然而使用
BSTR来工作时,若处理有传回值的STRING参数,则还要有额外的动作:

1.先给定字串的初值,且字串的长度要够放传回值。
2.传回後,去除传回值中多余的字元。


例如:
-----------------------------------------------------------------------------
int GetWindowText(
HWND hWnd, // handle of window or control with text
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum number of characters to copy
);
该 API 取得WINDOW Title Bar的文字,而传回值是放入lpString的character个数。
VB的宣告如下:

Decl are Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hwnd As Long, _
ByVal lpString As String, _
ByVal cch As Long) As Long
范例一
*****************************************************************************
Dim CharCnt As Long
Dim lpString As String
Dim tmpstr As String
Dim NullPos As Long

Form1.Caption = "这是一个test"
lpString = String(255, 0) ''''设定初值
CharCnt = GetWindowText(Me.hwnd, lpString, 256) ''''CharCnt = 12
tmpstr = Left(lpString, CharCnt) ''''如此做会有一些问题
Debug.Print Len(tmpstr) ''''得12
Label1.Caption = Left(lpString, CharCnt)
Debug.Print Len(Label1.Caption) ''''得8
*****************************************************************************

以范例一的例子来看,设定lpString= String(255,0)的目的,是设定255个字元的
空间给 lpString(加上最後的null一共256),CharCnt的值是12,明眼者可看到len("这
是一个test") 会是8,但CharCnt是12, 所以直接使用Left()函数来取得子字串会有问
题,这是UniCode与ANSI String间的关系,所以了,当您看到有些书的范例用这种方法
取子字串,是不太完善的,所以改用范例二的方式,比较正确。

范例二
*****************************************************************************
Form1.Caption = "这是一个test"
lpString = String(255, 0) ''''设定初值
CharCnt = GetWindowText(Me.hwnd, lpString, 256) ''''CharCnt = 12
NullPos = InStr(1, lpString, Chr(0), vbBinaryCompare)
tmpstr = Left(lpString, NullPos - 1)
lable1.Caption = tmpstr
*****************************************************************************
四、 Null 值的传递

我们再回到求ProductId的问题,我们已知使用RegOpenKeyEx()来取得subkey的Han
dle值,紧接著便是用RegQueryValueEx()来取值。

-----------------------------------------------------------------------------
LONG RegQueryValueEx(
HKEY hKey, // handle of key to query
LPTSTR lpszValueName, // address of name of value to query
LPDWORD lpdwReserved, // reserved
LPDWORD lpdwType, // address of buffer for value type
LPBYTE lpbData, // address of data buffer
LPDWORD lpcbData // address of data buffer size
);
VB的宣告(由API检视员中Copy下来者)
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" _
(ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
lpType As Long, _
lpData As Any, _
lpcbData As Long) As Long
-----------------------------------------------------------------------------
仔细看一下第三个参数,WIN API中是LPDWORD可是VB中麽会是用ByVal的方式传递
呢?原因在於 lpReserved一定要传Null进去,VB在呼叫时便在 这参数的位置上填0(见
范例三)。为何传Null就得这做?我们可以这麽想,我们 在程式中下指令,告诉VB要以
ByVal 的方式传0出去,而WIN API里,它可不管VB是ByVal或ByRef,API 认定我们传

来的就是它需要的,所以了,第三个参数在API中认定我们传进的是一个Address,而VB
传0进去,那代表API若去取得它的内容,便会取得Address 0 的内容,或许Window的
Null值便是指向Address 0呢!另一个作法比较直接,将VB宣告的第三个参数宣告由
ByVal lpReserved As Long改成 ByVal lpReserved as String而使用时固定传
vbNullString 进去也可以。这里在一个观念,那就是VB对Win API的宣告,纯粹是给VB
自己看的,在API中定义了一个指标的参数,Api检视员会将之宣告成ByRef的方式(字串
除外),但我们可随需要而更动它,一个原始应为ByRef的参数宣告,我们可以将之改为
ByVal的方式,只要我们能取得参数的位址,而将这型态为Long的位址以ByVal传出去,
Win API 端根本不知道VB端是用什麽方式传,反正只要我们传了一Long值进去,Win API
就会以这个Long值当作是Address来运作。

问题还没有解决,RegQueryValueEx()的第四个参数lpType若为REG_SZ(= 1)那代表
lpData是Null Terminate的String,若为REG_DWORD ( = 4)那代表lpData是Long值,

是因为没有办法事先知道lpData的真正型态,所以VB就使用 ASAny的型态,它要VB放弃
型态的检查,传什麽值进去都可以,但是在这里有一些问题,如果lpType是REG_DWORD
那麽lpData以ByRef的方式没有问题,但是如果lpType 是REG_SZ,STRING是要以ByVal
的方式来宣告,所以会有冲突,而解决的方式就是改写API检视员Copy进来的宣告。

-----------------------------------------------------------------------------
Declare Function RegQueryLong Lib "advapi32.dll" Alias "RegQueryValueExA" _
(ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
lpType As Long, _
lpData As Long, _
lpcbData As Long) As Long

Declare Function RegQueryString Lib "advapi32.dll" Alias "RegQueryValueExA" _
(ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
lpType As Long, _
Byval lpData As String, _
lpcbData As Long) As Long
-----------------------------------------------------------------------------
使用两个宣告来解决这个问题,依不同的lpType呼叫不同的函式,即lpType= REG_
DWORD时,呼叫RegQueryLong, lpType = REG_SZ时则为RegQueryString这也可以让我们
了解为何VB API的宣告为什麽要有Alias的存在。

范例三
*****************************************************************************
Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) _
As Long
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA"
(ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, _
ByVal samDesired As Long, phkResult As Long) As Long
Declare Function RegQueryString Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, _
ByVal lpValueName As String, ByVal lpReserved As Long, _
lpType As Long, ByVal lpData As String, lpcbData As Long) As Long
Const REG_EXPAND_SZ = 2
Const HKEY_CLASSES_ROOT = &H80000000
Const READ_CONTROL = &

[1] [2] [3]  下一页


[VB.NET程序]Auto Complete combo Box(VB.NET Source Use API…  [VB.NET程序]在 VB 中使用 Unicode API
[VB.NET程序]API 更改系统菜单条目  [VB.NET程序]在VB中调用Windows API的注意事项
[VB.NET程序]vb调用winInet API接口post数据到指定的url  [VB.NET程序]如 何 用 API 播 放 CD
[VB.NET程序]在VB6中用WINDOWS API函数读写INI文件  [VB.NET程序]Visual Basic调用Windows API函数的应用举例
[VB.NET程序]VB + API 获取 IE 的 代理服务器 配制  [Delphi程序]Windows API函数使用技巧
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台