Лабы по драйверам / lr2
.docЛабораторная работа №2
Создание диалоговой прикладной программы для управления драйверами.
Интерфейс:
Программа должна предоставлять диалоговое окно с четырьмя полями ввода и 7 кнопками
Приблизительно окно должно выглядеть так:
Назначение полей ввода
-
Задание имени сервиса ServiceName (с этим именем в реестре будет создан ключ HKEY_LOCAL_MASHINE\System\CurrentControlSet\Services\ServiceName, описывающий местоположение драйвера, способ его загрузки и т.п.)
-
Задание имени символической ссылки на имя устройства. В это поле должно быть введено имя, определенное загружаемым нами драйвером при создании устройства
-
Задание полного пути к sys-файлу с драйвером. Это имя будет помещено в реестр как значение ключа HKEY_LOCAL_MASHINE\System\CurrentControlSet\Services\ServiceName\ImagePath
-
Поле для вывода журнала работы программы (отображение результатов работы функций программы, коды и описания ошибок)
Назначение кнопок:
-
Вывод окна запроса пути к sys-файлу
-
Добавление драйвера в систему
-
Удаление драйвера из системы
-
Запуск драйвера
-
Остановка драйвера
-
Открытие устройства
-
Закрытие устройства
Создание проекта:
-
Запустить Visual C++
-
Выбрать пункт меню File\New…
-
В появившемся окне выбрать тип проекта – “MFC AppWizard (exe)”, в поле Location задать путь к своей рабочей директории, в поле Project Name – имя проекта (instdrv). Нажать Ok
-
В появившемся окне мастера создания приложений MFC выбрать тип приложения “Dialog Based”. Жать кнопку Next, пока она доступна. После этого – Finish. Будет создан проект на базе диалогового окна.
-
Ресурс с диалоговым окном находится в диспетчере проектов в закладке ResourceView в пункте Dialog\IDD_INSTDRV_DIALOG (второе диалоговое окно, IDD_ABOUTBOX, мы использовать не будем). В закладке ClassView находится список классов C++ нашего приложения – по одному классу на каждое диалоговое окно и класс для всего приложения. В закладке FileView находится список всех файлов проекта. Оба класса блоков диалога помещены в один cpp-файл, класс приложения – в другой cpp-файл. Каждый cpp-файл имеет одноименный ему h-файл.
-
Вставить в блок диалога все элементы управления. Для этого перейти к закладке ResourceView, выбрать нужный блок диалога. Появится окно редактирования ресурса и панель с элементами управления (Controls). В этой панели выбрать поля ввода (Edit Box) и кнопки (Button). Для вставки пояснений к полям ввода добавить элементы управления Static Text.
-
Для изменения заголовков элементов управления щелкнуть на элементе управления в диалоговом окне правой кнопкой мыши, в появившемся меню – пункт Properties. В появившемся окне поменять поле Caption (надпись на элементе управления) и поле ID (идентификатор ресурса). В качестве идентификаторов ресурсов выбирать осмысленные имена, типа IDADD для кнопок или IDC_PATH для полей ввода.
-
Отдельное внимание уделить полю ввода для вывода журнала работы программы. В его свойствах перейти в закладку Styles, выбрать пункт Multiline, все пункты во втором столбике (Horizontal Scroll и т.д.), и пункт WantReturn в третьем столбике свойств.
-
Создать в классе диалогового окна поля-члены класса, соответствующие всем полям ввода текста в блоке диалога. Для этого в блоке диалога щелкнуть правой кнопкой мыши на нужном поле ввода, в появившемся меню выбрать ClassWizard. В появившемся окне перейти в закладку Member Variables, выбрать кнопку Add Variable… В появившемся окне в поле Category задать Control, в поле Variable Type – Cedit, в поле Member Variable Name задать имя переменной, например m_edtPath (префикс m_ означает, что это член класса, edt указывает на то, что переменная имеет тип CEdit).
-
В интегрированной подсказке изучить класс MFC CEdit. Нас будут интересовать функции-члены класса GetWindowText(), SetWindowText(),ReplaceSel().
-
Нас также будет интересовать класс CString, который можно использовать везде, где требуются нуль-терминированные строки.
-
Исследовать класс CFileDialog, предоставляющий блок диалогового окна открытия файла. Нас будет интересовать его конструктор, функция-член DoModal() и ее возвращаемое значение и функция-член GetPathName().
-
Создать функции – обработчики событий нажатия на кнопки. Для этого вызвать ClassWizard, в закладке MessageMaps выбрать идентификатор ресурса нужной кнопки, в списке Messages выбрать BN_CLICKED и нажать кнопку AddFunction. После запроса имени функции обработчик будет добавлен и в него можно будет перейти или из окна ClassWizard нажатием на кнопку EditCode, или из закладки ClassView диспетчера проектов выбором соответствующей функции-члене в классе CInstdrvDlg.
-
Создать новый класс CScMgr, который будет заниматься работой с ServiceControlManager’ом посредством вызова функций Win32 OpenSCManager(), CreateService(), CloseServiceHandle(), OpenService(),DeleteService(), StartService(),ControlService() и использовать функции CreateFile() и CloseHandle() для открытия и закрытия устройства. Изучить эти функции в помощи. Пример использования этих функций можно посмотреть на E:\DDK\Src\General\InstDrv\exe\instdrv.c. Для создания класса перейти в закладку ClassView диспетчера проектов, выбрать верхнюю строку (Instdrv classes), щелкнуть на ней правой кнопкой мыши, в появившемся меню выбрать “New Class”. В качестве типа класса указать “Generic Class”.
-
Конструктор класса должен инициализировать переменную-член класса, представляющую описатель ServiceControlManager’а, с помощью функции OpenSCManager(). Деструктор класса должен освобождать описатель с помощью вызова CloseServiceHandle(). Должны быть реализованы функции-члены класса, реализующие установку, удаление, запуск и остановку драйвера, открытие и закрытие устройства. В случае возникновения ошибок информация о них должна быть выведена в поле журнала работы программы. Для этого обратить внимание на функции GetLastError() и FormatMessage().
-
Функции – обработчики событий нажатия на кнопки должны содержать вызов соответствующих функций класса CScMgr. Экземпляр класса создается и уничтожается внутри функции-обработчике события.
Далее приводится пример реализации функции вывода сообщения в формате функции vprintf() в поле ввода с именем m_edtDump, и функции получения и вывода сообщения об ошибке в то же поле.
void CInstdrvDlg::vspf(char *fmt, va_list argptr)
{
memset(tmpbuf, 0, sizeof(tmpbuf));
vsprintf(tmpbuf, fmt, argptr);
strcat(tmpbuf, "\r\n");
m_edtDump.ReplaceSel(tmpbuf);
}
void CInstdrvDlg::PrintLastError(char *fmt, va_list argptr)
{
LPVOID lpMsgBuf;
int cnt;
memset(tmpbuf, 0, sizeof(tmpbuf));
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
cnt = vsprintf(tmpbuf, fmt, argptr);
strcat(tmpbuf, (char*)lpMsgBuf);
strcat(tmpbuf, "\r\n");
m_edtDump.ReplaceSel(tmpbuf);
// Free the buffer.
LocalFree( lpMsgBuf );
}
В классе работы с ServiceControlManager’ом должны быть соответствующие функции vspf и PrintLastError, принимающие переменное число параметров
в формате функции printf, например:
int CScMgr::vspf(char *fmt, ...)
{
va_list argptr;
va_start(argptr, fmt);
((CInstdrvDlg*)(theApp.m_pMainWnd))->vspf(fmt, argptr);
va_end(argptr);
}
Смысл этой функции в том, чтобы из функции-члена одного класса (CScMgr) вызвать функцию-член другого класса (CInstdrvDlg). Сделать это можно через переменную – указатель на экземпляр класса CInstdrvDlg. Проблема в том, что эта переменная в свою очередь является членом третьего класса – CInstdrvApp, и вдобавок имеет тип указателя на базовый для CInstdrvDlg класс – CDialog. Переменная – указатель на экземпляр класса CInstdrvApp является глобальной переменной.
Упрощенная схема этих классов выглядит следующим образом:
class CInstdrvApp
{
…
CDialog *m_pMainWnd; //инициализация этой переменной происходит
//в функции CInstdrvApp::InitInstance()
…
};
CInstdrvApp theApp; //глобальная переменная
class CInstdrvDlg: public CDialog
{
...
void vspf(char *fmt, va_list argptr);
void PrintLastError(char *fmt, va_list argptr);
...
//переменные, соответствующие полям редактирования (CEdit)
...
//функции-обработчики событий нажатия на кнопки
...
};
class CScMgr
{
...
void vspf(char *fmt, ...);
void PrintLastError(char *fmt, ...);
...
//функции установки, удаления, запуска и остановки драйвера
//и открытия устройства
...
};