- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试使用以下代码读取 Hardware\ResourceMap\System Resources\Physical Memory
中的物理内存值:
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <string>
#include <stdlib.h>
using namespace std;
int main()
{
HKEY hKey = NULL;
LPCTSTR pszSubKey = L"Hardware\\ResourceMap\\System Resources\\Physical Memory";
LPCTSTR pszValueName = L".Translated";
if (! RegOpenKey(HKEY_LOCAL_MACHINE, pszSubKey, &hKey) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}
DWORD dwType = 0;
LPBYTE lpData = NULL;
DWORD dwLength = 0;
if (! RegQueryValueEx(hKey, pszValueName, 0, &dwType, NULL, &dwLength) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}
lpData = new BYTE[dwLength];
RegQueryValueEx(hKey, pszValueName, 0, &dwType, lpData, &dwLength);
RegCloseKey(hKey);
DWORD dwResourceCount = *(DWORD*)(lpData + 16);
auto pmi = lpData + 24;
for (int dwIndex = 0; dwIndex < dwResourceCount; dwIndex++)
{
auto start = *(uint64_t*)(pmi + 0);
cout << "-> 0x" << hex << start;
auto length = *(uint64_t*)(pmi + 8);
cout << "\t + 0x" << hex << length;
auto endaddr = start + length;
cout << "\t0x" << hex << endaddr << endl;
pmi += 20;
}
delete[]lpData;
}
示例输出:
-> 0x1000 + 0x57000 0x58000
-> 0x59000 + 0x46000 0x9f000
-> 0x100000 + 0xc855f000 0xc865f000
-> 0xc8666000 + 0xbf3000 0xc9259000
-> 0xc9759000 + 0x13779000 0xdced2000
-> 0xdd0d8000 + 0x3c000 0xdd114000
-> 0xddfff000 + 0x1000 0xde000000
-> 0x100000000 + 0x41f0000 0x1041f0000
问题是最后的长度值不正确。
注册表编辑器显示 0x41f000000
是正确的值,而不是 0x41f0000
:
过去几天我一直在研究这个问题,但无法弄清楚为什么我在这里得到一个错误的值。
有更多使用 Win32 API 经验的人可以帮助我吗?
最佳答案
如果值类型是 REG_RESOURCE_LIST
值数据是 CM_RESOURCE_LIST
结构体。需要使用它来代替 *(DWORD*)(lpData + 16);
, lpData + 24
。无论如何,如果 Count
!= 1,您的代码是不正确的。您尝试打印的是 CM_PARTIAL_RESOURCE_DESCRIPTOR
结构。但您没有检查 CM_PARTIAL_RESOURCE_DESCRIPTOR
的 Type
成员。但它可能会有所不同。可以是 CmResourceTypeMemory
也可以是 CmResourceTypeMemoryLarge
- 你没有考虑到这一点。如果 CmResourceTypeMemoryLarge
需要检查 Flags
CM_RESOURCE_MEMORY_LARGE_40
CM_RESOURCE_MEMORY_LARGE_48
CM_RESOURCE_MEMORY_LARGE_64
和
你说:
Instead of 0x41f0000 the regeditor shows 0x41f000000
但是 0x41f000000
移动了 8 位 0x41f0000
。基于这一点,您确实在此处拥有带有 CM_RESOURCE_MEMORY_40
标志的 CmResourceTypeMemoryLarge
。
在这种情况下需要使用Length40成员:
The high 32 bits of the 40-bit length, in bytes, of the range of allocated memory addresses. The lowest 8 bits are treated as zero.
因此转储 CM_RESOURCE_LIST
的代码必须是下一个:
BOOL Memory(PCM_RESOURCE_LIST pcrl, ULONG size)
{
if (size < FIELD_OFFSET(CM_RESOURCE_LIST, List))
{
return FALSE;
}
size -= FIELD_OFFSET(CM_RESOURCE_LIST, List);
if (ULONG Count = pcrl->Count)
{
PCM_FULL_RESOURCE_DESCRIPTOR List = pcrl->List;
do
{
if (size < FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors))
{
return FALSE;
}
size -= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
DbgPrint("InterfaceType=%x BusNumber=%u\n", List->InterfaceType, List->BusNumber);
if (ULONG n = List->PartialResourceList.Count)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors = List->PartialResourceList.PartialDescriptors;
do
{
if (size < sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))
{
return FALSE;
}
size -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
ULONG64 Length = PartialDescriptors->u.Memory.Length;
switch (PartialDescriptors->Type)
{
case CmResourceTypeMemoryLarge:
switch (PartialDescriptors->Flags & (CM_RESOURCE_MEMORY_LARGE_40|
CM_RESOURCE_MEMORY_LARGE_48|CM_RESOURCE_MEMORY_LARGE_64))
{
case CM_RESOURCE_MEMORY_LARGE_40:
Length <<= 8;
break;
case CM_RESOURCE_MEMORY_LARGE_48:
Length <<= 16;
break;
case CM_RESOURCE_MEMORY_LARGE_64:
Length <<= 32;
break;
default:
DbgPrint("unknown mamory type\n");
continue;
}
case CmResourceTypeMemory:
DbgPrint("%016I64x %I64x\n",
PartialDescriptors->u.Memory.Start.QuadPart, Length);
break;
}
} while (PartialDescriptors++, --n);
}
} while (List++, --Count);
}
return size == 0;
}
同样,当我们获取数据时 - 即使出现错误也无需忘记关闭 key 句柄(当 RegQueryValueEx
失败时您不会这样做)并使用 RegOpenKeyExW
代替 RegOpenKey
对于 ability 指定所需的 key 访问权限。使用 2 个顺序调用 RegQueryValueEx
(使用 0 个缓冲区并分配一次缓冲区)也不是最好的。因为理论上缓冲区大小可以在这 2 次调用之间更改(某些更改值),并且您也可能无法在第二次调用 RegQueryValueEx
时获取数据。我们也可以在第一次调用时分配合理的内存空间,并且只有在内存空间不够时 - 在下次调用时重新分配。所以最好在循环中调用它,直到我们得到 ERROR_MORE_DATA
并且第一次调用已经不为空的缓冲区:
ULONG Memory()
{
HKEY hKey;
ULONG dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Hardware\\ResourceMap\\System Resources\\Physical Memory",
0, KEY_READ, &hKey);
if (dwError == NOERROR)
{
ULONG cb = 0x100;
do
{
dwError = ERROR_NO_SYSTEM_RESOURCES;
union {
PVOID buf;
PBYTE pb;
PCM_RESOURCE_LIST pcrl;
};
if (buf = LocalAlloc(0, cb))
{
ULONG dwType;
if ((dwError = RegQueryValueExW(hKey, L".Translated",
0, &dwType, pb, &cb)) == NOERROR)
{
if (dwType == REG_RESOURCE_LIST)
{
if (!Memory(pcrl, cb))
{
DbgPrint("error parsing resource list\n");
}
}
else
{
dwError = ERROR_INVALID_DATATYPE;
}
}
LocalFree(buf);
}
} while (dwError == ERROR_MORE_DATA);
RegCloseKey(hKey);
}
return dwError;
}
关于c++ - 读取 REG_RESOURCE_LIST 内存值 - 不正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48485364/
我正在尝试使用以下代码读取 Hardware\ResourceMap\System Resources\Physical Memory 中的物理内存值: #include #include #in
我是一名优秀的程序员,十分优秀!