VB调用DLL

作为一种32Windows应用程序的开发工具,VB生成的exe文件自然也都是32位的,通常情况下也只能调用32位的动态连接库。但是,并不是所有的32位动态库都能被VB生成的exe 文件正确地识别。

一般来说,自己编写用于VB应用程序调用的动态连接库时,应注意以下几个方面的问题:

  1、生成动态库时要使用__stdcall调用约定,而不能使用缺省的__cdecl调用约定;__stdcall 约定通常用于32API函数的调用。

  2、在VC中的定义文件(.def)中,必须列出输出函数的函数名,以强制VC系统将输出函数的装饰名(decoratedname)改成普通函数名;所谓装饰名是VC的编译器在编译过程中生成的输出函数名,它包含了用户定义的函数名、函数参数及函数所在的类等多方面的信息。由于在VC中定义文件不是必需的,因此工程不包含定义文件时VC就按自己的约定将用户定义的输出函数名修改成装饰名后放到输出函数列表中,这样的输出函数在VB生成的应用程序中是不能正确调用的(除非声明时使用Alias子句)。因此需要增加一个.def文件,其中列出用户需要的函数名,以强制VC不按装饰名进行输出。

  3VC中的编译选项"结构成员对齐方式(structure member alignment应设成4字节,其原因将在后文详细介绍。

  4、由于在C中整型变量是4个字节,而VB中的整型变量依然只有2个字节,因此在C中声明的整型(int)变量在VB中调用时要声明为长整型(long),而C中的短整型(short)在VB中则 要声明成整型(integer);下表针对最常用的C语言数据类型列出了与之等价的Visual Basic 类型(用于32位版本的Windows)。

C语言数据类型在VisualBasic中声明为调用时使用的表达式

   ATOM ByVal variable As Integer 结果为Integer 类型的表达式

   BOOL ByVal variable As Long 结果为 Long 类型的表达式

   BYTE ByVal variable As Byte 结果为 Byte 类型的表达式

   CHAR ByVal variable As Byte 结果为 Byte 类型的表达式

   COLORREF ByVal variable As Long 结果为 Long 类型的表达式

   DWORD ByVal variable As Long 结果为 Long 类型的表达式

   HWND, HDC, HMENU ByVal variable As Long 结果为 Long 类型的表达式等Windows 句柄

   INT, UINT ByVal variable As Long 结果为 Long 类型的表达式

   LONG ByVal variable As Long 结果为 Long 类型的表达式

   LPARAM ByVal variable As Long 结果为 Long 类型的表达式

   LPDWORD variable As Long 结果为 Long 类型的表达式

   LPINT, LPUINT variable As Long 结果为 Long 类型的表达式

   LPRECT variable As type 自定义类型的任意变量

   LPSTR, LPCSTR ByVal variable As String 结果为 String 类型的表达式

   LPVOID variable As Any 任何变量(在传递字符串的时候使用ByVal

   LPWORD variable As Integer 结果为Integer 类型的表达式

   LRESULT ByVal variable As Long 结果为 Long 类型的表达式

   NULL As Any  ByVal Nothing 

   ByVal variable As Long ByVal 0&  VBNullString

   SHORT ByVal variable As Integer 结果为Integer 类型的表达式

   VOID Sub procedure 不可用

   WORD ByVal variable As Integer 结果为Integer 类型的表达式

   WPARAM ByVal variable As Long 结果为 Long 类型的表达式

5 VB 中进行 32 位动态库的声明时,函数名是大小写敏感的。在获得了需要的动态连接   库之后,就可以在 VB 中进行调用了。

下面就具体介绍一下在VB中调用API函数时需要做的工作。

要声明一个DLL过程,首先需要在代码窗口的"通用(General"部分增加一个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]]...])] 

  缺省情况下,在标准模块中声明的DLL过程,可以在应用程序的任何地方调用它。在其它类型的模块中定义的DLL过程则是模块私有的,必须在它们前面声明Private关键字,以示区分。下面分别介绍声明语句的各个组成部分。

()、指定动态库:

  Declare语句中的Lib子句用来告诉Visual Basic如何找到包含过程的.dll文件。 如果引用的过程属于Windows核心库(User32Kernel32GDI32),则可以不包含文件扩展名,如:

   Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount" () As Long 

   对于其它动态连接库,可以在Lib子句指定文件的路径:

   Declare Function lzCopy Lib "c:/windows/lzexpand.dll" _

   (ByVal S As Integer, ByVal D As Integer) As Long 

如果未指定libname的路径,Visual Basic将按照下列顺序查找该文件:

  ①.exe文件所在的目录

  ②当前目录

  ③Windows系统目录

  ④Windows目录

  ⑤Path环境变量中的目录

  下表中列出了常用的操作系统环境库文件。

  动态链接库描述

  Advapi32.dll高级API服务,支持大量的API(其中包括许多安全与注册方面的调用)

  Comdlg32.dll通用对话框API

  Gdi32.dll图形设备接口API

  Kernel32.dllWindows32位核心的API支持

  Lz32.dll32位压缩例程

  Mpr.dll多接口路由器库

  Netapi32.dll32位网络API

  Shell32.dll32ShellAPI

  User32.dll用户接口例程库

  Version.dll版本库

  Winmm.dllWindows多媒体库

  Winspool.drv后台打印接口,包含后台打印API调用。

  对于Windows的系统API函数,可以利用VB提供的工具API Viewer查找某一函数及其相 关数据结构和常数的声明,并复制到自己的程序中。

()、使用别名:

A.函数名是标准的名称

  Declare语句中的Alias子句是一个可选的部分,用户可以通过它所标识的别名对动态 库中的函数进行引用。例如,在下面的语句中,声明了一个在VB中名为MyFunction的函数,而它在动态库Mydll.dll中最初的名字是MyFunctionX

   Private Declare Function MyFunction Lib "Mydll.dll" _

   Alias "MyFunctionX" ( ) As Long 

  需要注意的是,Alias子句中的函数名是大小写敏感的,也就是说,必须与函数在生成时的声明(如在C源文件中的声明)一致。这是因为32位动态库与16位动态库不同,其中的函数名是区分大小写的。同样道理,如果没有使用Alias子句,那么在Function(或Sub)后的函数名也是区分大小写的。

通常在以下几种情况时需要使用 Alias 子句:

如果调用的系统Windows API过程要使用字符串,那么声明语句中必须增加一个Alias 子句,以指定正确的字符集。包含字符串的系统Windows API函数实际有两种格式:ANSIUnicode 关于ANSIUnicode两种字符集的区别将在后面详细阐述)。因此,在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

  应当注意,对于VB中使用的系统WindowsAPI函数,应该指定函数的ANSI版本,因为只 WindowsNT才支持Unicode版本,而Windows95不支持这个版本。仅当应用程序只运行 WindowsNT平台上的时候才可以使用Unicode版本。

()、使用值或引用传递

  在缺省的情况下,VB以引用方式传递所有参数(ByRef)。这意味着并没有传递实际的参 数值,VB只传递了数据的32位地址。另外有许多DLL过程要求参数以值方式传递(ByVal)。这意味着它们需要实际的数据,而不是数据的内存地址。如果过程需要一个传值参数,而传递给它的参数是一个指针,那么由于得到了错误的数据,该过程将不能正确地工作。要使参数以使用值方式传递,在Declare语句中需要在参数声明的前面加上ByVal关键字。例如InvertRect过程要求第一个参数用传值方式传递,而第二个用引用方式传递:

Declare Function InvertRect Lib "user32" Alias _

"InvertRectA" (ByVal hdc As Long, lpRect As RECT) As Long

  动态连接库的参数传递是一个复杂的问题,也是VB中调用动态连接库时最容易出现错误的地方。参数类型或传递方式的声明错误都可能导致应用程序出现GPF(通用保护错误),甚至使操作系统崩溃。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值