注册表枚举调用中的字符串/值失败



您好,提前感谢。我今天的问题是,我要为注册表项值名称和值数据的字符串返回"垃圾"。除了最后一个值之外,这似乎是一个注册表项/文件夹中所有注册表值的问题,尽管有时我可以读取第一个值的名称(但仍然不能读取数据)

我想做的是能够在一个可能是可变的注册表项中显示值名称和值数据(目前我不关心子项)我尝试使用windows unicode字符串、WCHAR*和LPWSTR类型来实现这一点。我在问题字符串中看到的"垃圾"是一系列重复的非英语字符,这会扰乱后续的wcout显示。在注册表编辑器显示中,我试图读取的值具有REG_SZ类型的数据,我认为它是一个字符串。

我最大的问题可能是,我找不到一个明确的指南,简单地介绍如何准确地完成我要做的事情,查看注册表项内部,并列出值名称和值数据。任何帮助都将不胜感激。我是unicode字符串和windows api的新手。我的环境是windowsxpsp3,visualc++2010express。

#include <stdio.h>
#include <iostream> /* for std::wcin and wcout */
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include "conio.h"
#
include "stdafx.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        int return_val;
        DWORD error;
        HKEY hkey;
        BYTE iterations = 0;
        /* 1. first, open key (folder) */
        return_val = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\DEVICEMAP\VIDEO", 0, KEY_READ, &hkey);
        /* check how the open went */
        if(return_val != ERROR_SUCCESS)
        {
            std::wcout << L"error opening the key: " << return_val << std::endl;
        }
        else
        {
            std::wcout << L"it's cool" << std::endl;
            /* 1.a. query the key (optional) */
            LPTSTR className = new WCHAR[255];
            DWORD classNameSize = MAX_PATH;
            DWORD subKey = 0; 
            DWORD maxSubKey;
            DWORD maxClass;
            DWORD value;
            DWORD maxValue;
            DWORD maxValueData;
            DWORD securityDescriptor;
            FILETIME ftLastWriteTime;
            DWORD sectionNameSize;
            return_val = RegQueryInfoKey(hkey, className, &classNameSize, NULL, 
                                        &subKey, &maxSubKey, &maxClass, &value, &maxValue, 
                                        &maxValueData, &securityDescriptor, &ftLastWriteTime);
            std::wcout << L"query return: " << return_val << std::endl;
            std::wcout << L"class name: " << className << L", (size): " << classNameSize << std::endl;
            std::wcout << L"subkey: " << subKey << L", max: " << maxSubKey << L", maxClass: " << maxClass << std::endl;
            std::wcout << L"Value: " << value << L", maxval: " << maxValue << L", maxvaldata: " << maxValueData << std::endl;
            std::wcout << L"Sec descrpt: " << securityDescriptor << std::endl << std::endl;
            /* now enumerate the strings in the key */
            int count = 0;
            DWORD valuename_size = 16, type_return = 0, data_size = 102;
            LPWSTR valuename = new WCHAR[valuename_size];//maxValue
            LPWSTR data = new WCHAR[data_size];//maxValueData>>1
            /* 2. the outer loop grabs the values one at a time (the data within the key/folder) */
            do {
                iterations++; /* just for debugging */
                return_val = RegEnumValue(hkey, count, valuename, &valuename_size, 0, &type_return, (LPBYTE)data, &data_size);
               /* return of RegEnumValue */
                std::wcout << L"RegEnumValue return val: " << return_val << std::endl;
                /* double check sizes */
                std::wcout << L"size: valname_size: " << valuename_size << L", data_size: " << data_size << std::endl;
                if(return_val == ERROR_SUCCESS || return_val == ERROR_MORE_DATA)
                {
                    /* to try and avoid bad strings */
                    if(type_return == REG_DWORD || count == 0)
                    std::wcout << L"Value - " << valuename << L", Type: " << type_return << L" Data - " << (BYTE)(*data) << std::endl;
                    else
                    std::wcout << L"Value - " << valuename << L", Type: " << type_return << L" Data - " << data << std::endl;
                }
                //data = REG_SZ;
                count++;
            } while (return_val != ERROR_NO_MORE_ITEMS && count < value);
        }
        /* just to check my code */
        std::wcout << L"iterations: " << iterations << std::endl;
        /* to "pause" during debugging */
        std::wcin >> input;
        return 0;
    }

这个版本部分基于评论者的帮助,似乎按照我的意愿运行,我发布这个供其他人参考。我不清楚的是,当为valuename返回字符数时,不包括null终止字符(当然),而且你传递到它的缓冲区大小需要包括这一点,所以如果你返回16并输入16,这就是为什么它会返回234,(不公平的是,输入遵循与输出不同的约束,但生活不公平),然后您需要为字符串大小的输入17

        /* now enumerate the strings in the key */
        int count = 0;
        DWORD valuename_size, type_return = 0, data_size;
        LPWSTR valuename;
        BYTE *data;
        /* 2. the outer loop grabs the values one at a time (the data within the key/folder) */
        do {
            valuename_size = maxValue;
            data_size = maxValueData;
            iterations++; /* just for debugging */
            return_val = RegEnumValue(hkey, count, NULL, &valuename_size, 0, &type_return, NULL, &data_size); /* value name */
            //return_val = RegEnumValue(hkey, count, NULL, NULL, 0, &type_return, NULL, &data_size); /* value data */
            valuename = new WCHAR[valuename_size+1];
            data = new BYTE[data_size]; /* data_size is in BYTES, of any type */
            valuename[0] = L''; /* if the string returned is still invalid, this will help make sure wcout doesnt mess up */
            return_val = RegEnumValue(hkey, count, valuename, &valuename_size, 0, &type_return, (LPBYTE)data, &data_size); /* value name */
            //return_val = RegEnumValue(hkey, count, NULL, NULL, 0, &type_return, (LPBYTE)data, &data_size); /* value data */
            /* return of RegEnumValue */
            std::wcout << L"RegEnumValue return val: " << return_val << std::endl;
            /* double check sizes */
            std::wcout << L"size: valname_size: " << valuename_size << L", data_size: " << data_size << L", Type: " << type_return << std::endl;
            if(return_val == ERROR_MORE_DATA /*&& type_return == REG_DWORD*/)
            {
                /* try again? */
                delete valuename;//free(valuename);
                delete data;
                /* double the "global" max number of WORDs for the string (including null termination) */
                maxValue <<= 1;
                valuename_size = maxValue;
                maxValueData <<= 1;
                data_size = maxValueData;
                /* doublecheck */
                std::wcout << L"new val size before enum: " << valuename_size << L", new data size before enum: " << data_size << std::endl;
                return_val = RegEnumValue(hkey, count, NULL, &valuename_size, 0, &type_return, NULL, &data_size); /* value name */
                /* the return version of valuename_size is the number of characters, not including the null terminating character */
                valuename = new WCHAR[valuename_size+1];
                data = new BYTE[data_size];
                valuename[0] = L''; /* if the string returned is still invalid, this will help make sure wcout doesnt mess up */
                return_val = RegEnumValue(hkey, count, valuename, &valuename_size, 0, &type_return, (LPBYTE)data, &data_size); /* value name */
                std::wcout << std::endl << L"return: " << return_val << L", Val size: " << valuename_size << L", data_size: " << data_size << std::endl << std::endl;
            }
            if(return_val == ERROR_SUCCESS)
            {
                valuename[valuename_size] = L''; /* null terminate the string before printing */
                /* I only care about string data */
                if (type_return == REG_SZ)
                {
                    data[data_size] = 0; /* null terminate the string before printing */
                    std::wcout << L"Value - " << valuename << L", Type: " << type_return << L" Data - " << (LPWSTR)data << std::endl;
                }
            }
            count++;
        } while (return_val != ERROR_NO_MORE_ITEMS && count < value);
    }
    /* just to check my code */
    std::wcout << L"iterations: " << iterations << std::endl;
    /* to "pause" during debugging */
    std::wcin >> input;
    return 0;
}

几个明显的问题:

  • 当您调用RegEnumValue时,valuename_size和data_size应该包含缓冲区的大小,但它们只对第一个值这样做。对于第二个值及其后的值,它们包含上一次调用的结果
  • 注册表中的字符串值不能保证以NULL结尾。在使用字符串之前,需要显式终止字符串(使用返回的长度)。请注意,由于您使用的是unicode,因此需要将字节长度除以2,以获得以代码为单位的长度。这些注释仅适用于值,而不适用于名称
  • 您假设任何不是DWORD的值都是字符串。二进制值呢

相关内容