Вопрос

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

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

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

Это было полезно?

Решение

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

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

В общем, я бы использовал DllImport вместо Declare, если только вы не исходите из 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

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

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

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

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

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

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

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

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

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

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

и

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

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

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

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

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

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

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

Чтобы применить лучшее сопоставление, вызовите условное обозначение, точное написание, PreserveSig, функции setlasterror или throwonunmappablechar задано значение поля в Визуальный основной декларации Майкрософт 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 рекомендуется использовать напрямую.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top