在VB中调用动态连接库

出处:www.examlink.com 作者:小罗 日期:2007年01月24日 14时23分

  WINUSERAPIBOOLWINAPISetWindowTextW(HWNDhWnd,LPCWSTRlpString);

  因为两个函数实际的名称都不是'SetWindowText',要引用正确的函数就必须增加一个Alias子句:

  PrivateDeclareFunctionSetWindowTextLib'user32'_

  Alias'SetWindowTextA'(ByValhwndAsLong,ByVal_

  lpStringAsString)AsLong

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

  B。函数名是不标准的名称

  有时,个别的DLL过程的名称不是有效的标识符。例如,它可能包含了非法的字符(如连字符),或者名称是VB的关键字(如GetObject)。在这种情况下,可以使用Alias关键字。例如,操作环境DLLs中的某些过程名以下划线开始。尽管在VB标识符中允许使用标识符,但是下划线不能作为标识符的第一个字符。为了使用这种过程,必须先声明一个名称合法的过程,然后用Alias子句引用过程的真实名称:

  DeclareFunctionlopenLib'kernel32'Alias'_lopen'_

  (ByVallpPathNameAsString,ByValiReadWrite_

  AsLong)AsLong

  在上例中,lopen是VB中使用的过程名称。而_lopen则是动态连接库中可以识别的名称。

  C。使用序号标识DLL过程

  除了使用名称之外,还可以使用序号来标识DLL过程。某些动态连接库中不包含过程的名称,在声明它们包含的过程时必须使用序号。同使用名称标识的DLL过程相比,如果使用序号,在最终的应用程序中消耗的内存将比较少,而且速度会快些。但是,一个具体的API的序号在不同的操作系统中可能是不同的。例如GetWindowsDirectory在Win95下的序号为432,而在WindowsNT4。0下为338。总而言之,如果希望应用程序能够在不同的操作系统下运行,那么最好不要使用序号来标识API过程。如果过程不属于API,或者应用程序使用的范围很有限,那么使用序号还是有好处的。

  要使用序号来声明DLL过程,Alias子句中的字符串需要包含过程的序号,并在序号的前面加一个数字标记字符(#)。例如,Windowskernel中的GetWindowsDirectory函数的序号为432;可以用下面的语句来声明该DLL过程:

  DeclareFunctionGetWindowsDirectoryLib'kernel32'_

  Alias'#432'(ByVallpBufferAsString,_

  ByValnSizeAsLong)AsLong

  在这里,可以使用任意的合法名称作为过程的名称,VB将用序号在DLL中寻找过程。

  为了得到要声明的过程的序号,可以使用Dumpbin。exe等实用工具(Dumpbin。exe是MicrosoftVisualC++提供的一个实用工具,它的使用说明可以参见VC的文档)。利用Dumpbin,可以提取出。dll文件中的各种信息,例如DLL中的函数列表,它们的序号以及与代码有关的其它信息。

  (三)、使用值或引用传递

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

  要使参数以使用值方式传递,在Declare语句中需要在参数声明的前面加上ByVal关键字。例如InvertRect过程要求第一个参数用传值方式传递,而第二个用引用方式传递:

  DeclareFunctionInvertRectLib'user32'Alias_

  'InvertRectA'(ByValhdcAsLong,lpRectAsRECT)AsLong

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

  (四)、灵活的参数类型

  某些DLL过程的同一个参数能够接受多种数据类型。如果需要传递多种类型的数据,可以将参数声明为AsAny,从而取消类型限制。例如,下面的声明中的第三个参数(lpptAsAny)既可以传递一个POINT结构的数组,也可以传递一个RECT结构:

  DeclareFunctionMapWindowPointsLib'user32'Alias_

  'MapWindowPoints'(ByValhwndFromAsLong,_

  ByValhwndToAsLong,lpptAsAny,_

  ByValcPointsAsLong)AsLong

  AsAny子句提供了一定的灵活性,但是,由于它不进行任何的类型检查,风险也随之增加。因此在使用AsAny子句时,必须仔细检查所有参数的类型。

  正确的函数声明是在VB中调用动态连接库的前提,但要想在VB中用对、用好动态库中的函数,仅仅有声明还是远远不够的。前面已经说过,由于VB不能验证应用程序传递到动态连接库中的参数值是否正确,因此就要求程序员应对参数类型有非常详细的了解,否则很容易引起应用程序发生通用保护错或导致潜在的Bug,降低软件的可靠性。下面将参数类型分为简单数据类型、字符串、和用户自定义类型三种分别进行讨论。

最后更新时间:2008-05-28 11:40:52
文章评论
共有 0 位网友发表了评论
用户名: 新注册) 密码: 匿名评论 [查看所有评论]

评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
您可以用以下几种方式找到此文章

考试全流程