netlib.narod.ru< Назад | Оглавление | Далее >

Вызов API Win32

Но что делать, если позарез нужна функция 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< Назад | Оглавление | Далее >

Сайт управляется системой uCoz