netlib.narod.ru | < Назад | Оглавление | Далее > |
Но что делать, если позарез нужна функция API Win32, которой в .NET Framework просто нет?
В таком случае можно прибегнуть к службам PInvoke (Platform Invocation Services). PInvoke — это общий механизм вызова функций, экспортируемых из DLL. Функция ScrollWindow находится в динамически подключаемой библиотеке User32.dll, поэтому ее можно точно квалифицировать. Но у этого подхода есть минус: после того как программист воспользовался им, его код перестает быть управляемым и уж подавно независимым от платформы.
В документации по API Win32 приводится такой синтаксис ScrollWindow:
BOOL ScrollWindow(HWND hWnd, int XAmount, int YAmount, CONST RECT *lpRect, CONST RECT *lpClipRect);
В заголовочных файлах С для Windows BOOL определяется просто как int, a HWND (дескриптор окна) — как указатель на void, но реально это просто 32-разрядное значение.
Но откуда взять дескриптор окна в Windows Forms? У класса Control есть свойство Handle, описанное в документации как дескриптор HWND для экземпляра этого класса. Тип свойства Handle — определяемая в пространстве имен System структура IntPtr — свидетельствует, что это указатель. Типы данных int и IntPtr могут быть легко преобразованы друг в друга. Пока мы не встретили никаких трудностей при переходе от типов данных С# к аргументам функции ScrollWindow и возвращаемым ей значениям.
Трудности связаны с двумя последними аргументами ScrollWindow — указателями на структуру Windows RECT, определяемую в заголовочном файле Windows так:
typedef struct tagRECT { LONG left; LONG top; LONG right; LONG bottom; } RECT;
Тип данных LONG определяется в заголовочном файле Windows как long, но это не 64-разрядный long из С#, а всего лишь 32-разрядный long из С, поэтому он совместим с типом данных int из С#.
Чтобы вызвать ScrollWindow из программы С#, надо определить структуру, набор и порядок полей которой соответствуют таковым структуры Windows RECT, и предварить ее атрибутом:
[StructLayout(LayoutKind.Sequential)]
Structlayout — это атрибут С#, основанный на классе StructLayoutAttribute, определенном в пространстве имен System.Runtime.InteropServices. Кроме того, нужно объявить ScrollWindow как внешнюю функцию extern, предварив ее атрибутом:
[DllImport("user32.dll")]
Возможно, вы заметили, что класс KeyExamine содержит метод ScrollLines, отвечающий за прокрутку содержимого клиентской области. Метод ScrollLines в KeyExamine просто делает недействительной часть клиентской области ниже заголовков столбцов. В классе KeyExamineWithScroll, порожденном от KeyExamine, определена структура RECT, объявлена функция ScrollWindow и переопределен метод ScrollLines в KeyExamine. Модифицированная версия ScrollLines вызывает функцию Windows ScrollWindow.
KeyExamineWithScroll.cs
//----------------------------------------------------- // KeyExamineWithScroll.cs (C) 2001 by Charles Petzold //----------------------------------------------------- using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; class KeyExamineWithScroll: KeyExamine { public new static void Main() { Application.Run(new KeyExamineWithScroll()); } public KeyExamineWithScroll() { Text += " With Scroll"; } // Объявление структуры прямоугольника в стиле Win32 [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left; public int top; public int right; public int bottom; } // Объявление вызова ScrollWindow [DllImport("user32.dll")] public static extern int ScrollWindow(IntPtr hwnd, int cx, int cy, ref RECT rectScroll, ref RECT rectClip); // Переопределение методов в KeyExamine protected override void ScrollLines() { RECT rect; rect.left = 0; rect.top = Font.Height; rect.right = ClientSize.Width; rect.bottom = ClientSize.Height; ScrollWindow(Handle, 0, -Font.Height, ref rect, ref rect); } }
Эта версия намного лучше: программа работает более гладко и эффективно, когда ей не приходится перерисовывать все выводимые строки.
netlib.narod.ru | < Назад | Оглавление | Далее > |