Не только функции DLL могут быть вызваны приложениями на С#, но и сами функции DLL могут также вызывать определенные методы С# из вашего приложения в сценариях с обратными вызовами. Сценарии обратного вызова включают в себя использование любой из функций Win32
ЕпитХХХ.
При вызове этой функции для перечисления элементов ей передается указатель на функцию, которая будет активизироваться Windows каждый раз, когда искомый элемент будет найден. Это делается комбинированием
PInvoke
(для вызова функции DLL) и делегатов (для определения обратного вызова). О делегатах см. главу 14.
Этот код выполняет перечисление и вывод заголовков всех окон в системе:
using System;
using System.Runtime.InteropServices;
using System.Text;
class CallbackApp {
[Dlllmport("user32.dll")]
static extern int GetWindowText(int hWnd, StringBuilder text, int
count);
delegate bool CallbackDef(int hWnd, int IParam);
[Dlllmport("user32.dll")]
static extern int EnumWindows (CallbackDef callback, int IParam);
static bool PrintWindow(int hWnd, int IParam)
{
StringBuilder text = new StringBuilder(255); GetWindowText(hWnd, text, 255);
"
Console.WriteLine("Window caption: {0}", text);
return true; }
static void Main() {
CallbackDef callback = new CallbackDef(PrintWindow);
EnumWindows(callback, 0); } }
Сначала я определяю \Мп32-функции
EnumWindows
и
GetWindowText
с помощью атрибута
Dlllmport.
Затем я определяю делегат
CallbackDef
'и метод
PrintWindows.
После этого мне остается только в методе
Main
создать экземпляр делегата
CallbackDef
(передавая ему метод
PrintWindows)
и вызвать метод
Епит Windows.
Для каждого окна, найденного в системе, Windows вызовет метод
PrintWindows.
Метод
PrintWindows
интересен, так как использует класс
StringBuilder
для создания строки фиксированной длины, которую он передает функции
GetWindowText.
Поэтому функция
GetWindowText
определяется так:
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
Причина в том, что функции DLL не разрешается изменять строку, так что вы не можете использовать этот тип. И если даже попытаться осуществить передачу по ссылке, вызывающий код не может инициализировать строку с правильным размером. Тут в дело вступает класс
String-Builder.
Коль скоро длина текста не превышает максимального значения, переданного конструктору
StringBuilder,
объект
StringBuilder
может быть разыменован и модифицирован вызванной функцией.