DllImport 与 VB.NET 中的声明
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/937064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DllImport vs Declare in VB.NET
提问by Mike
I notice in the MSDN documentation that there are multiple waysto declare a reference to a function in an external DLL from within a VB.NET program.
我在 MSDN 文档中注意到有多种方法可以从 VB.NET 程序中声明对外部 DLL 中的函数的引用。
The confusing thing is that MSDN claims that you can only use the DllImportAttributeclass with Shared Function prototypes "in rare cases", but I couldn't find the explanation for this statement, while you can simply use the Declare
keyword instead.
令人困惑的是,MSDN 声称您只能在“极少数情况下”使用带有共享函数原型的DllImportAttribute类,但我找不到此声明的解释,而您可以简单地使用关键字来代替。Declare
Why are these different, and where would I appropriately use each case?
为什么这些不同,我应该在哪里适当地使用每种情况?
采纳答案by JaredPar
Declare is really an attempt to maintain a P/Invokesyntax which would be more familiar to Visual Basic 6.0 users converting to VB.NET. It has many of the same features as P/Invoke but the marshalling of certain types, in particular strings, are very different and can cause a bit of confusion to people more familiar with DllImport rules.
Declare 实际上是维护P/Invoke语法的一种尝试,对于转换到VB.NET 的Visual Basic 6.0 用户来说,它会更熟悉。它具有许多与 P/Invoke 相同的功能,但某些类型(特别是字符串)的编组非常不同,并且可能会给更熟悉 DllImport 规则的人造成一些混淆。
I'm not entirely sure what the documentation is alluding to with the "rare" distinction. I use DllImport in my code frequently from both VB.NET and C# without issue.
我不完全确定文档中提到的“罕见”区别是什么。我经常在 VB.NET 和 C# 的代码中使用 DllImport,没有问题。
In general, I would use DllImport over Declare unless you come from a Visual Basic 6.0 background. The documentation and samples for DllImport are much better and there are many tools aimed at generating DllImport declarations.
通常,除非您具有 Visual Basic 6.0 背景,否则我会使用 DllImport 而不是 Declare。DllImport 的文档和示例要好得多,并且有许多旨在生成 DllImport 声明的工具。
回答by leanne
Apparently the Declare and DllImport statements are basically the same. You can use whichever you prefer.
显然,Declare 和 DllImport 语句基本相同。您可以使用您喜欢的任何一种。
Following is a discussion of the few points that may work a little differently in each, which may influence a preference for one over the other:
以下是对在每个方面可能略有不同的几个点的讨论,这可能会影响对一个的偏好:
I started with an article from MSDN regarding Visual Studio 2003 titled Using the DllImport Attribute. (A bit old, but since the DllImport statement seems to have originated in .NET, it seemed appropriate to go back to the beginning.)
我从 MSDN 上一篇关于 Visual Studio 2003 的文章开始,标题为Using the DllImport Attribute。(有点旧,但由于 DllImport 语句似乎起源于 .NET,因此回到开头似乎是合适的。)
Given an example DllImport statement of:
给出一个示例 DllImport 语句:
[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned int uType);
It says that if the EntryPoint value is left out, the CLRwill look for the name of the function (MessageBox, in this case) as a default. However, in this instance, since a CharSet of Unicode was specified, the CLR would FIRST look for a function called "MessageBoxW" - the 'W' indicating a Unicode return type. (The ANSI return type version would be "MessageBoxA".) If no "MessageBoxW" were found, THEN the CLR would look for an API function actually called "MessageBox".
它表示如果忽略了 EntryPoint 值,CLR将查找函数的名称(在本例中为 MessageBox)作为默认值。但是,在这种情况下,由于指定了 Unicode 的 CharSet,CLR 将首先查找名为“MessageBoxW”的函数 - 指示 Unicode 返回类型的“W”。(ANSI 返回类型版本将是“MessageBoxA”。)如果未找到“MessageBoxW”,则 CLR 将查找实际称为“MessageBox”的 API 函数。
Current specifics about the DllImportAttribute class can be found here, where I viewed the .NET Framework 4 version: DLLImportAttribute Class
可以在此处找到有关 DllImportAttribute 类的当前详细信息,我在此处查看了 .NET Framework 4 版本:DLLImportAttribute Class
A key comment in the Remarks section of this .NET Framework 4 page is that:
此 .NET Framework 4 页面的备注部分中的一个关键评论是:
You apply this attribute directly to C# and C++ method definitions; however, the Visual Basic compiler emits this attribute when you use the Declare statement.
您可以直接将此属性应用于 C# 和 C++ 方法定义;但是,当您使用 Declare 语句时,Visual Basic 编译器会发出此属性。
So, at least as pertains to VB.NET, the compiler ends up with a Declare
statement anyway.
因此,至少对于 VB.NET 而言,编译器Declare
无论如何最终都会得到一条语句。
There is also an important note in this page:
这个页面还有一个重要的注意事项:
The DllImportAttribute does not support marshaling of generic types.
DllImportAttribute 不支持对泛型类型进行封送处理。
So, it would appear that if you want to use a generic type, you'd have to use a Declare
statement.
因此,看起来如果您想使用泛型类型,则必须使用Declare
语句。
Next, I headed to the Declare statement information. A Visual Studio 2010 version (Visual Basic statement info) was here: Declare Statement
接下来,我前往Declare 声明信息。Visual Studio 2010 版本(Visual Basic 语句信息)在这里:Declare Statement
A key item here was this note:
这里的一个关键项目是这个注释:
You can use Declare only at module level. This means the declaration context for an external reference must be a class, structure, or module, and cannot be a source file, namespace, interface, procedure, or block.
您只能在模块级别使用声明。这意味着外部引用的声明上下文必须是类、结构或模块,不能是源文件、命名空间、接口、过程或块。
Apparently, if you want to set up an API call outside of a class, structure, or module, you'll have to use the DllImport statement instead of the Declare
.
显然,如果要在类、结构或模块之外设置 API 调用,则必须使用 DllImport 语句而不是Declare
.
The example Declare
statement on this page is:
Declare
此页面上的示例语句是:
Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
Following that example is this little tidbit of information:
在这个例子之后是这个小信息:
The DllImportAttribute provides an alternative way of using functions in unmanaged code. The following example declares an imported function without using a Declare statement.
DllImportAttribute 提供了一种在非托管代码中使用函数的替代方法。下面的示例在不使用 Declare 语句的情况下声明一个导入的函数。
followed by, of course, an example of DllImport usage.
接下来当然是 DllImport 用法的一个例子。
Regarding Unicode vs ANSI results, according to this Declare page, if you specify a CharSet value (available in Declare, but not shown in the example above) the CLR will do the same type of automatic name search that DllImport does - for either Unicode or ANSI.
关于 Unicode 与 ANSI 结果,根据此声明页面,如果您指定 CharSet 值(在声明中可用,但未在上面的示例中显示),CLR 将执行与 DllImport 相同类型的自动名称搜索 - 对于 Unicode 或ANSI。
If you do not specify a CharSet value in the Declare
statement, then you must make sure that your function name in the Declare is the same as the function name in the actual API function's header file, OR you must specifiy an Alias
value that matches the actual function name in the header file (as shown in the example above).
如果你没有在Declare
语句中指定 CharSet 值,那么你必须确保你在 Declare 中的函数名与实际 API 函数的头文件中的函数名相同,或者你必须指定一个Alias
与实际函数匹配的值头文件中的名称(如上例所示)。
I was not able to find any specific Microsoft documentation stating that either DllImport or Declare were preferred, or even recommended, over one another in any situation other than those noted above.
我无法找到任何特定的 Microsoft 文档,说明在上述情况之外的任何情况下,DllImport 或 Declare 是首选,甚至是推荐的。
My conclusion, therefore, is:
因此,我的结论是:
1) Unless you need to place your definition in one of the places a Declare
statement cannot be used, either technique will work fine,
1) 除非您需要将定义放在Declare
不能使用语句的地方,否则两种技术都可以正常工作,
and
和
2) if you're using DllImport, make sure you specify the CharSet value you want (Unicode or ANSI), or you may get unexpected results.
2) 如果您使用的是 DllImport,请确保指定您想要的 CharSet 值(Unicode 或 ANSI),否则您可能会得到意想不到的结果。
回答by Shimmy Weitzhandler
In my opinion, since this keyword doesn't look deprected, etc. from what I searched, simply use compile-time keywords rather than attributes.
在我看来,由于这个关键字在我搜索的内容中看起来没有被弃用等,因此只需使用编译时关键字而不是属性。
Also, when you use the Declare
, you don't need to write the End Function
. The advantage of that is that you can create a whole module of declarations of function imports line by line, with no need to pulute your code with DllImport
s and End Function
s.
此外,当您使用 时Declare
,您无需编写End Function
. 这样做的好处是您可以逐行创建一个完整的函数导入声明模块,而无需使用DllImport
s 和End Function
s编写代码。
When you declare using the Declare
keyword, the compiler treats this function as Shared
anyway, so it can be accessed via other extenal objects.
当您使用Declare
关键字声明时,编译器会将此函数视为Shared
无论如何,因此可以通过其他外部对象访问它。
But I think in the current VB.NET they're both addressed to the same target and no performance difference - no warranty on this one.
但是我认为在当前的 VB.NET 中,它们都针对相同的目标并且没有性能差异 - 对此没有保证。
So my conclusion is: Do use the Declare instead of DllImport, especially reading what you quoted that Microsoft statedthat it should be used in rare cases.
所以我的结论是:请使用 Declare 而不是 DllImport,尤其是阅读您引用的Microsoft 声明应在极少数情况下使用的内容。
回答by BateTech
If you need to set one of the following options, then use DllImportAttribute
attribute, else use Declare
. From https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx
如果您需要设置以下选项之一,则使用DllImportAttribute
属性,否则使用Declare
. 来自https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx
To apply the BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError, or ThrowOnUnmappableChar fields to a Microsoft Visual Basic 2005 declaration, you must use the DllImportAttribute attribute instead of the Declare statement.
要将 BestFitMapping、CallingConvention、ExactSpelling、PreserveSig、SetLastError 或 ThrowOnUnmappableChar 字段应用于 Microsoft Visual Basic 2005 声明,您必须使用 DllImportAttribute 属性而不是 Declare 语句。
It is unclear from the above reference only whether this applies to only "Visual Basic 2005" or not, as the above reference is from a .NET 4.5 article. However, I also found this article (https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute(v=vs.110).aspx) which is specific to the DllImportAttribute
class in .NET 4.5 :
从上面的参考资料中不清楚这是否仅适用于“Visual Basic 2005”,因为上面的参考资料来自 .NET 4.5 文章。但是,我也发现了这篇文章(https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute(v=vs.110).aspx),它特定DllImportAttribute
于 .NET 中的类4.5 :
the Visual Basic compiler emits this attribute when you use the Declare statement. For complex method definitions that include BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError, or ThrowOnUnmappableChar fields, you apply this attribute directly to Visual Basic method definitions.
当您使用 Declare 语句时,Visual Basic 编译器会发出此属性。对于包含 BestFitMapping、CallingConvention、ExactSpelling、PreserveSig、SetLastError 或 ThrowOnUnmappableChar 字段的复杂方法定义,您可以将此特性直接应用于 Visual Basic 方法定义。
This tells you that the Declare
option is VB.net syntactical sugar which is converted to DllImportAttribute
at compile time, and outlines the exact scenarios when using DllImportAttribute
directly is recommended.
这告诉您该Declare
选项是DllImportAttribute
在编译时转换为的 VB.net 语法糖,并概述了DllImportAttribute
建议直接使用时的确切场景。