| 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 | < Назад | Оглавление | Далее > |