FILE_DEVICE_UNKNOWN,
static_cast(KUnitizedName(L"XDSPdrvDevice", m_Unit)),
0,
DO_DIRECT_IO)
XDSPDevice(Pdo, m_Unit);
//m_Unit – количество таких устройств в системе.
if (pDevice == NULL) //Не удалось создать объект устройства. Похоже, произошла какая-то ошибка.
{
t << "Error creating device XDSPdrvDevice" << (ULONG) m_Unit << EOL;
return STATUS_INSUFFICIENT_RESOURCES;
}
//Получить статус создания устройства.
NTSTATUS status = pDevice->ConstructorStatus();
if ( !NT_SUCCESS(status) ) //Похоже, устройство создано, но неудачно; произошла ошибка.
{
t << "Error constructing device XDSPdrvDevice" << (ULONG) m_Unit << " status " << (ULONG) status << EOL;
delete pDevice;
} else {
m_Unit++; //Устройство создано удачно
}
//Вернуть статус устройства.
return status;
}
Все. Работа объекта драйвера на этом окончена. Как мы можем видеть, объект драйвера практически не выполняет каких-либо функций управления аппаратурой, но он жизненно необходим для правильной инициализации драйвера. В нашем случае НЕ ТРЕБУЕТСЯ вносить какие-либо изменения в текст, сформированный DriverWizard.
Основным классом драйвера является класс устройства. Класс устройства XDSPdrvDevice является подклассом класса KpnpDevice. Конструктор получает два параметра: указатель на PDO и номер драйвера в системе.
XDSPdrvDevice::XDSPdrvDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : KPnpDevice(Pdo, NULL) {
t << "Entering XDSPdrvDevice::XDSPdrvDevice (constructor)\n";
//Здесь проверяется код ошибки, которую вернул конструктор суперкласса. В случае
//успешного создания объекта базового класса значение переменной m_ConstructorStatus
//будет NT_SUCCESS.
if ( ! NT_SUCCESS(m_ConstructorStatus) ) {
//Ошибка в создании объекта устройства
return;
}
//Запомнить номер драйвера
m_Unit = Unit;
//Инициализация устройства нижнего уровня. В роли устройства нижнего уровня в нашем
//драйвере выступает PDO. Но в случае стека драйверов в качестве устройства нижнего
//уровня может выступать объект устройства другого драйвера.
m_Lower.Initialize(this, Pdo);
// Установить объект нижнего уровня для нашего драйвера.
SetLowerDevice(&m_Lower);
// Установить стандартную политику PnP для данного устройства.
SetPnpPolicy();
}
Порядок вызова методов m_Lower.Initialize(this, Pdo), SetLowerDevice(&m_Lower) и SetPnpPolicy() является жизненно важным. Его нарушение может вызвать серьезные сбои в работе драйвера. Не стоит редактировать текст конструктора, сгенерированный DriverWizard.
Деструктор объекта устройства не выполняет никаких действий. Но для сложных драйверов, когда создаются системные потоки, разнообразные объекты синхронизации и выделяется память, то все созданные объекты должны быть уничтожены в деструкторе. В нашем простейшем случае не стоит вносить изменения в текст деструктора.
XDSPdrvDevice::~XDSPdrvDevice() {
t << "Entering XDSPdrvDevice::~XDSPdrvDevice() (destructor)\n";
}
Метод DefaultPnp — виртуальная функция, которая должна быть переопределена любым объектом устройства. Эта обработчик по умолчанию для IRP-пакета, у которого старший код функции (major function code) равен IRP_MJ_PNP. Драйвер обрабатывает некоторые из таких пакетов, у которых младший код функции равен IRP_MN_STOP_DEVICE, IRP_MN_START_DEVICE и т.п. (см. ниже) также при помощи виртуальных функций. Но те пакеты, которые не обрабатываются объектом устройства, передаются этой функции. Она ничего с ними не делает, а просто передает их устройству нижнего уровня (если такое есть, конечно). Не стоит изменять текст этой функции.
NTSTATUS XDSPdrvDevice::DefaultPnp(KIrp I) {
t << "Entering XDSPdrvDevice::DefaultPnp with IRP minor function=" << PNPMinorFunctionName(I.MinorFunction()) << EOL;
I.ForceReuseOfCurrentStackLocationInCalldown();
return m_Lower.PnpCall(this, I);
}
Метод SystemControl выполняет похожую функцию для IRP-пакетов, у которых старший код функции IRP_MJ_SYSTEM_CONTROL. Он также является виртуальной функцией и не выполняет никаких полезных действий, а просто передает IRP-пакет устройству нижнего уровня. Что-то менять в тексте этого метода надо только в том случае, если наше устройство является WMI-провайдером.
NTSTATUS XDSPdrvDevice::SystemControl(KIrp I) {
t << "Entering XDSPdrvDevice::SystemControl\n";
I.ForceReuseOfCurrentStackLocationInCalldown();
return m_Lower.PnpCall(this, I);
}
Метод Invalidate вызывается, когда устройство тем или иным образом завершает свою работу: из функций OnStopDevice, OnRemoveDevice а также при всевозможных ошибках. Метод Invalidate объекта устройства также вызывается из деструктора. Его можно вызывать несколько раз — не произойдет ничего страшного; но в методах Invalidate нет никакой защиты от реентерабельности. Т.е. если при работе метода Invalidate возникает какая– либо ошибка и из-за этого Invalidate должен будет вызваться снова, то ни DriverWorks, ни ОС Windows не станут этому мешать. Разработчик должен сам предусмотреть такую возможность и принять меры, чтобы подобная ситуация не привела к нехорошим последствиям.
Читать дальше