Виртуальный драйвер для обслуживания аппаратных прерываний
Страница 5. Упрощение программы


 

Упрощение программы

Заметного упрощения программы можно добиться, организовав посылку в приложение сообщения WM_USER непосредственно из обработчика прерываний драйвера, точнее с уровня отложенных прерываний. В этом случае отпадает необходимость в передаче драйверу каких-либо данных, кроме дескриптора того окна приложения, в которое посылается сообщение WM_USER, в данном случае - дескриптора главного окна. Сокращается и текст процедуры отложенных прерываний Reflect_Int. Приложение Windows также упрощается: отпадает необходимость в разделении функций обработки прерываний между функцией Isr(), работающей, по существу, на уровне отложенных прерываний, и функцией OnUser(), выполняемой уже на обычном уровне задачи. Поскольку результат измерений легко передать из драйвера в приложение в качестве параметра сообщения WM_USER, исчезает необходимость в пункте <Чтение> в меню приложения.

Рассмотрим изменения, вносимые при использовании такого метода.

Приложение Windows, обрабатывающее аппаратные прерывания

//Операторы препроцессора #define и #include  
... 
#define HANDLE_WM_USER(hwnd, wParam, lParam, fn) \//Макрос для обработки  
        ((fn)(hwnd,wParam), 0L) // сообщения WM_USER 
//Прототипы функций 
... 
void OnUser(HWND,WPARAM);     //Сигнатура функции изменилась 
//Глобальные переменные 
HWND hMainWnd;      //Дескриптор главного окна 
... 
//Главная функция WinMain 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int){ 
... 
  while(GetMessage(&msg,NULL,0,0))//Обычный цикл 
    DispatchMessage(&msg);//обработки сообщений 
  return 0; 
  }//Конец WinMain 
//Функция Register регистрации класса окна 
... 
//Функция Create создания и показа окна 
void Create(HINSTANCE hInst){ 
  hMainWnd=CreateWindow(szClassName,szTitle,WS_OVERLAPPEDWINDOW, 
     10,10,200,100,HWND_DESKTOP,NULL,hInst,NULL); 
  ShowWindow(hMainWnd,SW_SHOWNORMAL); 
  } 
//Оконная функция WndProc главного окна 
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){ 
  switch(msg){ 
    HANDLE_MSG(hwnd,WM_COMMAND,OnCommand); 
    HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy); 
    HANDLE_MSG(hwnd,WM_USER,OnUser); 
    default: 
      return(DefWindowProc(hwnd,msg,wParam,lParam)); 
    } 
  } 
//Функция OnCommand обработки сообщений WM_COMMAND от команд меню 
void OnCommand(HWND hwnd,int id,HWND,UINT){ 
  switch(id){ 
    case MI_START://Инициализация платы 
      InitCard(); 
      break; 
    case MI_EXIT://Завершить приложение 
      DestroyWindow(hwnd); 
    } 
  } 
//Функция OnUser обработки сообщения WM_USER 
void OnUser(HWND,WPARAM wParam){ 
  char txt [80]; 
  wsprintf(txt,"Измерения окончены\nНакоплено %d событий",(UINT)wParam); 
  MessageBox(hMainWnd,txt,"Контроль",MB_ICONINFORMATION);  
  } 
//Функция OnDestroy обработки сообщения WM_DESTROY 
... 
//Функция InitCard инициализации (через драйвер) платы 
void InitCard (){ 
  GetAPIEntry();     //Получение адреса точки входа в драйвер 
  _BX=55;      //Канал 0 
  _CX=20000;         //Канал 1; BX*CX=Длительность интервала 
  _DX=1000;      //Канал 2, внутренний генератор 
  _DI=(UINT)hMainWnd;     //Дескриптор главного окна 
  VxDEntry();        //Вызов драйвера 
  } 
//Функция GetAPIEntry получения адреса точки входа в драйвер 
void GetAPIEntry() 
...

В приведенном выше тексте файла .CPP детально показаны только измененные участки программы.

Изменилось определение макроса HANDLE_WM_USER для обработки сообщения WM_USER, которое мы пошлем в приложение из драйвера: функция обработки этого сообщения fn (в приложении она носит название OnUser()) принимает два параметра - hwnd и wParam. Через параметр сообщения wParam в приложение будет передан результат измерений. При необходимости передавать в приложение больший объем данных можно было расширить состав параметров функции третьим параметром lParam.

Цикл обработки сообщений существенно упростился и принял форму, обычную для простых приложений Windows.

В функции OnCommand() удален фрагмент, связанный с пунктом меню <Чтение> (идентификатор MI_READ), поскольку в этом пункте уже нет необходимости.

В функции OnUser() параметр wParam приводится к типу целого без знака, преобразуется в символьную форму и выводится на экран в окно сообщения с соответствующим текстом.

Как будет видно из программы драйвера (и как, впрочем, должно быть очевидно для читателя), при посылке из драйвера сообщения WM_USER необходимо указать системе, какому окну адресовано это сообщение. Однако драйверу, естественно, ничего не известно об окнах приложений; дескриптор нашего главного окна следует передать драйверу на этапе инициализации платы. Эта операция выполняется в функции InitCard(), где перед вызовом драйвера в регистры BX, CX и DX засылаются константы настройки таймера, а регистр DI является приведенным к целому типу дескриптором главного окна hMainWnd.

 
« Предыдущая статья   Следующая статья »