0

こんにちは、よろしくお願いします。今日の問題は、レジストリ キーの値の名前と値のデータの文字列に「ガベージ」が返されることです。これは、最後の値を除くキー/フォルダー内のすべてのレジストリ値の問題のようですが、最初の値の名前を読み取ることができる場合があります (ただし、データは読み取れません)。

私がやろうとしているのは、単一の、おそらく可変のレジストリ キーにある値の名前と値のデータを表示できるようにすることです (この時点ではサブキーは気にしません)。これを Windows Unicode 文字列で実行しようとしています。 、WCHAR * および LPWSTR タイプ。問題のある文字列に見られる「ガベージ」は、英語以外の一連の文字が繰り返されているため、後続の wcout 表示が台無しになります。レジストリ エディターの表示で、読み取ろうとしている値には REG_SZ 型のデータがあり、これは文字列であると理解しています。

おそらく私の最大の問題は、自分がやろうとしていることを正確に実行する方法、レジストリ キーの内部を調べて、値の名前と値のデータを一覧表示する方法についての明確なガイドが見つからないことです。どんな助けでも大歓迎です。ユニコード文字列と 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 の文字数を取得するときに 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'\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 にはバッファーのサイズが含まれている必要がありますが、これは最初の値に対してのみ行われます。2 番目以降の値には、前の呼び出しの結果が含まれます。
  • レジストリ内の文字列値は、NULL で終了することが保証されていません。文字列を使用する前に、(返された長さを使用して) 文字列を明示的に終了する必要があります。Unicode を使用しているため、コード単位の長さを取得するには、バイト長を 2 で割る必要があることに注意してください。これらのコメントは、名前ではなく値にのみ適用されます。
  • DWORD ではない値はすべて文字列であると想定します。バイナリ値はどうですか?
于 2013-02-21T20:50:06.843 に答える