DllImport vs VB.NET中的声明

时间:2009-06-01 22:11:40

标签: vb.net dllimport declare

我在MSDN文档中注意到有multiple ways从VB.NET程序中声明对外部DLL中的函数的引用。

令人困惑的是,MSDN声称您只能将DllImportAttribute类与共享函数原型“in rare cases”一起使用,但我无法找到此声明的解释,而您可以简单地请改用Declare关键字。

为什么这些不同,我会在哪里恰当地使用每个案例?

4 个答案:

答案 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。这样做的好处是,您可以逐行创建函数导入声明的整个模块,而无需使用DllImportEnd 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>