Поиск

Объявление экспортированной функции DLL

Во-первых, мы рассмотрим объявление на С# простой функции из DLL. Мы используем пример, который для .NET PInvoke быстро становится каноническим, — Win32 "MessageBox". Затем мы перейдем к более сложным вопросам, связанным с преобразованием параметров.
Как вы узнали из главы 8, атрибуты служат для предоставления информации периода разработки о типе С#. В период же выполнения эту информацию позволяет получить отражение. В С# атрибут Dlllmport позволяет указать компилятору функцию DLL, которую будет вызывать приложение:

[ОШтроЛ(имя_с/1[)]
модификатор ^доступа static extern
возвр_знанение функциями (парам!, парам2,...);

Как видите, чтобы импортировать функцию из DLL, нужно лишь прикрепить атрибут Dlllmport (передавая его конструктору имя DLL) к функции DLL, которую вы хотите вызвать. Заметьте: для определяемой вами функции нужно применять модификаторы static и extern. Вот пример MessageBox — он показывает, как легко использовать PInvoke: using System; using System.Runtime.InteropServices;

class PInvokelApp {
[Dlllmport("user32.dll")] static extern int MessageBoxA(int hWnd,
string msg, string caption, int type);
public static void MainQ
{
MessageBoxA(0,
"Hello, World!",
"This is called from a C# app!", 0); } }

В результате запуска этого приложения, как и ожидалось, будет показано окно с сообщением "Hello, World!".
Оператор using указывает пространство имен System.Runtime.InteropServices, которое определяет атрибут Dlllmport. Затем я определил метод MessageBoxA, вызываемый в Main. Но если вы хотите назвать свой внутренний метод на С# не так, как называется функция DLL? Это позволяет сделать один из именованных параметров атрибута Dlllmport.

В приведенной ниже программе происходит следующее. Я сообщаю компилятору, что хочу назвать свой метод MessageBoxA. Поскольку в атрибуте Dlllmport я не указал имя функции DLL, компилятор предполагает, что оба имени одинаковы.

[Dlllmport("user32.dll")]
static extern int MessageBoxA(int hWnd,
string msg, string caption, int type);

Чтобы понять, как изменить этот стандартный алгоритм, рассмотрим пример. На этот раз используется внутреннее имя MsgBox, но все равно вызывается функция DLL MessageBoxA.

using System;
using System.Runtime.InteropServices;
class PInvoke2App {
[Dlllmport("user32.dll",
EntryPoint="MessageBoxA")] static extern int MsgBox(int hWnd,
string msg,
string caption,
int type);
public static void Main() {
MsgBox(0,
"Hello, World!",
"This is called from a C# app!", 0); > }

Как видите, чтобы получить возможность называть внутренний эквивалент внешней функции DLL, как мне вздумается, я должен лишь задать именованный параметр Entry Point атрибута Dlllmport.

Последнее, что мы рассмотрим, прежде чем перейти к преобразованию параметров, — параметр CharSet. Он позволяет задавать набор символов, используемый файлом DLL. Обычно при написании С++-при-ложений вы не задаете явно использование MessageBoxA или Message-BoxW — благодаря pragma, компилятор уже знает, какой набор символов вы применяете — ANSI или Unicode. Поэтому при вызове MessageBox на C++ компилятор определяет, какой набор символов использовать. Сходным образом на С# вы можете задать целевой набор символов для атрибута Dlllmport, который будет указывать, какую версию MessageBox вызвать. В следующем примере все равно будет вызвана функция MessageBoxA, так как Dlllmport через его именованный параметр CharSet передается соответствующее значение.

using System;
using System.Runtime.InteropServices;
class PInvokeSApp {
// При задании CharSet.Ansi будет вызвана MessageBoxA.
// При задании CharSet.Unicode будет вызвана HessageBoxW.
[Dlllmport("user32.dll", CharSet=CharSet.Ansi)] static extern
int MessageBox(int hWnd,
string msg, string caption, int type);
public static void MainQ {
MessageBox(0,
"Hello, World!",
"This is called from a C# app!", 0); } }

Преимущество параметра CharSet в том, что я могу установить в приложении переменную, которая будет контролировать вызов той или иной версии функций (ANSI или Unicode). Мне не придется менять весь код при переходе от одной версии к другой.