我在MSDN文档中注意到有multiple ways从VB.NET程序中声明对外部DLL中的函数的引用。
令人困惑的是,MSDN声称您只能将DllImportAttribute类与共享函数原型“in rare cases”一起使用,但我无法找到此声明的解释,而您可以简单地请改用Declare
关键字。
为什么这些不同,我会在哪里恰当地使用每个案例?
答案 0 :(得分:18)
显然,Declare和DllImport语句基本相同。你可以使用你喜欢的任何一种。
以下是对每一点可能会有所不同的几点的讨论,这可能会影响对另一方的偏好:
我从MSDN开始撰写一篇名为Using the DllImport Attribute的Visual Studio 2003文章。 (有点旧,但由于DllImport语句似乎起源于.NET,因此回到开头似乎是合适的。)
给出一个示例DllImport语句:
[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned int uType);
它表示如果遗漏了EntryPoint值,CLR将查找函数的名称(在本例中为MessageBox)作为默认值。但是,在这种情况下,由于指定了Unicode的CharSet,因此CLR将首先查找名为“MessageBoxW”的函数 - 表示Unicode返回类型的“W”。 (ANSI返回类型版本将是“MessageBoxA”。)如果没有找到“MessageBoxW”,那么CLR将寻找实际上称为“MessageBox”的API函数。
可以在此处找到有关DllImportAttribute类的当前详细信息,其中我查看了.NET Framework 4版本:DLLImportAttribute Class
此.NET Framework 4页面的“备注”部分中的关键注释是:
您可以将此属性直接应用于C#和C ++方法定义;但是,当您使用Declare语句时,Visual Basic编译器会发出此属性。
因此,至少与VB.NET相关,编译器最终会以Declare
语句结束。
此页面中还有一个重要提示:
DllImportAttribute不支持封送泛型类型。
因此,如果您想使用泛型类型,则必须使用Declare
语句。
接下来,我前往Declare声明信息。 Visual Studio 2010版本(Visual Basic语句信息)位于:Declare Statement
这里的一个关键项目就是这个说明:
您只能在模块级别使用Declare。这意味着外部引用的声明上下文必须是类,结构或模块,并且不能是源文件,命名空间,接口,过程或块。
显然,如果要在类,结构或模块之外设置API调用,则必须使用DllImport语句而不是Declare
。
此页面上的示例Declare
语句为:
Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
在这个例子之后是这个小小的信息:
DllImportAttribute提供了在非托管代码中使用函数的替代方法。以下示例声明导入的函数,而不使用Declare语句。
当然是DllImport用法的一个例子。
关于Unicode与ANSI结果,根据此Declare页面,如果指定CharSet值(在Declare中可用,但未在上面的示例中显示),CLR将执行与DllImport相同类型的自动名称搜索 - 对于Unicode或ANSI。
如果未在Declare
语句中指定CharSet值,则必须确保Declare中的函数名与实际API函数头文件中的函数名相同,或者必须指定一个Alias
值,该值与头文件中的实际函数名称相匹配(如上例所示)。
我无法找到任何特定的Microsoft文档,声明在上述情况之外的任何情况下,DllImport或Declare都是首选的,甚至是推荐的。
因此,我的结论是:
1)除非您需要将您的定义放在其中一个地方,否则无法使用Declare
语句,这两种技术都可以正常使用,
和
2)如果您正在使用DllImport,请确保指定所需的CharSet值(Unicode或ANSI),否则可能会出现意外结果。
答案 1 :(得分:10)
声明实际上是尝试维护P/Invoke语法,对于转换为VB.NET的Visual Basic 6.0用户来说,这种语法更为熟悉。它具有许多与P / Invoke相同的功能,但是某些类型的编组,特别是字符串,是非常不同的,并且可能对更熟悉DllImport规则的人造成一些混淆。
我不完全确定文档中提到的“罕见”区别。我经常在VB.NET和C#的代码中使用DllImport而没有问题。
一般情况下,我会使用DllImport而不是Declare,除非你来自Visual Basic 6.0背景。 DllImport的文档和示例要好得多,并且有许多工具旨在生成DllImport声明。
答案 2 :(得分:6)
在我看来,由于这个关键字看起来并不像我搜索过的那样,所以只需使用编译时关键字而不是属性。
此外,当您使用Declare
时,您无需编写End Function
。这样做的好处是,您可以逐行创建函数导入声明的整个模块,而无需使用DllImport
和End Function
来填充代码。
当您声明使用Declare
关键字时,编译器无论如何都会将此函数视为Shared
,因此可以通过其他外部对象访问它。
但我认为在目前的VB.NET中,它们都是针对同一目标而没有性能差异 - 对此没有保证。
所以我的结论是:使用Declare而不是DllImport ,尤其是阅读Microsoft stated引用的内容,在极少数情况下应该使用它。
答案 3 :(得分:1)
如果您需要设置以下选项之一,请使用DllImportAttribute
属性,否则请使用Declare
。来自https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx
应用BestFitMapping,CallingConvention,ExactSpelling, PreserveSig,SetLastError或ThrowOnUnmappableChar字段为a Microsoft Visual Basic 2005声明,必须使用 DllImportAttribute属性而不是Declare语句。
仅从上述参考文献中不清楚这是否仅适用于" Visual Basic 2005"或不,因为上面的参考是来自.NET 4.5的文章。但是,我还发现这篇文章(https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute(v=vs.110).aspx)特定于.NET 4.5中的DllImportAttribute
类:
使用时,Visual Basic编译器会发出此属性 声明声明。 对于包含的复杂方法定义 BestFitMapping,CallingConvention,ExactSpelling,PreserveSig, SetLastError或ThrowOnUnmappableChar字段,您可以应用它 直接归因于Visual Basic方法定义。
这告诉您Declare
选项是VB.net语法糖,在编译时转换为DllImportAttribute
,并概述了建议直接使用DllImportAttribute
时的确切方案。 / p>