> //Освободить ресурсы устройства
> 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-пакетов.