DllImport против Declare in VB.NET

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

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

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

4 ответов


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

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

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


по-видимому, операторы 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, среда CLR сначала будет искать функцию под названием "MessageBoxW" - "W", указывающую тип возврата Unicode. (Версия возвращаемого типа ANSI будет "MessageBoxA".) Если " MessageBoxW "не найден, CLR будет искать функцию API, фактически называемую"MessageBox".

текущие сведения о классе DllImportAttribute можно найти здесь, где я просматривал версию .NET Framework 4:Dllimportattribute Class

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

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

Итак, по крайней мере, что касается VB.NET, компилятор заканчивается на Declare в любом случае заявление.

на этой странице также есть важная заметка:

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

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

затем я направился к информации заявления объявления. Версия Visual Studio 2010 (Visual Basic statement info) была здесь:Объявить Заявление

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

вы можете использовать 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 vs ANSI, согласно этой странице объявления, Если вы укажете значение кодировки (доступное в объявлении, но не показанное в примере выше), среда CLR выполнит тот же тип автоматического поиска имен, что и DllImport - для Unicode или ANSI.

если значение кодировки не указано в Declare заявление, затем вы должны убедиться, что имя вашей функции в объявлении совпадает с именем функции в заголовочном файле фактической функции API, или вы должны указать Alias значение, соответствующее фактическому имени функции в заголовочном файле (как показано в примере выше).

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

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

и

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


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

также, Когда вы используете Declare, вам не нужно писать End Function. Преимущество этого заключается в том, что вы можете создать целый модуль объявлений импорта функций строка за строкой, без необходимости вытягивать свой код с помощью DllImports и End Functions.

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

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

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


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

применить BestFitMapping, CallingConvention, ExactSpelling, Поля PreserveSig, SetLastError или ThrowOnUnmappableChar для Visual основные декларации Майкрософт 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 класс в .NET 4.5:

компилятор Visual Basic выдает этот атрибут при использовании инструкция DECLARE. для комплекс определений метода BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError или throwonunmappablechar поля, вы применяете это атрибут непосредственно к определениям методов Visual Basic.

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