VB.NET 中的 DllImport 与声明

发布于 2024-07-21 20:33:08 字数 596 浏览 2 评论 0 原文

我注意到 MSDN 文档中有多种方法来声明引用从 VB.NET 程序中调用外部 DLL 中的函数。

令人困惑的是,MSDN 声称您只能使用 具有共享函数原型的 DllImportAttribute 类“在极少数情况下” ,但我找不到此语句的解释,而您可以简单地使用 而是使用 Declare 关键字。

为什么这些不同,我应该在哪里适当地使用每种情况?

I notice in the MSDN documentation that there are multiple ways to declare a reference to a function in an external DLL from within a VB.NET program.

The confusing thing is that MSDN claims that you can only use the DllImportAttribute class 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.

Why are these different, and where would I appropriately use each case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鹤舞 2024-07-28 20:33:08

显然 Declare 和 DllImport 语句基本相同。 您可以使用您喜欢的任何一个。

以下是对每个要点的讨论,这些要点的工作方式可能略有不同,这可能会影响对其中一个的偏好:

我从 MSDN 上一篇关于 Visual Studio 2003 的文章开始,标题为 使用 DllImport 属性。 (有点旧,但由于 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”的函数 - “W”表示 Unicode 返回类型。 (ANSI 返回类型版本将为“MessageBoxA”。)如果未找到“MessageBoxW”,则 CLR 将查找实际称为“MessageBox”的 API 函数。

有关 DllImportAttribute 类的当前详细信息可以在此处找到,我在其中查看了 .NET Framework 4 版本:DLLImportAttribute Class

此 .NET Framework 4 页面的“备注”部分中的关键注释是:

您可以将此属性直接应用于 C# 和 C++ 方法定义; 但是,当您使用 Declare 语句时,Visual Basic 编译器会发出此属性。

因此,在 VB.NET 中,使用 Declare 语句会导致编译器生成 DLLImportAttribute

此页面还有一个重要注释:

DllImportAttribute 不支持泛型类型的封送处理。

因此,如果您想使用泛型类型,则必须使用 Declare 语句。

接下来,我前往 Declare 声明信息。 Visual Studio 2010 版本(Visual Basic 语句信息)位于:声明声明

这里的一个关键项目是这个注释:

您只能在模块级别使用 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 语句的地方,否则任何一种技术都可以正常工作,

并且

  1. 如果您使用 DllImport,请确保指定所需的 CharSet 值(Unicode 或 ANSI),否则可能会得到意外结果。

Apparently the Declare and DllImport statements are basically the same. You can use whichever you prefer.

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.)

Given an example DllImport statement of:

[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 CLR will 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".

Current specifics about the DllImportAttribute class can be found here, where I viewed the .NET Framework 4 version: DLLImportAttribute Class

A key comment in the Remarks section of this .NET Framework 4 page is that:

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.

So, in VB.NET, using the Declare statement causes the compiler to generate a DLLImportAttribute.

There is also an important note in this page:

The DllImportAttribute does not support marshaling of generic types.

So, it would appear that if you want to use a generic type, you'd have to use a Declare statement.

Next, I headed to the Declare statement information. A Visual Studio 2010 version (Visual Basic statement info) was here: 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.

The example Declare statement on this page is:

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.

followed by, of course, an example of DllImport usage.

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.

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).

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.

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,

and

  1. if you're using DllImport, make sure you specify the CharSet value you want (Unicode or ANSI), or you may get unexpected results.
输什么也不输骨气 2024-07-28 20:33:08

Declare 实际上是维护 Visual Basic 6.0 更熟悉的 P/Invoke 语法的尝试用户转换为 VB.NET。 它具有许多与 P/Invoke 相同的功能,但某些类型(特别是字符串)的编组非常不同,可能会给更熟悉 DllImport 规则的人带来一些混乱。

我不完全确定文档中提到的“罕见”区别是什么。 我经常在 VB.NET 和 C# 代码中使用 DllImport,没有出现任何问题。

一般来说,我会使用 DllImport 而不是 Declare,除非您有 Visual Basic 6.0 背景。 DllImport 的文档和示例要好得多,并且有许多旨在生成 DllImport 声明的工具。

Declare is really an attempt to maintain a P/Invoke syntax 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.

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.

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.

心病无药医 2024-07-28 20:33:08

在我看来,由于从我搜索的内容来看,这个关键字看起来并没有被弃用,因此只需使用编译时关键字而不是属性。

另外,当您使用Declare时,您不需要编写End Function。 这样做的优点是,您可以逐行创建函数导入声明的整个模块,而无需使用 DllImportEnd Function 来填充代码。

当您使用Declare关键字进行声明时,编译器无论如何都会将此函数视为Shared,因此可以通过其他外部对象访问它。

但我认为在当前的 VB.NET 中,它们都针对相同的目标,并且没有性能差异 - 对此没有任何保证。

所以我的结论是:请使用 Declare 而不是 DllImport,尤其是阅读您引用的内容 微软表示应该在极少数情况下使用它。

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 DllImports and End Functions.

When you declare using the Declare keyword, the compiler treats this function as Shared anyway, so it can be accessed via other extenal objects.

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.

So my conclusion is: Do use the Declare instead of DllImport, especially reading what you quoted that Microsoft stated that it should be used in rare cases.

我还不会笑 2024-07-28 20:33:08

如果您需要设置以下选项之一,请使用 DllImportAttribute 属性,否则使用 Declare。 来自 https://msdn.microsoft.com/en-us/library/w4byd5y4。 ASPX

要应用 BestFitMapping、CallingConvention、ExactSpelling,
将serveSig、SetLastError 或ThrowOnUnmappableChar 字段保留到
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 ),这是特定于 DllImportAttribute 类:

当您使用
声明声明。 对于复杂的方法定义,包括
BestFitMapping、CallingConvention、ExactSpelling、PreserveSig、
SetLastError 或 ThrowOnUnmappableChar 字段,您应用此
属性直接指向 Visual Basic 方法定义

这告诉您 Declare 选项是 VB.net 语法糖,它在编译时转换为 DllImportAttribute,并概述了使用 DllImportAttribute 时的确切场景> 直接推荐。

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

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.

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 :

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
.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文