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

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

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

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

Ответы

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

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.

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

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

Таким образом, мой вывод:

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

и

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

Ответ 3

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

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

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

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

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

Ответ 4

Если вам нужно установить один из следующих параметров, используйте атрибут 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.