Модификация приложения для тестирования драйвера
Тестирующее консольное приложение не так сильно изменилось, за исключением переписывания кода на использование вызовов DeviceIoControl
и организации ожидания вызовом WaitForSingleObject.
//======================================================================= // Файл тестовой программы test.cpp //=======================================================================
#include <windows.h> #include <stdio.h> #include "winioctl.h"
#define IOCTL_SEND_TO_PORT CTL_CODE( \ FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_SEND_TO_USER CTL_CODE( \ FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_TAKE_EVENT CTL_CODE( \ FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_CLOSE_EVENT CTL_CODE( \ FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) int ReadWrite(HANDLE devHandle); #define BUFFSIZE (17) static unsigned char outBuffer[BUFFSIZE], inBuffer[BUFFSIZE*2]; static HANDLE devHandle, hEvent;
int __cdecl main() { printf("\n\n\n\n\nParallel Port CheckIt Loopback Device Test Program.\n" ); devHandle = CreateFile( "\\\\.\\LPTPORT0", GENERIC_READ | GENERIC_WRITE, 0, // share mode none NULL, // no security OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); // no template
if ( devHandle == INVALID_HANDLE_VALUE ) { printf("Error: can not open device PLPTPORT0. Win32 errno %d\n", GetLastError() ); return -1; } printf("Congratulation. LPTPORT0 device is open.\n\n"); //========================================== // Получение доступа к объекту события, // создаваемому в драйвере DWORD bytesRead; if ( !DeviceIoControl(devHandle, IOCTL_TAKE_EVENT, NULL, 0, // отправляем в драйвер &hEvent, sizeof(HANDLE), // получаем из драйвера &bytesRead, NULL ) ) { printf("Error during IOCTL_TAKE_EVENT: errno %d.\n", GetLastError() ); CloseHandle(devHandle); return -1; } printf("\nEvent handle = %04X(hex)\n", hEvent); //========================================== // Заполнение буфера данными: DWORD i=3,j=0; for ( ; j<sizeof(outBuffer); ) outBuffer[j++] = (unsigned char)i++; //========================================== ReadWrite(devHandle); //========================================== // Завершение работы if ( !DeviceIoControl(devHandle, IOCTL_CLOSE_EVENT, NULL, 0, // отправляем в драйвер NULL, 0, // получаем из драйвера &bytesRead, NULL ) ) { printf("\nError during IOCTL_CLOSE_EVENT: errno %d.\n", GetLastError() ); } else printf("\nEvent handle is normally closed.\n");
if ( ! CloseHandle(devHandle) ) { printf("\ n Error during CloseHandle: errno %d.\n", GetLastError() ); return -1; } printf("\n\n\n Device LPTPORT0 successfully closed. Normal exit.\n"); return 0; } //========================================================================== // передача и получение данных из CheckIt заглушки: int ReadWrite(HANDLE devHandle) { //========================================== // Передача данных драйверу printf("Writing to LPTPORT0 device...\n");
DWORD bytesReturned, outCount = sizeof(outBuffer); if ( !DeviceIoControl(devHandle, IOCTL_SEND_TO_PORT, outBuffer, outCount, // отправляем в драйвер NULL, 0, // получаем из драйвера &bytesReturned, NULL ) ) { printf("Error during IOCTL_SEND_TO_PORT: errno %d.\n", GetLastError() ); return 11; } printf( "Successfully transferred %d bytes.\n" "Buffer content was: \n", outCount); for (DWORD i=0; i<outCount; i++ ) printf("%02X ",outBuffer[i]); //========================================== // Использование созданного события DWORD result = WaitForSingleObject(hEvent,10);
switch(result) { case WAIT_TIMEOUT: printf("\nWait timeout.\n");break; case WAIT_ABANDONED: printf("\nWait WAIT_ABANDONED.\n"); break; default: printf("\nWait default case.\n"); } //========================================== // Получение данных из драйвера printf("\n\nReading from device LPTPORT0...\n"); DWORD bytesRead, inCount = sizeof(inBuffer); if ( !DeviceIoControl(devHandle, IOCTL_SEND_TO_USER, NULL, 0, // отправляем в драйвер inBuffer, inCount, // получаем из драйвера &bytesRead, NULL ) ) { printf("Error during OCTL_SEND_TO_USER: errno %d.\n", GetLastError() ); return 12; } if ( bytesRead != outCount ) { // размер записанных и прочитанных данных не совпадает printf("Error: is to read %d bytes,\n" "but IOCTL_SEND_TO_USER reported %d bytes.\n", outCount, inCount); return 13; } printf("Succesfully read %d bytes.\n Buffer content is: \n", bytesRead); for ( i=0; i<bytesRead; i++ ) printf( "%02X ", (UCHAR)inBuffer[i] );
return 0; // Нормальное завершение }
Как уже обсуждалось в этой главе, запуск процесса переноса данных в параллельный порт и через него в буфер для данных, передаваемых клиенту, производится генерацией одного лишь первого прерывания. Далее, при наличии заглушки CheckIt в порту, процесс "регенерируется" автоматически до окончания данных во входном буфере. При такой "цепной реакции" весь перенос может пройти на высоких уровнях IRQL, и тестирующее приложение даже не успеет получить управление и прибегнуть к услугам "ожидания по событию". В том случае, если запустить драйвер и тестовое приложение в отсутствие заглушки, то приложение остановится, ожидая окончания обработки запроса по записи данных в порт. В этот момент можно убедиться в создании объекта именованного события при помощи программы WinObj, рис. 11.5.
Рис. 11.5 Именованный объект события "LPTPORT_EVENT", созданный драйвером, в рабочем окне программы WinObj |
Parallel Port CheckIt Loopback Device Test Program. Congratulation. LPTPORT0 device is open.
Event handle = 07CC(hex) Writing to LPTPORT0 device...
Successfully transferred 17 bytes. Buffer content was: 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 Wait default case.
Reading from device LPTPORT0... Successfully read 17 bytes. Buffer content is: 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 02 03 Event handle is normally closed.
Device LPTPORT0 successfully closed. Normal exit.
Ниже приводится информация из отладочного вывода, перехваченного программой DebugView (log-файл этой программы). Средняя часть этого файла (сообщения с 35 по 137) опущена, как и в первом случае, поскольку в этих строках содержится однообразная и малоинтересная информация.
00000000 0.00000000 LPTPORT: in DriverEntry, RegistryPath is: 00000001 0.00000223 \REGISTRY\MACHINE\SYSTEM\ControlSet001\ Services\LPTPort. 00000002 0.00003101 LPTPORT: Interrupt 7 converted to kIrql = 8, kAffinity = 1, kVector = 191(hex) 00000003 0.00004023 LPTPORT: Interrupt successfully connected. 00000004 0.00006761 LPTPORT: Symbolic Link is created: \DosDevices\LPTPORT0. 00000005 3.62195949 LPTPORT: in DispatchCreate now 00000006 3.62206817 LPTPORT: We are now in DeviceControlRoutine, currentIrql=0 00000007 3.62210393 LPTPORT: DeviceControlRoutine: IOCTL_TAKE_EVENT, 00000008 3.62210616 event named \BaseNamedObjects\LPTPORT_EVENT successfully created. 00000009 3.62211231 LPTPORT: DeviceControlRoutine: IOCTL_TAKE_EVENT, 00000010 3.62211426 event handle = 07CC(hex) is sent to user. 00000011 3.62228496 LPTPORT: We are now in DeviceControlRoutine, currentIrql=0 00000012 3.62229082 LPTPORT: DeviceControlRoutine: IOCTL_SEND_TO_PORT, 00000013 3.62229250 xfer size is 17 Irp is pending. 00000014 3.62229864 LPTPORT: We are now in StartIo , currentIrql=2 00000015 3.62230256 LPTPORT: StartIo: IoRequestDpc will be called now. 00000016 3.62230982 LPTPORT: We are now in DpcForIsr, currentIrql=2 xferCount = 0 00000017 3.62231485 LPTPORT: currentByteNo = 0, byteToBeOutToPort=03(hex) 00000018 3.62231848 LPTPORT: DoNextTransfer: 00000019 3.62232323 LPTPORT: Sending 0x03 to port 378 00000020 3.62232826 LPTPORT: generating next interrupt... 00000021 3.62243972 LPTPORT: In Isr procedure, ISR_Irql=8 00000022 3.62244671 LPTPORT: We are now in DpcForIsr, currentIrql=2 xferCount = 0 00000023 3.62245341 LPTPORT: ReadDataSafely, currentIrql=8 ReadStatus = 1F ReadByte = 03 00000024 3.62245621 LPTPORT: 00000025 3.62246096 LPTPORT: currentByteNo = 1, byteToBeOutToPort=04(hex) 00000026 3.62246459 LPTPORT: DoNextTransfer: 00000027 3.62246906 LPTPORT: Sending 0x04 to port 378 00000028 3.62247409 LPTPORT: generating next interrupt... 00000029 3.62258471 LPTPORT: In Isr procedure, ISR_Irql=8 00000030 3.62259170 LPTPORT: We are now in DpcForIsr, currentIrql=2 xferCount = 1 00000031 3.62259812 LPTPORT: ReadDataSafely, currentIrql=8 ReadStatus= 27 ReadByte= 04 00000032 3.62260120 LPTPORT: 00000033 3.62260595 LPTPORT: currentByteNo =2, byteToBeOutToPort=05(hex) 00000034 3.62260958 LPTPORT: DoNextTransfer: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 00000138 3.62448468 LPTPORT: DoNextTransfer: 00000139 3.62448915 LPTPORT: Sending 0x02 to port 378 00000140 3.62449417 LPTPORT: generating next interrupt... 00000141 3.62460480 LPTPORT: In Isr procedure, ISR_Irql=8 00000142 3.62461123 LPTPORT: We are now in DpcForIsr, currentIrql=2 xferCount = 15 00000143 3.62461765 LPTPORT: ReadDataSafely, currentIrql=8 ReadStatus= 17 ReadByte= 02 00000144 3.62462073 LPTPORT: 00000145 3.62462548 LPTPORT: currentByteNo = 16, byteToBeOutToPort=13(hex) 00000146 3.62462883 LPTPORT: DoNextTransfer: 00000147 3.62463330 LPTPORT: Sending 0x03 to port 378 00000148 3.62463833 LPTPORT: generating next interrupt... 00000149 3.62474868 LPTPORT: In Isr procedure, ISR_Irql=8 00000150 3.62475566 LPTPORT: We are now in DpcForIsr, currentIrql=2 xferCount= 16 00000151 3.62476209 LPTPORT: ReadDataSafely, currentIrql=8 ReadStatus= 1F ReadByte= 03 00000152 3.62476488 LPTPORT: 00000153 3.62476879 LPTPORT: We are now in DpcForIsr, all data transmitted. 00000154 3.62529372 LPTPORT: We are now in DeviceControlRoutine, currentIrql=0 00000155 3.62529875 LPTPORT: TransferToUserSafely, currentIrql=8 00000156 3.62530322 requested 34 bytes, while ready 17 bytes. 00000157 3.62530769 Transferred 17, the rest 0 bytes. 00000158 3.62531271 LPTPORT: DeviceControlRoutine: IOCTL_SEND_TO_USER, 00000159 3.62531439 17 bytes transferred to user. 00000160 3.62566360 LPTPORT: We are now in DeviceControlRoutine, currentIrql=0 00000161 3.62567449 LPTPORT: DeviceControlRoutine: IOCTL_CLOSE_EVENT, 00000162 3.62567645 event handle closed with STATUS_SUCCESS. 00000163 3.62568231 LPTPORT: DeviceControlRoutine: IOCTL_CLOSE_EVENT, 00000164 3.62568427 event (handle 07CChex) closing status = 0. 00000165 3.62577506 LPTPORT: in DispatchClose now 00000166 6.71423547 LPTPORT: in DriverUnload now 00000167 6.71426704 LPTPORT: SymLink \DosDevices\LPTPORT0 deleted