Использование NuMega DriverStudio для написания WDM-драйверов | страница 33



> //Освободить ресурсы устройства

> Invalidate();

> // Здесь добавляется код, специфичный для данного устройства.

> return status;

>}

Виртуальная функция OnRemoveDevice вызывается при извлечении устройства из системы. При этом системная политика PnP сама позаботится об удалении PDO.

>NTSTATUS XDSPdrvDevice::OnRemoveDevice(KIrp I) {

> t << "Entering XDSPdrvDevice::OnRemoveDevice\n";

> // Освободить ресурсы устройства

> Invalidate();

> // Здесь добавляется код, специфичный для данного устройства.

> return STATUS_SUCCESS;

>}

Иногда бывает необходимо отменить обработку IRP, уже поставленного в очередь (такие запросы иногда посылает диспетчер В/В). Когда такая ситуация может возникнуть?

Представим такую ситуацию: в приложении пользователя поток послал нашему драйверу запрос на ввод-вывод и завершил свою работу. А IRP-пакет попал в очередь запросов и терпеливо ждет своей очереди на обработку. Конечно же, обработка такого "бесхозного" IRP-пакета должна быть отменена. Для этого драйвером поддерживается целый механизм отмены обработки запросов. В Win2000 DDK подробно описано, почему ЛЮБОЙ драйвер должен поддерживать этот механизм. Это связано, в основном, с проблемами надежности и устойчивости работы системы. Ведь сбой в драйвере — это, практически, сбой в ядре ОС.

В классе KPnPDevice механизм отмены запроса реализован при помощи метода CancelQueuedIrp.

>VOID XDSPdrvDevice::CancelQueuedIrp(KIrp I) {

> //Получаем очередь IRP-пакетов этого устройства.

> KDeviceQueue dq(DeviceQueue());

>//Проверить, является ли IRP, который должен быть отменен, тем пакетом, который должен

> //быть обработан.

> if ( (PIRP)I == CurrentIrp() ) {

>  //Уничтожить пакет.

>  CurrentIrp() = NULL;

>  //При вызове метода CancelQueuedIrp устанавливается глобальная системная

>  //защелка (SpinLock). Теперь следует ее сбросить.

>  CancelSpinLock::Release(I.CancelIrql());

>  t << "IRP canceled " << I << EOL;

>  I.Information() = 0;

>  I.Status() = STATUS_CANCELLED;

>  //Обработать следующий пакет.

>  PnpNextIrp(I);

> }

> //Удалить из очереди пакет. Если это удалось, то функция вернет true.

> else if (dq.RemoveSpecificEntry(I)) {

>  // Это удалось. Теперь сбрасываем защелку.

>  CancelSpinLock::Release(I.CancelIrql());

>  t << "IRP canceled " << I << EOL;

>  I.Information() = 0;

>  I.PnpComplete(this, STATUS_CANCELLED);

> } else {

>  //Неудача. Сбрасываем защелку.

>  CancelSpinLock::Release(I.CancelIrql());

> }

>}

Меотод StartIo является виртуальной функцией. Она вызывается системой, когда драйвер готов обрабатывать следующий запрос в очереди. Это чрезвычайно важная функция: она является диспетчером всех запросов на ввод-вывод, поступаемых к нашему драйверу. В функции вызываются обработчики запросов на чтение, запись а также обработчики вызовов IOCTL. К счастью, умный DriverWizard генерирует скелет функции автоматически и вносить изменения в нее в нашем простом случае не требуется. В принципе, в эту функцию можно ввести какие-то дополнительные проверки IRP-пакетов.