[Previous] [Next]

Модификация приложения для тестирования драйвера

Тестирующее консольное приложение не так сильно изменилось, за исключением переписывания кода на использование вызовов 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

Вывод на экран (при наличии в параллельном порту заглушки CheckIt) практически не изменился и при запуске тестирующего приложения, текст которого приведен выше, в консольном окне можно наблюдать следующие сообщения:

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