我需要在 WDM 驱动中 获取 PDO 的物理信息 设备属性,如 PhysicalDeviceObjectName HardwareID DevicePropertyDeviceDescription
我知道可以用 IoGetDeviceProperty 获取,但是我的PDO 是ACPI 驱动 创建的 ,我需要获取我PDOI 的 _UID , 但是 IoGetDeviceProperty 只支持如下的信息获取,没有 UID 的类型。
我怎么获取PDO设备的_UID 呢?
给一个通过 IRP 请求 获取 UID 的代码示例
引用chatgpt内容作答:
在 WDM 驱动中,您可以使用其他方法来获取 ACPI PDO 设备的 _UID(唯一 ID)。由于 IoGetDeviceProperty 函数不直接提供 _UID 属性的查询,您可以尝试以下方法来获取 _UID:
1、使用 IRP_MN_QUERY_ID 请求:
您可以向 ACPI PDO 设备发送 IRP_MN_QUERY_ID 请求,并指定 QueryType 为 BusQueryDeviceID。这将使设备栈返回设备的标识符字符串,其中包含设备的 _UID。
2、使用 IRP_MN_QUERY_DEVICE_TEXT 请求:
同样,您可以向 ACPI PDO 设备发送 IRP_MN_QUERY_DEVICE_TEXT 请求,并指定 RequestType 为 DeviceTextDescription。这将使设备栈返回设备的描述字符串,其中可能包含设备的 _UID。
3、解析 ACPI 配置:
ACPI 设备对象通常包含一个名为 _HID 的属性,它是硬件 ID。该 ID 通常与设备的 _UID 相对应。您可以通过解析 ACPI 配置来获取这些属性,并从中提取 _UID。
以下是第一种方法的示例代码:
NTSTATUS GetAcpiDeviceUid(PDEVICE_OBJECT pdo, PWSTR* pUid)
{
NTSTATUS status = STATUS_SUCCESS;
PIRP irp = NULL;
KEVENT event;
IO_STATUS_BLOCK ioStatusBlock;
PAGED_CODE();
*pUid = NULL;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pdo, NULL, 0, NULL, &event, &ioStatusBlock);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
irpSp->MinorFunction = IRP_MN_QUERY_ID;
irpSp->Parameters.QueryId.IdType = BusQueryDeviceID;
status = IoCallDriver(pdo, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
if (NT_SUCCESS(status))
{
*pUid = ExAllocatePoolWithTag(PagedPool, ioStatusBlock.Information, 'myTag');
if (*pUid != NULL)
{
RtlCopyMemory(*pUid, ioStatusBlock.Information, ioStatusBlock.Information);
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
return status;
}
这只是获取 ACPI PDO 设备 _UID 的一种方法。在实际实现中,您可能需要根据具体的设备和驱动情况进行适当的调整。同时,记得在使用 ExAllocatePoolWithTag 分配的内存后,在不再使用时使用 ExFreePool 释放它,以避免内存泄漏。
ACPI 设备的 _UID 并非硬件标识符,而是与 ACPI 设备节点相关的标识符。如果您需要硬件 ID,请使用 IRP_MN_QUERY_ID 请求并指定 QueryType 为 BusQueryHardwareIDs。
结合chatgpt
对于ACPI驱动创建的PDO,确实无法直接通过IoGetDeviceProperty获取_UID属性。在这种情况下,您需要使用其他方法来获取PDO的其他物理信息和设备属性。
一种可行的方法是使用WMI (Windows Management Instrumentation) 查询。您可以通过执行WMI查询来获取设备的其他属性,包括_UID。以下是一个示例代码片段,演示如何使用WMI查询获取设备的物理信息和_UID属性:
c
#include <Windows.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main()
{
HRESULT hres;
// 初始化COM
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
return 1;
}
// 初始化WMI
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (FAILED(hres))
{
CoUninitialize();
return 1;
}
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID*)&pLoc
);
if (FAILED(hres))
{
CoUninitialize();
return 1;
}
IWbemServices* pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
pLoc->Release();
CoUninitialize();
return 1;
}
// 设置WMI查询语句
_bstr_t query = _bstr_t("SELECT * FROM Win32_PnPEntity");
// 执行WMI查询
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
query,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator
);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1;
}
// 遍历查询结果
IWbemClassObject* pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
// 获取设备描述
hr = pclsObj->Get(L"Description", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR)
{
wprintf(L"Device Description: %s\n", vtProp.bstrVal);
VariantClear(&vtProp);
}
// 获取硬件ID
hr = pclsObj->Get(L"HardwareID", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && (vtProp.vt == (VT_ARRAY | VT_BSTR)))
{
SAFEARRAY* pSafeArray = vtProp.parray;
LONG lLBound, lUBound;
SafeArrayGetLBound(pSafeArray, 1, &lLBound);
SafeArrayGetUBound(pSafeArray, 1, &lUBound);
for (LONG i = lLBound; i <= lUBound; i++)
{
BSTR bstrValue;
SafeArrayGetElement(pSafeArray, &i, &bstrValue);
wprintf(L"Hardware ID: %s\n", bstrValue);
}
VariantClear(&vtProp);
}
// 获取_UID属性
hr = pclsObj->Get(L"_UID", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR)
{
wprintf(L"_UID: %s\n", vtProp.bstrVal);
VariantClear(&vtProp);
}
pclsObj->Release();
}
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
Co
该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
在 WDM 驱动中,可以通过以下步骤获取 PDO 设备的 _UID 属性:
使用 IoGetDeviceProperty
函数获取 PDO 设备的 DEVPKEY_Device_PDOName
属性,该属性包含了 PDO 设备的名称。
使用 IoGetDeviceObjectPointer
函数获取 PDO 设备的设备对象指针和设备扩展对象指针。
使用 IoGetDeviceProperty
函数获取 PDO 设备的 DEVPKEY_Device_EnumeratorName
属性,该属性包含了 PDO 设备所属的枚举器名称。
使用 IoGetDeviceProperty
函数获取枚举器设备的 DEVPKEY_Device_Enumerator
属性,该属性包含了枚举器设备的设备描述符。
使用 CM_Get_Device_ID
函数获取设备描述符中的 _UID
属性,该属性包含了 PDO 设备的唯一标识符。
以下是获取 PDO 设备 _UID 属性的代码示例:
NTSTATUS GetPdoUid(PDEVICE_OBJECT pdo, PWSTR uid, ULONG uidSize)
{
NTSTATUS status;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_OBJECT parentDeviceObject = NULL;
UNICODE_STRING pdoName;
UNICODE_STRING enumeratorName;
DEVPROPTYPE propertyType;
ULONG enumeratorNameLength;
ULONG deviceDescriptionLength;
ULONG ulSize = 0;
ULONG ulPropertySize = 0;
ULONG ulResult = 0;
PVOID pPropertyBuffer = NULL;
CONFIGRET configRet;
PWSTR deviceDescription = NULL;
ULONG uidLength = 0;
PWSTR uidBuffer = NULL;
ULONG requiredSize = 0;
CONFIGRET cr;
DEVINST devinst;
CONFIGRET status;
ULONG ulLength = 0;
// 获取 PDO 设备名称
status = IoGetDeviceProperty(pdo, &DEVPKEY_Device_PDOName, sizeof(UNICODE_STRING), &pdoName, &ulPropertySize);
if (!NT_SUCCESS(status)) {
return status;
}
// 获取 PDO 设备对象指针和设备扩展对象指针
status = IoGetDeviceObjectPointer(&pdoName, FILE_READ_ATTRIBUTES, &deviceObject, &parentDeviceObject);
if (!NT_SUCCESS(status)) {
return status;
}
// 获取 PDO 设备所属的枚举器名称
status = IoGetDeviceProperty(parentDeviceObject, &DEVPKEY_Device_EnumeratorName, sizeof(UNICODE_STRING), &enumeratorName, &ulPropertySize);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(deviceObject);
return status;
}
// 获取枚举器设备的设备描述符
ulSize = 0;
cr = CM_Get_Device_ID_Size(&ulSize, enumeratorName.Buffer, CM_GETIDLIST_FILTER_ENUMERATOR);
if (cr != CR_SUCCESS || ulSize == 0) {
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
PWSTR pDeviceID = (PWSTR)ExAllocatePoolWithTag(PagedPool, ulSize, 'TDIM');
if (pDeviceID == NULL) {
IoDeleteDevice(deviceObject);
return STATUS_NO_MEMORY;
}
cr = CM_Get_Device_ID_List(enumeratorName.Buffer, pDeviceID, ulSize, CM_GETIDLIST_FILTER_ENUMERATOR);
if (cr != CR_SUCCESS) {
ExFreePool(pDeviceID);
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
// 获取设备描述符中的 _UID 属性
cr = CM_Locate_DevNode(&devinst, pDeviceID, CM_LOCATE_DEVNODE_NORMAL);
if (cr != CR_SUCCESS) {
ExFreePool(pDeviceID);
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
ulLength = 0;
cr = CM_Get_DevNode_Property(devinst, &DEVPKEY_Device_UniqueId, &propertyType, NULL, &ulLength, 0);
if (cr != CR_BUFFER_SMALL || ulLength == 0) {
ExFreePool(pDeviceID);
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
uidBuffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, ulLength, 'TDIM');
if (uidBuffer == NULL) {
ExFreePool(pDeviceID);
IoDeleteDevice(deviceObject);
return STATUS_NO_MEMORY;
}
cr = CM_Get_DevNode_Property(devinst, &请注意,上述代码示例中获取 _UID 属性的方式是使用 `DEVPKEY_Device_UniqueId` 属性,而不是 `DEVPKEY_Device_HardwareIds` 属性。这是因为 `_UID` 属性是一个设备特定的唯一标识符,而 `HardwareID` 属性是一个设备的硬件标识符列表。
如果您希望获取 `HardwareID` 属性,可以使用以下代码:
```c
// 获取设备的硬件 ID 列表
status = IoGetDeviceProperty(pdo, &DEVPKEY_Device_HardwareIds, 0, NULL, &ulSize);
if (status != STATUS_BUFFER_TOO_SMALL) {
IoDeleteDevice(deviceObject);
return status;
}
pPropertyBuffer = ExAllocatePoolWithTag(PagedPool, ulSize, 'TDIM');
if (pPropertyBuffer == NULL) {
IoDeleteDevice(deviceObject);
return STATUS_NO_MEMORY;
}
status = IoGetDeviceProperty(pdo, &DEVPKEY_Device_HardwareIds, ulSize, pPropertyBuffer, &ulSize);
if (!NT_SUCCESS(status)) {
ExFreePool(pPropertyBuffer);
IoDeleteDevice(deviceObject);
return status;
}
PHardwareIDList pHardwareIDList = (PHardwareIDList)pPropertyBuffer;
PWCHAR pHardwareID = (PWCHAR)(pHardwareIDList + 1);
其中,PHardwareIDList
是一个结构体,定义如下:
typedef struct _HardwareIDList {
ULONG NumberOfIds;
WCHAR Ids[ANYSIZE_ARRAY];
} HardwareIDList, *PHardwareIDList;
在 HardwareIDList
结构体中,NumberOfIds
表示硬件 ID 的数量,Ids
数组包含了所有硬件 ID。
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
不知道你这个问题是否已经解决, 如果还没有解决的话:要获取ACPI驱动创建的PDO设备的_UID属性,可以通过如下步骤进行操作:
在WDM驱动程序中,从ACPI驱动创建的PDO设备对象开始遍历,获取其父设备对象指针。
使用父设备对象指针调用IoGetDeviceProperty
函数,指定属性参数为DevicePropertyDeviceID
,获取设备的硬件ID(HardwareID)。
使用IO_STACK_LOCATION结构体中的Parameters.QueryDeviceRelations关联的DEVICE_RELATIONS
结构体来获取ACPI设备的子设备对象。
循环遍历子设备对象,获取其对应的_UID属性值。
下面是一个示例代码片段:
#include <ntddk.h>
#include <wdm.h>
NTSTATUS GetPDODeviceInfo(PDEVICE_OBJECT pdo)
{
PDEVICE_OBJECT parentDeviceObject;
UNICODE_STRING deviceID;
NTSTATUS status;
parentDeviceObject = pdo->AttachedDevice;
// 获取设备的硬件ID(HardwareID)
status = IoGetDeviceProperty(parentDeviceObject, DevicePropertyDeviceID,
sizeof(UNICODE_STRING), &deviceID.Length, &deviceID);
if (!NT_SUCCESS(status)) {
// 错误处理
return status;
}
// 打印设备的硬件ID(HardwareID)
DbgPrint("Hardware ID: %wZ\n", &deviceID);
// 释放deviceID
RtlFreeUnicodeString(&deviceID);
// 获取ACPI设备的子设备对象
PDEVICE_RELATIONS deviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
// 遍历子设备对象
for (ULONG i = 0; i < deviceRelations->Count; i++) {
// 获取设备对象的_UID属性值
IO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PKEY_VALUE_PARTIAL_INFORMATION keyInformation = NULL;
ULONG keyLength = 0;
PVOID buffer = NULL;
// 为查询注册表键值的长度
status = ZwQueryValueKey(
ParentDeviceObject,
L"DeviceID",
KeyValuePartialInformation,
buffer,
keyLength,
&keyLength
);
if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW) {
buffer = ExAllocatePoolWithTag(PagedPool, keyLength, 'DevI');
if (buffer) {
status = ZwQueryValueKey(
ParentDeviceObject,
L"DeviceID",
KeyValuePartialInformation,
buffer,
keyLength,
&keyLength
);
if (NT_SUCCESS(status)) {
keyInformation = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
// 输出设备的_UID属性值
DbgPrint("UID: %ws\n", (PWCHAR)keyInformation->Data);
}
}
}
// 释放buffer
if (buffer != NULL) {
ExFreePoolWithTag(buffer, 'DevI');
}
}
return STATUS_SUCCESS;
}
// 在驱动程序中使用
void DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
// ...
NTSTATUS status;
UNICODE_STRING pdoName;
// 通过某种方式获取ACPI驱动创建的PDO设备对象
// ...
// 调用获取PDO设备信息函数
status = GetPDODeviceInfo(pdo);
if (!NT_SUCCESS(status)) {
// 错误处理
}
// ...
}
以上是一个简单的示例代码,用于获取ACPI驱动创建的PDO设备的_UID属性。具体的实现可能因系统环境及驱动代码结构而有所差异,可以根据实际需求进行修改。
希望对你有所帮助!如果需要进一步帮助,请随时提问。
援引GPT回答:
如果您需要获取ACPI驱动创建的PDO设备的_UID,可以尝试使用以下方法:
获取ACPI设备对象的设备扩展属性:
您可以使用IoGetDeviceProperty
函数获取ACPI设备对象的设备扩展属性。具体步骤如下:
IoGetDeviceProperty
函数获取设备对象的DevicePropertyPhysicalDeviceObjectName
属性,以获取设备对象的物理设备对象名称。IoGetDeviceObjectPointer
函数将物理设备对象名称转换为物理设备对象的指针。IoGetDeviceProperty
函数,获取其设备扩展属性,包括DevicePropertyDeviceDescription
和DevicePropertyHardwareID
。下面是一个示例代码片段,展示了如何使用上述方法获取ACPI设备对象的设备扩展属性:
// 获取设备对象的物理设备对象名称
UNICODE_STRING pdoObjectName;
status = IoGetDeviceProperty(deviceObject, DevicePropertyPhysicalDeviceObjectName, sizeof(UNICODE_STRING), &pdoObjectName, &returnLength);
if (NT_SUCCESS(status)) {
// 将物理设备对象名称转换为物理设备对象的指针
PDEVICE_OBJECT pdoDeviceObject;
status = IoGetDeviceObjectPointer(&pdoObjectName, FILE_READ_ATTRIBUTES, &pdoDeviceObject, &pdoFileObject);
if (NT_SUCCESS(status)) {
// 获取物理设备对象的设备扩展属性
UNICODE_STRING deviceDescription;
status = IoGetDeviceProperty(pdoDeviceObject, DevicePropertyDeviceDescription, sizeof(UNICODE_STRING), &deviceDescription, &returnLength);
if (NT_SUCCESS(status)) {
// 获取设备描述信息成功
// 处理设备描述信息
}
UNICODE_STRING hardwareID;
status = IoGetDeviceProperty(pdoDeviceObject, DevicePropertyHardwareID, sizeof(UNICODE_STRING), &hardwareID, &returnLength);
if (NT_SUCCESS(status)) {
// 获取硬件ID成功
// 处理硬件ID
}
// 释放物理设备对象
ObDereferenceObject(pdoDeviceObject);
}
}
使用其他方法获取_UID:
如果上述方法无法获取_UID,您可以尝试使用其他方法来获取_UID。例如,您可以尝试使用ACPI接口来查询设备的_UID,或者查看设备的注册表信息以获取_UID。具体方法可能因设备和驱动程序的不同而有所不同,请根据具体情况进行调整。
请注意,获取_UID可能需要对ACPI驱动进行特定的处理,因此具体实现可能会因驱动程序的实现方式而有所不同。建议您参考相关文档或与驱动程序开发者进行沟通,以获取准确的方法和信息。
结合GPT建议:
在 ACPI 驱动中,获取 PDO 设备的 UID(Unique Identifier)可以通过处理 IRP_MN_QUERY_ID 请求来实现。在 Windows 驱动开发中,IRP_MN_QUERY_ID 是一种 I/O 请求包 (IRP),它用于获取设备的标识符,包括设备的 UID。下面是一个获取 UID 的示例代码:
#include <ntddk.h>
NTSTATUS GetDeviceUID(PDEVICE_OBJECT pdo, PUNICODE_STRING pUID)
{
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
pdo,
NULL,
0,
NULL,
&event,
&ioStatus);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
// 设置 IRP 请求类型为 IRP_MN_QUERY_ID,并指定获取 UID
UCHAR minorFunction = IRP_MN_QUERY_ID;
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
irp->IoStatus.Information = 0;
IoSetNextIrpStackLocation(irp);
irp->Tail.Overlay.CurrentStackLocation->MinorFunction = minorFunction;
// 设置请求 ID 类型为 BusQueryDeviceID,即获取设备的 UID
irp->Tail.Overlay.CurrentStackLocation->Parameters.QueryId.IdType = BusQueryDeviceID;
// 发送 IRP 请求
status = IoCallDriver(pdo, irp);
if (status == STATUS_PENDING)
{
// 如果请求挂起,则等待请求完成
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (NT_SUCCESS(status))
{
// 获取 UID 字符串
*pUID = *((PUNICODE_STRING)ioStatus.Information);
}
return status;
}
在调用 GetDeviceUID
函数时,传递包含 ACPI PDO 的 PDEVICE_OBJECT
指针作为参数,并将 PUNICODE_STRING
类型的指针传递给函数,用于接收设备的 UID 字符串。
请注意,上述代码假定你已经创建了一个驱动,并且已经在驱动中实现了正确的 PnP(Plug and Play)处理程序。在实际的驱动中,你需要处理其他 IRP 类型和更多的错误情况。此外,此代码示例适用于 Windows 内核驱动程序开发。
根据你的具体环境和驱动实现,可能还需要进行其他适当的设置和检查,以确保正确获取设备的 UID。