0

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

我正在尝试做的是能够显示单个可能变量注册表项中的值名称和值数据(此时我不关心子项)我正在尝试使用 windows unicode 字符串执行此操作, WCHAR * 和 LPWSTR 类型。我看到的问题字符串的“垃圾”是一系列重复的非英文字符,这会弄乱随后的 wcout 显示。在注册表编辑器显示中,我尝试读取的值具有 REG_SZ 类型的数据,我理解它是一个字符串。

可能我最大的问题是我找不到一个明确的指南来简单地说明如何做我正在尝试做的事情,查看注册表项,并列出值名称和值数据。任何帮助将不胜感激。我是 unicode 字符串和 windows api 的新手。我的环境是windows xp sp3,visual c++ 2010 express。

#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 的字符数时,不包括空终止字符(当然),而且你传递给它的缓冲区的大小需要包括它,所以如果你返回 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'\0'; /* 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'\0'; /* 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'\0'; /* 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;
}
4

1 回答 1

0

几个明显的问题:

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