Использование NuMega DriverStudio для написания WDM-драйверов - [15]

Шрифт
Интервал

>void XDSPdrv::LoadRegistryParameters(KRegistryKey &Params) {

> m_bBreakOnEntry = FALSE;

> Params.QueryValue(L"BreakOnEntry", &m_bBreakOnEntry);

> t << "m_bBreakOnEntry loaded from registry, resulting value: [" << m_bBreakOnEntry << "]\n";

>}

На этом заканчивается секция инициализации драйвера. Далее следует метод AddDevice. Он вызывается, когда система обнаруживает устройство, за которое отвечает драйвер (обычно это происходит при загрузке драйвера). В метод ситема передает указатель на физический объект устройства (Physical Device Object, PDO). Этот объект представляет собой некий блок информации о физическом устройстве, который используется ОС. Данный метод создает объект устройства XDSPDevice. С точки зрения системы, создается функциональный объект устройства (Functional Device Object, FDO).

>NTSTATUS XDSPdrv::AddDevice(PDEVICE_OBJECT Pdo) {

> t << "AddDevice called\n";

> //Здесь вызывается конструктор класса XDSPDevice.

> XDSPdrvDevice* pDevice = new(

>  static_cast(KUnitizedName(L"XDSPdrvDevice", m_Unit)),

>  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-провайдером.