2009-06-01 7 views
13

В документации MSDN есть уведомление, что есть multiple ways, чтобы объявить ссылку на функцию во внешней DLL из программы VB.NET.DllImport vs Declare in VB.NET

Запутанное Дело в том, что MSDN утверждает, что вы можете использовать только DllImportAttribute класса с общими функциональными прототипами «in rare cases», но я не мог найти объяснение этого утверждения, в то время как вы можете просто использовать Declare ключевое слово вместо этого.

Почему эти разные, и где бы я надлежащим образом использовал каждый случай?

ответ

9

Объявление действительно является попыткой поддерживать синтаксис P/Invoke, который будет более знаком с пользователями Visual Basic 6.0, которые преобразуются в VB.NET. Он имеет многие из тех же функций, что и P/Invoke, но сортировка определенных типов, в частности строк, очень различна и может вызвать некоторую путаницу для людей, более знакомых с правилами DllImport.

Я не совсем уверен, что документация ссылается на «редкое» различие. Я часто использую DllImport в своем коде из VB.NET и C# без проблем.

В общем, я бы использовал DllImport над Declare, если вы не используете фон Visual Basic 6.0. Документация и образцы для DllImport намного лучше, и есть много инструментов, предназначенных для создания объявлений DllImport.

6

На мой взгляд, поскольку это ключевое слово не выглядит измененным и т. Д. Из того, что я искал, просто используйте ключевые слова компиляции, а не атрибуты.

Также, если вы используете Declare, вам не нужно писать End Function. Преимущество состоит в том, что вы можете создать цельный модуль деклараций импорта функций по строкам, без необходимости генерировать ваш код с DllImport s и End Function s.

Когда вы заявляете, используя ключевое слово Declare, компилятор рассматривает эту функцию как Shared в любом случае, поэтому к ней можно получить доступ через другие объекты extenal.

Но я думаю, что в текущем VB.NET оба они адресованы одной и той же цели и не имеют разницы в производительности - никаких гарантий на этот счет.

Так что мой вывод: Есть ли использовать Declare вместо DllImport, особенно читая то, что вы процитировали, что Microsoft stated, что его следует использовать в редких случаях.

16

Очевидно, заявления Declare и DllImport в основном одинаковы. Вы можете использовать то, что вы предпочитаете.

Ниже приводится обсуждение нескольких пунктов, которые могут работать немного по-разному в каждом, которые могут влиять на предпочтение одного над другим:

Я начал со статьи из MSDN относительно Visual Studio 2003 под названием Using the DllImport Attribute. (Немного устарел, но поскольку оператор 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, в данном случае) по умолчанию , Однако в этом случае, поскольку был указан CharSet из Unicode, CLR бы FIRST искал функцию под названием «MessageBoxW» - «W», указывающую тип возврата Unicode. (Версия типа ANSI возвращаемого типа будет «MessageBoxA».) Если «MessageBoxW» не было найдено, THEN CLR будет искать функцию API, фактически называемую «MessageBox».

Современные особенности о классе DllImportAttribute можно найти здесь, где я рассматривал .NET Framework 4 версии: DLLImportAttribute Class

Ключевой комментарий в разделе Замечаний этой страницы 4 .NET Framework является то, что:

Вы применяете этот атрибут непосредственно к определениям методов C# и C++; однако компилятор Visual Basic испускает этот атрибут, когда вы используете оператор Declare.

Таким образом, по крайней мере, так же,

Существует также важное примечание на этой странице:

DllImportAttribute не поддерживает маршалинг родовых типов.

Таким образом, если вы хотите использовать общий тип, вам нужно будет использовать оператор Declare.

Далее я направился к информации заявления Declare. Визуальное версия Studio 2010 (Visual Basic Информация заявление) здесь: Declare Statement

Ключевой пункт здесь был это примечание:

Вы можете использовать Объявите только на уровне модуля. Это означает, что контекст объявления для внешней ссылки должен быть классом, структурой или модулем и не может быть исходным файлом, пространством имен, интерфейсом, процедурой или блоком.

Очевидно, что если вы хотите, чтобы настроить вызов 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 заявления, то вы должны убедиться, что ваше имя функции в Declare таким же, как имя функции в файле заголовок фактической функции API, либо вы должны specifiy в Alias значение, соответствующее фактическому имени функции в файле заголовка (как показано в примере выше).

Я не смог найти какую-либо конкретную документацию Microsoft, в которой указывалось, что либо DllImport, либо Declare были предпочтительны или даже рекомендованы друг другу в любой ситуации, отличной от отмеченной выше.

Мой вывод, таким образом, является:

1) Если вам не нужно поместить определение в одном из мест не может быть использована Declare заявление, либо метод будет работать нормально,

и

2) если вы используете DllImport, убедитесь, что вы указали требуемое значение CharSet (Unicode или ANSI), или вы можете получить неожиданные результаты.

+3

Это отличная запись и отличные исследования. Большое спасибо! – Mike

1

Если вам нужно установить один из следующих параметров, используйте атрибут DllImportAttribute, иначе используйте Declare. От https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx

Чтобы применить BestFitMapping, CallingConvention, ExactSpelling, поля PreserveSig, SetLastError или ThrowOnUnmappableChar в Microsoft Visual Basic декларации в 2005 году, вы должны использовать атрибут вместо инструкции Объявите DllImportAttribute.

Из приведенной выше ссылки неясно, применяется ли это только к «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:

Visual Basic компилятор испускающий этот атрибут при использовании оператора Declare. Для сложных определений методов, которые включают BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError или поля ThrowOnUnmappableChar, применить этот атрибут непосредственно к основным определениям Визуальный метод.

Это говорит о том, что вариант Declare является VB.net синтаксический сахар, который превращается в DllImportAttribute во время компиляции, и определяет точные сценарии при использовании DllImportAttribute непосредственно рекомендуется.