-
Declare 语句
声明对在外部文件中实现的过程的引用。
[ <attributelist> ] [ accessmodifier ] [ Shadows ] [ Overloads ] _
Declare [ charsetmodifier ] [ Sub ] name Lib "libname" _
[ Alias "aliasname" ] [ ([ parameterlist ]) ]
' -or-
[ <attributelist> ] [ accessmodifier ] [ Shadows ] [ Overloads ] _
Declare [ charsetmodifier ] [ Function ] name Lib "libname" _
[ Alias "aliasname" ] [ ([ parameterlist ]) ] [ As returntype ]
部件
术语 |
定义 |
attributelist |
可选。 请参见特性列表。 |
accessmodifier |
可选。 可以是如下内容之一:
请参见Visual Basic 中的访问级别。 |
Shadows |
可选。 请参见 Shadows。 |
charsetmodifier |
可选。 指定字符集和文件搜索信息。 可以是如下内容之一:
|
Sub |
可选项,但是 Sub 或 Function 必须出现。 指明外部过程并不返回值。 |
Function |
可选项,但是 Sub 或 Function 必须出现。 指明外部过程返回值。 |
name |
必选。 此外部引用的名称。 有关更多信息,请参见 已声明的元素名称 (Visual Basic)。 |
Lib |
必选。 引入 Lib 子句,用于标识包含外部过程的外部文件(DLL 或代码资源)。 |
libname |
必选。 包含所声明过程的文件的名称。 |
Alias |
可选。 指明无法在所声明过程的文件内依据 name 中指定的名称标识该过程。 您在 aliasname 中指定其标识。 |
aliasname |
如果使用 Alias 关键字,则为必选项。 按以下两种方式之一标识过程的字符串: 过程在其文件内的入口点名称,括在引号 ("") 内 - 或 - 在数字符号 (#)后跟一个整数,指定过程入口点在其文件内的序号 |
parameterlist |
如果过程接受参数,则为必选项。 请参见参数列表 (Visual Basic)。 |
returntype |
如果指定了 Function,并且 Option Strict 为 On,则为必选项。 过程所返回值的数据类型。 |
备注
有时,您需要调用在项目外部的某个文件(如 DLL 或代码资源)中定义的过程。 当您这样做时,Visual Basic 编译器没有权限访问其正确调用过程所需的信息,例如过程的位置、标识方式、调用顺序和返回类型,以及过程使用的字符串字符集。 Declare 语句创建一个对外部过程的引用,并提供这些必需的信息。
仅可以在模块级别使用 Declare。 这意味着,外部引用的声明上下文必须是类、结构或模块,不能是源文件、命名空间、接口、过程或块。 有关更多信息,请参见声明上下文和默认访问级别 (Visual Basic)。
外部引用默认为 Public (Visual Basic) 访问。 可以使用访问修饰符来调整它们的访问级别。
规则
-
**特性。**可以将特性应用于外部引用。 所应用的任何特性都只在项目中有效,在外部文件中无效。
-
**修饰符。**外部过程隐式地为 Shared (Visual Basic)。 声明外部引用时不能使用 Shared 关键字,也不能改变它的共享状态。
外部过程不能参与重写过程、实现接口成员或处理事件。 因此,不能在 Declare 语句中使用 Overrides、Overridable、NotOverridable、MustOverride、Implements 或 Handles 关键字。
-
**外部过程名称。**不必(在 name 中)为此外部引用指定与过程在其外部文件内的入口点名称 (aliasname) 相同的名称。 可以使用 Alias 子句来指定入口点名称。 如果外部过程具有与 Visual Basic 保留修饰符或变量、过程或同一范围中的任何其他编程元素相同的名称,这一点可能十分有用。
提示
大多数 DLL 中的入口点名称都区分大小写。
-
**外部过程编号。**或者,您可以使用 Alias 子句来指定外部文件的导出表内入口点的序号。 为此,您可使用数字符号 (#) 作为 aliasname 的开头。 如果不允许在 Visual Basic 中使用外部过程名称中的任何字符,或者,如果外部文件在导出过程时未使用名称,则这一点十分有用。
数据类型规则
-
**参数数据类型。**如果 Option Strict 为 On,您必须指定 parameterlist 中每个参数的数据类型。 这可以是任何数据类型或枚举、结构、类或接口的名称。 在 parameterlist 内,您使用 As 子句来指定要传递给每个参数的变量的数据类型。
提示
如果外部过程不是针对 .NET Framework 编写的,您必须注意应使数据类型相符。 例如,如果用 Integer 参数(在 Visual Basic 6.0 中为 16 位)声明对 Visual Basic 6.0 过程的引用,则必须在 Declare 语句中将对应的变量标识为 Short,因为在 Visual Basic 中它是 16 位的整数类型。 同样,Long 在 Visual Basic 6.0 中具有不同的数据宽度,并且 Date 的实现方式也不同。
-
**返回数据类型。**如果外部过程是 Function,并且 Option Strict 设置为 On,您必须指定返回到调用代码的值的数据类型。 这可以是任何数据类型或枚举、结构、类或接口的名称。
提示
Visual Basic 编译器不会验证您的数据类型是否与外部过程的数据类型兼容。 如果存在不匹配现象,公共语言运行时将在运行时产生 MarshalDirectiveException 异常。
-
**默认数据类型。**如果 Option Strict 设置为 Off,并且未在 parameterlist 中指定某个形参的数据类型,Visual Basic 编译器会将对应的实参转换为 Object 数据类型。 同样,如果未指定 returntype,编译器会将返回数据类型转换为 Object。
提示
由于所处理的外部过程有可能是在不同平台上编写的,因此,对数据类型做出任何假定或允许它们采用默认设置会十分危险。 指定每个参数和返回值(如果有)的数据类型将会安全很多。 这还提高了代码的可读性。
行为
-
**范围。**外部引用的应用范围覆盖了其整个类、结构或模块。
-
**生存期。**外部引用具有与声明它的类、结构或模块相同的生存期。
-
**调用外部过程。**调用外部过程的方式与调用 Function 或 Sub 过程时相同,都是在表达式中使用它(如果它返回值)或在 Call 语句 (Visual Basic) 中指定它(如果它不返回值)。
您将完全按照 Declare 语句中的 parameterlist 指定的方式将变量传递给外部过程。 不要考虑参数最初在外部文件中的声明方式。 同样,如果存在返回值,请完全按照 Declare 语句中 returntype 指定的方式使用它。
-
**字符集。**可以在 charsetmodifier 中指定 Visual Basic 在调用外部过程时应如何封送字符串。 Ansi 修饰符指示 Visual Basic 将所有字符串封送为 ANSI 值,Unicode 修饰符则指示它将所有字符串封送为 Unicode 值。 Auto 修饰符指示 Visual Basic 依据 .NET Framework 规则,基于外部引用 name 或 aliasname(如果已指定)封送字符串。 默认值为 Ansi。
charsetmodifier 还指定 Visual Basic 应如何在外部文件中查找外部过程。 Ansi 和 Unicode 都指示 Visual Basic 在搜索过程中查找外部过程而不修改其名称。 Auto 指示 Visual Basic 确定运行时平台的基本字符集,并在可能时修改外部过程名称,如下所示:
-
在 ANSI 平台(如 Windows 95、Windows 98 或 Windows Millennium Edition)上,将首先查找外部过程,而不修改名称。 如果查找失败,则在外部过程名称结尾附加“A”,并再次查找。
-
在 Unicode 平台(如 Windows NT、Windows 2000 或 Windows XP)上,将首先查找外部过程,而不修改名称。 如果查找失败,则在外部过程名称结尾附加“W”,并再次查找。
-
-
**机制。**Visual Basic 使用 .NET Framework 的平台调用 (PInvoke) 机制来解析和访问外部过程。 Declare 语句和 DllImportAttribute 类都会自动使用此机制,您无需对 PInvoke 有任何了解。 有关更多信息,请参见 演练:调用 Windows API (Visual Basic)。
安全说明 |
---|
如果外部过程在公共语言运行时 (CLR) 外部运行,则它为非托管代码。 当您调用此类过程(例如,Win32 API 函数或 COM 方法)时,可能会使应用程序面临安全风险。 有关更多信息,请参见 非托管代码。 |
示例
下面的示例声明对 Function 过程的外部引用,该过程返回当前用户名。 它随后调用外部过程 GetUserNameA 作为 getUser 过程的一部分。
Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
Sub getUser()
Dim buffer As String = New String(CChar(" "), 25)
Dim retVal As Integer = getUserName(buffer, 25)
Dim userName As String = Strings.Left(buffer, InStr(buffer, Chr(0)) - 1)
MsgBox(userName)
End Sub
DllImportAttribute 提供了另一种在非托管代码中使用函数的方式。 下面的示例声明导入了一个函数,但不使用 Declare 语句。
' Add an Imports statement at the top of the class, structure, or
' module that uses the DllImport attribute.
Imports System.Runtime.InteropServices
<DllImportAttribute("kernel32.dll", EntryPoint:="MoveFileW",
SetLastError:=True, CharSet:=CharSet.Unicode,
ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)>
Public Shared Function moveFile(ByVal src As String,
ByVal dst As String) As Boolean
' This function copies a file from the path src to the path dst.
' Leave this function empty. The DLLImport attribute forces calls
' to moveFile to be forwarded to MoveFileW in KERNEL32.DLL.
End Function
原文链接:https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/4zey12w5(v=vs.100)