-
vb教程之怎样手工声明API
尽管 Visual Basic 在 Win32api.txt 中提供了大量的预定义声明,但还是需要知道如何亲自编写声明。例如,有时希望访问用其它语言编写的 DLL 中的过程,或者改写 Visual Basic 的预定义声明,以满足特殊需要。
要声明一个 API 过程,需要在代码窗口的“声明”部分增加一个 Declare 语句。如果该过程返回一个值,应将其声明为 Function:
Declare Function publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])] As Type
如果过程没有返回值,可将其声明为 Sub:
Declare Sub publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])]
缺省情况下,在标准模块中声明的 API 过程是公有的,可以在应用程序的任何地方调用它。在其它类型的模块中定义的 API 过程是模块私有的,必须在它们前面声明 Private 关键字,以示区分。
一.指定库
Declare 语句中的 Lib 子句用来告诉 Visual Basic 如何找到包含过程的 .API 文件。如果引用的过程属于 Windows 核心库(User32、Kernel32 或 GDI32),则可以不包含文件扩展名:
Declare Function GetTickCount Lib "kernel32" Alias _
"GetTickCount" () As Long
对于其它 DLL,Lib 子句指定文件的路径:
Declare Function lzCopy Lib "c:\windows\lzexpand.API" _
(ByVal S As Integer, ByVal D As Integer) As Long
如果未指定 libname 的路径,Visual Basic 将按照下列顺序查找该文件:
.exe 文件所在的目录
当前目录
Windows 位系统目录(通常为 \Windows\System)
Windows 目录(不一定是 \Windows)
Path 环境变量中的目录
下表中列出了通常的操作系统环境库文件。
动态链接库 描述
Advapi32.API 高级 API 服务,支持大量的 API(其中包括许多安全与注册方面的调用)
Comdlg32.API 通用对话框 API 库
Gdi32.API 图形设备接口 API 库
Kernel32.API Windows 32 位核心的 API 支持
Lz32.API 32 位压缩例程
Mpr.API 多接口路由器库
Netapi32.API 32 位网络 API 库
Shell32.API 32 位 Shell API 库
User32.API 用户接口例程库
Version.API 版本库
Winmm.API Windows 多媒体库
Winspool.drv 后台打印接口,包含后台打印 API 调用。
二.处理使用字符串的 Windows API 过程
如果调用的 Windows API 过程要使用字符串,那么声明语句中必须增加一个 Alias 子句,以指定正确的字符集。包含字符串的 Windows API 函数实际有两种格式:ANSI 和 Unicode。因此,在 Windows 头文件中,每个包含字符串的函数都同时有 ANSI 版本和 Unicode 版本。
例如,下面是 SetWindowText 函数的两种 C 语言描述。可以看到,第一个描述将函数定义为 SetWindowTextA,尾部的“A”表明它是一个 ANSI 函数:
WINUSERAPI
BOOL
WINAPI
SetWindowTextA(
HWND hWnd,
LPCSTR lpString);
第二个描述将它定义为 SetWindowTextW,尾部的“W”表明它是一个 Unicode 函数:
WINUSERAPI
BOOL
WINAPI
SetWindowTextW(
HWND hWnd,
LPCWSTR lpString);
因为两个函数实际的名称都不是“SetWindowText”,要引用正确的函数就必须增加一个 Alias 子句:
Private Declare Function SetWindowText Lib "user32" _
Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _
lpString As String) As Long
请注意,Alias 子句后面的字符串必须是过程的真正名称,而且必须是区分大小写的。
对于 Visual Basic 中使用的 API 函数,应该指定函数的 ANSI 版本,因为只有 Windows NT 才支持 Unicode 版本,而 Windows 95 不支持这个版本。仅当应用程序只运行在 Windows NT 平台上的时候才可以使用 Unicode 版本。
三.使用值或引用传递
在缺省的情况下,Visual Basic 以引用方式传递所有参数。这意味着并没有传递实际的参数值,Visual Basic 只传递了数据的 32 位地址。在 Declare 语句中不要求包含 ByRef 关键字,但是如果包含该关键字,就能够清楚地看出数据是以何种方式传递的。
许多 API 过程要求参数以值方式传递。这意味着它们需要实际的数据,而不是数据的内存地址。如果过程需要一个传值参数,而传递给它的参数是一个指针,那么由于得到了错误的数据,该过程将不能正确地工作。
要使参数以使用值方式传递,在 Declare 语句中需要在参数声明的前面加上 ByVal 关键字。例如,InvertRect 过程要求第一个参数使用值,而第二个使用引用:
Declare Function InvertRect Lib "user32" Alias _
"InvertRectA" (ByVal hdc As Long, _
lpRect As RECT) As Long
也可以在调用过程时使用 ByVal 关键字。
字符串参数是一个特例。如果以使用值方式传递字符串,那么传递的将是该字符串中第一个数据字节的地址;如果以使用引用方式传递字符串,那么实际传递的将是用来保存另一个地址的内存单元的地址;后面的“地址”实际是字符串的第一个数据字节的内存地址。
要声明一个 API 过程,需要在代码窗口的“声明”部分增加一个 Declare 语句。如果该过程返回一个值,应将其声明为 Function:
Declare Function publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])] As Type
如果过程没有返回值,可将其声明为 Sub:
Declare Sub publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])]
缺省情况下,在标准模块中声明的 API 过程是公有的,可以在应用程序的任何地方调用它。在其它类型的模块中定义的 API 过程是模块私有的,必须在它们前面声明 Private 关键字,以示区分。
一.指定库
Declare 语句中的 Lib 子句用来告诉 Visual Basic 如何找到包含过程的 .API 文件。如果引用的过程属于 Windows 核心库(User32、Kernel32 或 GDI32),则可以不包含文件扩展名:
Declare Function GetTickCount Lib "kernel32" Alias _
"GetTickCount" () As Long
对于其它 DLL,Lib 子句指定文件的路径:
Declare Function lzCopy Lib "c:\windows\lzexpand.API" _
(ByVal S As Integer, ByVal D As Integer) As Long
如果未指定 libname 的路径,Visual Basic 将按照下列顺序查找该文件:
.exe 文件所在的目录
当前目录
Windows 位系统目录(通常为 \Windows\System)
Windows 目录(不一定是 \Windows)
Path 环境变量中的目录
下表中列出了通常的操作系统环境库文件。
动态链接库 描述
Advapi32.API 高级 API 服务,支持大量的 API(其中包括许多安全与注册方面的调用)
Comdlg32.API 通用对话框 API 库
Gdi32.API 图形设备接口 API 库
Kernel32.API Windows 32 位核心的 API 支持
Lz32.API 32 位压缩例程
Mpr.API 多接口路由器库
Netapi32.API 32 位网络 API 库
Shell32.API 32 位 Shell API 库
User32.API 用户接口例程库
Version.API 版本库
Winmm.API Windows 多媒体库
Winspool.drv 后台打印接口,包含后台打印 API 调用。
二.处理使用字符串的 Windows API 过程
如果调用的 Windows API 过程要使用字符串,那么声明语句中必须增加一个 Alias 子句,以指定正确的字符集。包含字符串的 Windows API 函数实际有两种格式:ANSI 和 Unicode。因此,在 Windows 头文件中,每个包含字符串的函数都同时有 ANSI 版本和 Unicode 版本。
例如,下面是 SetWindowText 函数的两种 C 语言描述。可以看到,第一个描述将函数定义为 SetWindowTextA,尾部的“A”表明它是一个 ANSI 函数:
WINUSERAPI
BOOL
WINAPI
SetWindowTextA(
HWND hWnd,
LPCSTR lpString);
第二个描述将它定义为 SetWindowTextW,尾部的“W”表明它是一个 Unicode 函数:
WINUSERAPI
BOOL
WINAPI
SetWindowTextW(
HWND hWnd,
LPCWSTR lpString);
因为两个函数实际的名称都不是“SetWindowText”,要引用正确的函数就必须增加一个 Alias 子句:
Private Declare Function SetWindowText Lib "user32" _
Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _
lpString As String) As Long
请注意,Alias 子句后面的字符串必须是过程的真正名称,而且必须是区分大小写的。
对于 Visual Basic 中使用的 API 函数,应该指定函数的 ANSI 版本,因为只有 Windows NT 才支持 Unicode 版本,而 Windows 95 不支持这个版本。仅当应用程序只运行在 Windows NT 平台上的时候才可以使用 Unicode 版本。
三.使用值或引用传递
在缺省的情况下,Visual Basic 以引用方式传递所有参数。这意味着并没有传递实际的参数值,Visual Basic 只传递了数据的 32 位地址。在 Declare 语句中不要求包含 ByRef 关键字,但是如果包含该关键字,就能够清楚地看出数据是以何种方式传递的。
许多 API 过程要求参数以值方式传递。这意味着它们需要实际的数据,而不是数据的内存地址。如果过程需要一个传值参数,而传递给它的参数是一个指针,那么由于得到了错误的数据,该过程将不能正确地工作。
要使参数以使用值方式传递,在 Declare 语句中需要在参数声明的前面加上 ByVal 关键字。例如,InvertRect 过程要求第一个参数使用值,而第二个使用引用:
Declare Function InvertRect Lib "user32" Alias _
"InvertRectA" (ByVal hdc As Long, _
lpRect As RECT) As Long
也可以在调用过程时使用 ByVal 关键字。
字符串参数是一个特例。如果以使用值方式传递字符串,那么传递的将是该字符串中第一个数据字节的地址;如果以使用引用方式传递字符串,那么实际传递的将是用来保存另一个地址的内存单元的地址;后面的“地址”实际是字符串的第一个数据字节的内存地址。
最新更新
求1000阶乘的结果末尾有多少个0
详解MyBatis延迟加载是如何实现的
IDEA 控制台中文乱码4种解决方案
SpringBoot中版本兼容性处理的实现示例
Spring的IOC解决程序耦合的实现
详解Spring多数据源如何切换
Java报错:UnsupportedOperationException in Col
使用Spring Batch实现批处理任务的详细教程
java中怎么将多个音频文件拼接合成一个
SpringBoot整合ES多个精确值查询 terms功能实
数据库审计与智能监控:从日志分析到异
SQL Server 中的数据类型隐式转换问题
SQL Server中T-SQL 数据类型转换详解
sqlserver 数据类型转换小实验
SQL Server数据类型转换方法
SQL Server 2017无法连接到服务器的问题解决
SQLServer地址搜索性能优化
Sql Server查询性能优化之不可小觑的书签查
SQL Server数据库的高性能优化经验总结
SQL SERVER性能优化综述(很好的总结,不要错
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比