列举Windows注册表项中的所有子键和值
Enumerating all subkeys and values in a Windows registry key
我正在尝试编写一个Windows应用程序,该应用程序可以让我返回给定某个键的所有子键和值。我编写的代码似乎可以在给定键内提供子键,但不能正确枚举值;它成功地枚举了不带值的子键,并以选项卡树的形式返回结果。但是,在枚举值时,程序会为每个存在的值返回一个随机值(每次都是相同的随机值),然后崩溃并出现调试错误。
它的预期输出基本上是:
(1) KEY
(1) SUBKEY
(1) SUBKEYWITHINSUBKEY
Code: value1data
Code: value2data
Code: value3data
(2) SUBKEY
(1) SUBKEYWITHINSUBKEY
(3) SUBKEY
…等等。
我得到的输出是这样的:(1) KEY
(1) SUBKEY
(1) SUBKEYWITHINSUBKEY
Code: someValue
Code: someValue
Code: someValue
(…然后崩溃)
之后会出现以下错误:
"调试错误!"运行时检查失败#2 -变量'valNameLen'周围的堆栈已损坏。"
代码现在有点乱(我是一个Windows API新手),但是如果有人能告诉我我做错了什么,或者以任何他们认为合适的方式批评我的编码风格,那将是伟大的。
谢谢!
- r
/*
Windows Registry Subkey Enumeration Example
Based on example found at code-blue.org
*/
#include <windows.h>
#include <stdio.h>
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD dataType;
DWORD data;
DWORD dataSize;
for (int i = 0; i < numValues; i++)
{
RegEnumValue(hKey,
dwIndex,
valueName,
&valNameLen,
NULL,
&dataType,
(BYTE*)&data,
&dataSize);
dwIndex++;
printf("Code: 0x%08Xn", data);
}
}
void EnumerateSubKeys(HKEY RootKey, char* subKey, unsigned int tabs = 0)
{
HKEY hKey;
DWORD cSubKeys; //Used to store the number of Subkeys
DWORD maxSubkeyLen; //Longest Subkey name length
DWORD cValues; //Used to store the number of Subkeys
DWORD maxValueLen; //Longest Subkey name length
DWORD retCode; //Return values of calls
RegOpenKeyEx(RootKey, subKey, 0, KEY_ALL_ACCESS, &hKey);
RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&maxSubkeyLen, // longest subkey length
NULL, // longest class string
&cValues, // number of values for this key
&maxValueLen, // longest value name
NULL, // longest value data
NULL, // security descriptor
NULL); // last write time
if(cSubKeys>0)
{
char currentSubkey[MAX_PATH];
for(int i=0;i < cSubKeys;i++){
DWORD currentSubLen=MAX_PATH;
retCode=RegEnumKeyEx(hKey, // Handle to an open/predefined key
i, // Index of the subkey to retrieve.
currentSubkey, // buffer to receives the name of the subkey
¤tSubLen, // size of that buffer
NULL, // Reserved
NULL, // buffer for class string
NULL, // size of that buffer
NULL); // last write time
if(retCode==ERROR_SUCCESS)
{
for (int i = 0; i < tabs; i++)
printf("t");
printf("(%d) %sn", i+1, currentSubkey);
char* subKeyPath = new char[currentSubLen + strlen(subKey)];
sprintf(subKeyPath, "%s\%s", subKey, currentSubkey);
EnumerateSubKeys(RootKey, subKeyPath, (tabs + 1));
}
}
}
else
{
EnumerateValues(hKey, cValues);
}
RegCloseKey(hKey);
}
int main()
{
EnumerateSubKeys(HKEY_CURRENT_USER,"SOFTWARE\MyKeyToSearchIn");
return 0;
}
以这种方式枚举键是多余的。这只会浪费系统资源、内存、调用堆栈,并给注册表子系统带来压力。除非必要,否则不要这样做。
你打算在你的应用程序中有"搜索注册表"吗?如果是,则仅在用户要求时枚举。或者,如果您正在开发"注册表查看器/编辑器",请仅在需要时展开和打开子键。
如果你绝对需要检索和存储所有的键/值,你可以使用多个线程来枚举键。线程的数量最初将是hkey -major-key,然后您可以有更多的线程,这取决于子键的数量和您在枚举键时执行的运行时启发式。
递归可能是也可能不是子键"递归枚举"的好方法-你必须保持递归实现的参数数量最少-将参数放入一个struct
或将它们放在类中。您可能也喜欢使用std::stack
进行相同的操作。
似乎您正在调用RegEnumValue()而没有将lpcchValueName参数设置为适当的值。该参数既是[in]参数,也是[out]参数。试试这个:
for (int i = 0; i < numValues; i++)
{
DWORD valNameLen = 64; //added this line to match valueName buffer size
RegEnumValue(hKey,
dwIndex,
valueName,
&valNameLen,
NULL,
&dataType,
(BYTE*)&data,
&dataSize);
RegEnumValue()的文档:http://msdn.microsoft.com/en-us/library/ms724865(v=vs.85).aspx
我在一个具有少量子键的键上尝试了您的代码。
在函数EnumerateValues
中,调用RegEnumValue
一次后,numValues
的值被一些随机的垃圾填充。解决方案是将RegEnumValue
的参数更改为
RegEnumValueA(hKey,
dwIndex,
valueName,
&valNameLen,
nullptr,
nullptr,
nullptr,
nullptr);
这是最后的函数,
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD numback = numValues;
for (int i = 0; i < numValues; i++)
{
// printf("%lu, %dn", numValues, i);
RegEnumValueA(hKey,
dwIndex,
valueName,
&valNameLen,
nullptr,
nullptr,
nullptr,
nullptr);
dwIndex++;
if (i > numback)
{
RegCloseKey(hKey);
printf("Inf loop exiting...n");
exit(-1);
}
// printf("Code: 0x%08X, %lu, %dn", data, numValues, i);
// printf("Code: %lu, %dn", numValues, i);
}
RegCloseKey(hKey);
}
我修复了你的代码并将其发布在github上。
主要问题是你需要创建自己的缓冲区并将数据指向它,并且还需要在调用RegEnumValue之前设置dataSize。除此之外,如果您以所有权限调用RegOpenKeyEx,那么如果没有用户提升(admin),该程序将无法运行,因此我将它们更改为只读。
- 在具有 std::p air 键和值的映射中添加 b2vec2
- 如何将键和值从映射传输到另一个映射?
- std::在地图上查找无法正常工作并循环访问地图的键和值
- 如何通过键和值以及在C 中的结果映射中比较两个地图?我们有任何STL API吗?
- 多重映射的每个元素是否同时包含键和值
- 如何正确使用带有智能指针和自定义类的映射作为键和值
- 如何使用 boost 连接映射的键和值,特别是如果值是结构
- 对象来映射键和值
- 我的代码到底在哪里不符合键和值类型的规范
- 比较键和值 std::maps
- C++STL映射键和值工作不正常
- Lua 访问表的键和值
- 当我使用 std::map 从文件中读取值时,该值会随之",",因为键和值用逗号分隔
- 是否可以在C++中使用命名变量(例如,键和值)而不是 .first 和 .second 进行 std::map<> "for element : container" 迭代?
- 使用C++中的函数指针映射枚举键和值
- 从变量映射键和值初始化
- 键和值属于同一类型的多重映射是否有任何意义
- 如何在C++中创建将键和值作为结构的映射
- 如何使用 boost 对键和值进行排序
- 列举Windows注册表项中的所有子键和值