驱动配置信息读取RtlQueryRegistryValues 重启电脑驱动读注册表失败
2023-02-01
80
0
为什么这里要说是“驱动配置信息读取RtlQueryRegistryValues”,那是因为自己踩了坑的。
在写Windows驱动的时候,有时需要根据配置信息上来让驱动实现不同的功能。但这个配置信息放在那里合适呢?
第一当然是在文件中了,但是感觉放在那里都感觉好像不合适,而且容易被删除。另外如果参数信息比较多,自己还得写解析格式代码,感觉开发起来有点2。在驱动中重复造轮子,好像不是什么好的选择。
第二种就是放在注册表了,这种想法感觉很正统。但是放在那里了?又是一个问题。这又由每个人定义而不同,但放在不同的位置有时会有一些莫名的问题。比如如下:
我们知道驱动是随系统开机时加载的,所以这时候有一种情况就是驱动加载的比较早,注册表加载的比较晚。这时会导致我们需要读取信息的注册表目录树尚未建立,而读不到信息。这样让驱动会使用默认的信息来配置,但实际上是有的。这在我们系统开机后安装驱动是没有问题的,但对于重启后,很可能造成配置的参数信息不成功。
本人曾在AddDevice中读取计算机\HKEY_LOCAL_MACHINE\SOFTWARE
,是一定读取不到的。在测试模式或者禁用驱动模式下,在IRP_MN_START_DEVICE中读,是可以的。但在签完名后,有的机器还是读不到的。
上面说了这么多,就是要表达一个意思,使用注册表读驱动的参数信息,是要讲究的。这个讲究很可能就出现在RtlQueryRegistryValues上。另外我们在看一些驱动的源代码时,有大量这种获取配置信息,所以这应该就是正确了。
NTSTATUS
RtlQueryRegistryValues(
IN ULONG RelativeTo,
IN PCWSTR Path,
IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
IN PVOID Context,
IN PVOID Environment OPTIONAL
);
- RelativeTo是要读的注册表的路径,可以为
值 | 含义 |
---|---|
RTL_REGISTRY_ABSOLUTE | Path 是绝对注册表路径。 |
RTL_REGISTRY_CONTROL | Registry\Machine\System\CurrentControlSet\Control。 |
RTL_REGISTRY_DEVICEMAP | Registry\Machine\Hardware\DeviceMap。 |
RTL_REGISTRY_SERVICES | Registry\Machine\System\CurrentControlSet\Services。 |
RTL_REGISTRY_USER | Registry\User\CurrentUser |
RTL_REGISTRY_WINDOWS_NT | Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion。 |
- Path:是二级路径
- QueryTable:是一次可以获取多个参数的数组。
这个数组的最后一项必须为NULL,表示最后一个。NTSTATUS QueryRoutine ( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext );
这里搞一个示例,需要的自行修改:
NTSTATUS RegQueryGenericCompositeUSBDeviceString(IN OUT PWCHAR *GenericCompositeUSBDeviceString)
{
NTSTATUS ntStatus;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
PWCHAR usbstr = L"pnpflag";
PWCHAR valuename = L"pnpstring";
PAGED_CODE();
//
// Set up QueryTable to do the following:
//
// Upgrade install flag
QueryTable[0].QueryRoutine = GetConfigValue;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = valuename;
QueryTable[0].EntryContext = GenericCompositeUSBDeviceString;
QueryTable[0].DefaultType = 0;
QueryTable[0].DefaultData = NULL;
QueryTable[0].DefaultLength = 0;
//
// Stop
//
QueryTable[1].QueryRoutine = NULL;
QueryTable[1].Flags = 0;
QueryTable[1].Name = NULL;
ntStatus = RtlQueryRegistryValues(
RTL_REGISTRY_CONTROL,
usbstr,
QueryTable, // QueryTable
NULL, // Context
NULL); // Environment
return ntStatus;
}
NTSTATUS GetConfigValue(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PWCHAR tmpStr;
switch (ValueType) {
// case REG_DWORD:
// *(PVOID*)EntryContext = *(PVOID*)ValueData;
// break;
// case REG_BINARY:
// RtlCopyMemory(EntryContext, ValueData, ValueLength);
// break;
case REG_SZ:
if (ValueLength) {
tmpStr = ExAllocatePool(PagedPool, ValueLength);
if (tmpStr) {
RtlZeroMemory(tmpStr, ValueLength);
RtlCopyMemory(tmpStr, ValueData, ValueLength);
*(PWCHAR *)EntryContext = tmpStr;
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
ntStatus = STATUS_INVALID_PARAMETER;
}
break;
default:
// TEST_TRAP();
ntStatus = STATUS_INVALID_PARAMETER;
}
return ntStatus;
}