Видимо, операторы 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), иначе вы можете получить неожиданные результаты.