DllImport vs объявить в VB.NET - PullRequest
       11

DllImport vs объявить в VB.NET

14 голосов
/ 02 июня 2009

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

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

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

Ответы [ 4 ]

18 голосов
/ 09 января 2012

Видимо, операторы 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) в качестве значения по умолчанию. Тем не менее, в этом случае, поскольку был указан CharSet из Unicode, CLR ПЕРВЫЙ будет искать функцию с именем «MessageBoxW» - «W», указывающий тип возврата Unicode. (Версией возвращаемого типа ANSI будет «MessageBoxA».) Если «MessageBoxW» не найден, ТОГДА CLR будет искать функцию API, фактически называемую «MessageBox».

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

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

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

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

На этой странице также есть важное примечание:

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

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

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

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

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

Очевидно, что если вы хотите настроить вызов 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.

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

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

Поэтому мой вывод таков:

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

и

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

10 голосов
/ 02 июня 2009

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

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

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

6 голосов
/ 21 июня 2010

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

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

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

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

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

1 голос
/ 10 февраля 2015

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

Чтобы применить BestFitMapping, CallingConvention, ExactSpelling, Поля PreserveSig, 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 в .NET 4.5:

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

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

...