Здравствуйте. Возникла проблема с использованием IoGetDeviceProperty, точнее даже не проблема, а некоторое недопонимание ее использование. А именно с первый параметром - PDEVICE_OBJECT DeviceObject. Это, как следует из MSDN'а, указатель на POD. Как я понял, POD - есть ничто иное, как самое нижнее устройство стека фильтров. Теперь вопрос: как получить этот самый POD, если у меня из исходных данных только имя устройства, например \Device\Harddisk2\DP(1)0-0+5? Буду благодарен любой помощи. P.S. Просьба сильно не пинать, я в низкоуровневом программировании сравнительно недавно. P.P.S. К гуглу не посылать, поиском на форуме пользовался =)
Только она вернёт указатель не на сам PDO, а на вершину стека, если конечно над PDO кто-то сидит. Если скормить этот указатель IoGetDeviceProperty - BSOD. Нужно сперва спуститься до PDO. Под ХР и выше можно использовать IoGetDeviceAttachmentBaseRef. http://www.wasm.ru/forum/viewtopic.php?id=16125
Four-F Ссылку глянул, почитал доки. Один только вопрос остался (только не смейтесь товарищи =)): там везде упоминается DEVOBJ_EXTENSION_EX, а именно ее поле AttachedTo. Все понятно, только одна проблема: а где вы взяли этот DEVOBJ_EXTENSION_EX? У меня описания этой структуры нет ни в одном хидере ДДК. Она как я понимаю входит в DEVICE_OBJECT? Так DEVICE_OBJECT у меня во всех хидерах вот как описан: Код (Text): typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT { CSHORT Type; USHORT Size; LONG ReferenceCount; struct _DRIVER_OBJECT *DriverObject; struct _DEVICE_OBJECT *NextDevice; struct _DEVICE_OBJECT *AttachedDevice; struct _IRP *CurrentIrp; PIO_TIMER Timer; ULONG Flags; // See above: DO_... ULONG Characteristics; // See ntioapi: FILE_... PVPB Vpb; PVOID DeviceExtension; DEVICE_TYPE DeviceType; CCHAR StackSize; union { LIST_ENTRY ListEntry; WAIT_CONTEXT_BLOCK Wcb; } Queue; ULONG AlignmentRequirement; KDEVICE_QUEUE DeviceQueue; KDPC Dpc; // // The following field is for exclusive use by the filesystem to keep // track of the number of Fsp threads currently using the device // ULONG ActiveThreadCount; PSECURITY_DESCRIPTOR SecurityDescriptor; KEVENT DeviceLock; USHORT SectorSize; USHORT Spare1; struct _DEVOBJ_EXTENSION *DeviceObjectExtension; PVOID Reserved; } DEVICE_OBJECT; Подскажите, в чем я неправ и если неверна моя структура DEVICE_OBJECT, то дайте правильную, и тогда уж и DEVOBJ_EXTENSION_EX. Совсем запутался я что-то...
Кажется дошло. Указатель на DEVOBJ_EXTENSION_EX в структуре DEVICE_OBJECT равен адресу DEVOBJ_EXTENSION, только в DEVOBJ_EXTENSION не все поля, а только первые три: Код (Text): typedef struct _DEVOBJ_EXTENSION { CSHORT Type; USHORT Size; // // Public part of the DeviceObjectExtension structure // PDEVICE_OBJECT DeviceObject; // owning device object } DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION; В то время как DEVOBJ_EXTENSION_EX Код (Text): typedef struct _DEVOBJ_EXTENSION_EX { CSHORT Type; USHORT Size; PDEVICE_OBJECT DeviceObject; ULONG PowerFlags; struct _DEVICE_OBJECT_POWER_EXTENSION *Dope; ULONG ExtensionFlags; PVOID DeviceNode; PDEVICE_OBJECT AttachedTo; LIST_ENTRY FileObjectList; } DEVOBJ_EXTENSION_EX, *PDEVOBJ_EXTENSION_EX; Таким образом, получается, что DEVOBJ_EXTENSION_EX это тот же DEVOBJ_EXTENSION, только более полный, то есть содержащий все поля. Теперь вопросы: 1. Правильны ли мои догадки? 2. Если 1 верно, то верно ли описание DEVOBJ_EXTENSION_EX, которое я все же нашел? 3. Таким образом, чтобы получить указатель на PDO нужно вызвать IoGetDeviceObjectPointer, которая возвращает указатель на FILE_OBJECT и на DEVICE_OBJECT. Если я буду использовать DEVICE_OBJECT то надо последовательно спускаться вниз по стеку фильтров до тех пор пока AttachedTo не будет равно нулю, как только равно нулю, значит это PDO? 4. А если использовать FILE_OBJECT возвращаемый IoGetDeviceObjectPointer, то у него есть поле DeviceObject, а не является ли этот указатель (FILE_OBJECT.DeviceObject) указателем на PDO? Если так, то может быть будет лучше не спускаться "вручную" по стеку фильтров, а получить POD через FILE_OBJECT? Много вопросов... Буду весьма признателен если вы на все ответите.
Уже не помню. Если она мне была нужна до появления исходников w2k, то пропарсил pdb с помощью PdbDump (лужит на нашем сайте, кажется). Если после, то, соответственно, в исходники глянул. PdbDump дает вот что: Код (Text): struct _DEVOBJ_EXTENSION { /*<thisrel this+0x0>*/ /*|0x2|*/ short Type; /*<thisrel this+0x2>*/ /*|0x2|*/ unsigned short Size; /*<thisrel this+0x4>*/ /*|0x4|*/ struct _DEVICE_OBJECT* DeviceObject; /*<thisrel this+0x8>*/ /*|0x4|*/ unsigned long PowerFlags; /*<thisrel this+0xc>*/ /*|0x4|*/ struct _DEVICE_OBJECT_POWER_EXTENSION* Dope; /*<thisrel this+0x10>*/ /*|0x4|*/ unsigned long ExtensionFlags; /*<thisrel this+0x14>*/ /*|0x4|*/ void* DeviceNode; /*<thisrel this+0x18>*/ /*|0x4|*/ struct _DEVICE_OBJECT* AttachedTo; /*<thisrel this+0x1c>*/ /*|0x8|*/ struct _LIST_ENTRY FileObjectList; }; В DDK есть только публичная часть DEVOBJ_EXTENSION. То что идет после DeviceObject недокументировано, но в отладочные символы таки попадает. Не входит, а на нее указывает поле DeviceObjectExtension. Если нужно спуститься до PDO под w2k, то можно юзать мой вариант GetNextLowerDeviceObject по этой ссылке: http://www.wasm.ru/forum/viewtopic.php?id=11363 Под ХР+ IoGetDeviceAttachmentBaseRef либо в цикле IoGetLowerDeviceObject.
Да. Да. Да. Ммм... Точно не скажу - отладчика под рукой щас нет, но даже если так, то я бы не стал на это опираться.
Уважаемый Four-F, не мог бы ты еще мне помочь. Вот мой код: Код (Text): const PCWSTR DeviceName=L"\\Device\\Harddisk2\\DP(1)0-0+5"; NTSTATUS ns; UNICODE_STRING usDeviceName; PFILE_OBJECT pFileObject=0; PDEVICE_OBJECT pDeviceObject; PDEVOBJ_EXTENSION_EX pDevObjExtensionEx; RtlInitUnicodeString(&usDeviceName, DeviceName); ns=IoGetDeviceObjectPointer(&usDeviceName, FILE_READ_DATA, &pFileObject, &pDeviceObject); DBGPRINT(NT_SUCCESS(ns) ? "IoGetDeviceObjectPointer success" : "IoGetDeviceObjectPointer failed"); pDevObjExtensionEx=(PDEVOBJ_EXTENSION_EX) pDeviceObject->DeviceObjectExtension; if(!pDevObjExtensionEx->AttachedTo) { IoGetDeviceProperty(...); // [b]на этом месте вылетает BSOD[/b] } if(pFileObject) { ObDereferenceObject(pFileObject); } Почему БСОД? Ведь если AttachedTo == 0 то это POD? Хотя если это POD то у него DeviceNode != 0, а у меня ноль. В чем ошибка? Я явно что-то недогоняю...
Не POD, я PDO (Physical Device Object). Я пошарился, с помощью WinObjEx, у себя в системе и нашёл парочку девайсов вида \Device\HarddiskX\DP(X)XXX, у которых AttachedTo == NULL и DeviceNode == NULL, но это не PDO. В том смысле, что эти девайсы не являются узлами PnP. К сожалению, я плохо шарю в файловых системах, но возможно это CDO (Control Device Object), которые создает файловая система при монтировании тома, или какие-то особые девайсы, представляющие логические разделы диска, т.к. судя по именам.. DP(1)0x7e00-0x138c97e00+1 DP(2)0x138ca7a00-0x36f888600+2 .. цифры - смещения начала и конца раздела. У меня на стареньком ноуте, за которым щас сижу, как раз два раздела 5,2 и 14,7 гига. Твой DP(1)0-0+5, видимо, соотв. единственному разделу диска или флешки. Вобщем, я не знаю, что это за девайсы, но по-любому, если у них нет ноды, то от IoGetDeviceProperty толку всё равно не будет. Кстати, вспомнил ещё один хороший способ поиметь PDO, хотя в данном случае это всё равно не поможет. Нужно синхронно послать в стек PnP IRP IRP_MN_QUERY_DEVICE_RELATIONS с пареметром TargetDeviceRelation. Целевой девайс любой в стеке: хоть на вершину, хоть в любой другой. Он гарантированно дойдёт до PDO и драйвер, управляющий PDO, обязан его обработать и вернуть указатель на PDO. Не забыть дереференс потом сделать. См. в DDK\src\general\toaster\toastmon\toastmon.c функцию ToastMon_GetTargetDevicePdo. Если ещё глянуть ToastMon_OpenTargetDevice, то вообще красота
Это действительно девайсы, соответствующие разделам диска. Пара слов есть тут: http://www.osp.ru/text/302/174349/
Да, это действительно флешка. Но ведь вызов SetupDiGetDeviceRegistryProperty в юзермоде дает необходимую информацию? А разве SetupDiGetDeviceRegistryProperty не спускается в конце концов к вызову IoGetDeviceProperty? И если действительно не получится использовать IoGetDeviceProperty в данном случае, то не мог бы ты еще подсказать, каким образов в ядре можно получить идентификационные данные устройства (желательно без прямого обращения к драйверу устройства, т.е. без посылки ему каких-то управляющих кодов и т.д., поскольку это, как я понимаю, лишает код некоторой универсальности).
Попробуй через DeviceNode. Если он нулевой, можно сходить по ссылке NextSibling или через Parent получить ссылки на NextSibling. Класс-драйверы могут создавать несколько разнотипных объектов для обслуживания одного устройства, и у некоторых из них AttachedTo и DeviceNode выставляются в NULL, это не PDO
Скорее всего спускается, но SetupDiGetDeviceRegistryProperty в юзермоде не может дать ничего для девайса не являющегося узлом PnP. Если у девайса в экстеншене DeviceNode == NULL, то это не узел PnP и SetupDiGetDeviceRegistryProperty просто не может работать! Дело в том, что для получения PnP-related инфы, имея указатель на девайс, IoGetDeviceProperty должна сначала перевести этот указатель в DeviceInstance. DeviceInstance - это грубо говоря ветка в реестре, например для моей флешки \HKLM\SYSTEM\CurrentControlSet\Enum\STORAGE\RemovableMedia\7&3517586&0&RM. DeviceInstance содержится в DeviceNode. Если нет DeviceNode, то нет и DeviceInstance и ничего PnP-related получить невозможно. Я почти уверен, что ты просто путаешь девайсы. SetupDiGetDeviceRegistryProperty вызываешь для одного, а IoGetDeviceProperty для совершенно другого. Возьми devcon из DDK. Прогони его с параметром stack storage*. Получишь что-то вроде этого: Код (Text): E:\DDK\tools\devcon\i386>devcon stack storage* STORAGE\REMOVABLEMEDIA\7&3517586&0&RM Name: Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume Class upper filters: VolSnap Controlling service: (none) STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET1316FDC00LENGTH262DE3E00 Name: Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume Class upper filters: VolSnap Controlling service: (none) STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET3944E9800LENGTH7281E3400 Name: Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume Class upper filters: VolSnap Controlling service: (none) STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET7E00LENGTH1316EE000 Name: Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume Class upper filters: VolSnap Controlling service: (none) 4 matching device(s) found. Это DeviceInstance для томов. Первый - моя флешка, три остальных разделы на харде. Затем в поиске WinObjEx поищи символьные ссылки с такими же именами (бери только часть имени после слеша). Увидишь, что они кажут на девайсы: Код (Text): STORAGE\REMOVABLEMEDIA\7&3517586&0&RM -> \Device\Harddisk1\DP(1)0-0+5 STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET1316FDC00LENGTH262DE3E00 -> \Device\HarddiskVolume2 STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET3944E9800LENGTH7281E3400 -> \Device\HarddiskVolume3 STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET7E00LENGTH1316EE000 -> \Device\HarddiskVolume1 У всех этих девайсов DeviceNode != NULL (WinObjEx это показывает в свойствах), что естественно, иначе бы они просто не попали в вывод devcon'a. Те девайсы, которые у меня представляют логические разделы диска, DP(1)0x7e00-0x138c97e00+1, DP(2)0x138ca7a00-0x36f888600+2... не попадают в вывод devcon'a, т.к. у них нет ноды. Можешь ещё получить всё PnP дерево в KernelDebugger по команде... kd> !devnode 0 1 ...там тоже будут только PnP узлы. Попробуй поискать там тот девайс, на котором у тебя облом - его там быть не должно. Короче разберись точно, что и от какого девайса ты хочешь поиметь. В любом случае, если DeviceNode == NULL, то никаких "Plug and Play device property" не будет.
Возможен ещё вариант, что хозяин этих девайсов, соответствующих разделам диска, у которых нет ноды просто редиректит какие-то запросы в другой стек. И если SetupDiGetDeviceRegistryProperty посылает PnP IRP, то может быть просто возвращается инфа о другом девайсе. Но сомневаюсь, что это так. Т.к. я не знаю как работает файловая система, то не могу точно сказать.