将 RegQueryValueEx 用于可能是 REG_DWORD 或 REG_SZ 的注册表值

Posted

技术标签:

【中文标题】将 RegQueryValueEx 用于可能是 REG_DWORD 或 REG_SZ 的注册表值【英文标题】:Using RegQueryValueEx for a registry value that could be REG_DWORD or REG_SZ 【发布时间】:2017-07-31 23:00:04 【问题描述】:

目前我正在使用RegQueryValueEx() 检索可能以REG_SZREG_DWORD 格式写入的注册表值。

BYTE byteArray[MAX];
DWORD dataSize = sizeof(byteArray);
DWORD type = 0;
RegQueryValueEx(
        hKey,
        subKey,
        nullptr,
        &type,
        reinterpret_cast<BYTE*>(&byteArray),
        &dataSize));

当我获得REG_SZ 值的数据(例如:“42314”)时,我得到以下响应:

byteArray   0x004fe6a8 "4"  unsigned char[100]
    [0] 52 '4'  unsigned char
    [1] 0 '\0'  unsigned char
    [2] 50 '2'  unsigned char
    [3] 0 '\0'  unsigned char
    [4] 51 '3'  unsigned char
    [5] 0 '\0'  unsigned char
    [6] 49 '1'  unsigned char
    [7] 0 '\0'  unsigned char
    [8] 52 '4'  unsigned char
    [9] 0 '\0'  unsigned char
    [10]0 '\0'  unsigned char

有什么办法不能让每个字符后面都有空字节吗?我认为这是因为每个角色都调用了RegEnumValue(),但我不确定。

【问题讨论】:

你在问什么? 它是 Unicode UTF16-LE 以 16bit 0 结尾 【参考方案1】:

您的问题与RegEnumValue()无关。

您的应用正在调用基于TCHARRegQueryValueEx(),它实际上是一个预处理器宏,它映射到RegQueryValueExA() (ANSI) 或RegQueryValueExW() (Unicode),具体取决于UNICODE 是否定义在编译时。

RegQueryValueExW() 将字符串数据作为 UTF-16LE 格式的 Unicode 文本返回,这正是您在缓冲区中看到的内容,因此很明显您的应用程序正在为 Unicode 编译。您看到的是完全正常的行为。

因此,您需要以提供给您的格式处理字符串数据,例如:

BYTE byteArray[MAX];
DWORD dataSize = sizeof(byteArray);
DWORD type = 0;
if (RegQueryValueEx( // <-- calling the TCHAR version!
    hKey,
    subKey,
    nullptr,
    &type,
    reinterpret_cast<BYTE*>(&byteArray),
    &dataSize) == 0)

    switch (type)
    
        case REG_DWORD:
        
            LPDWORD value = reinterpret_cast<LPDWORD>(&byteArray);
            // use *value as needed ...
            break;
        

        case REG_SZ:
        case REG_MULTI_SZ:
        case REG_EXPAND_SZ:
        
            // note the T in LPTSTR!  That means 'TCHAR' is used...
            LPTSTR text = reinterpret_cast<LPTSTR>(&byteArray);
            // use text as needed, up to (dataSize/sizeof(TCHAR)) number
            // of TCHARs. This is because RegQueryValueEx() does not
            // guarantee the output data has a null terminator.  If you
            // want that, use RegGetValue() instead...
            break;
        
    

或者:

BYTE byteArray[MAX];
DWORD dataSize = sizeof(byteArray);
DWORD type = 0;
if (RegQueryValueExW( // <-- calling the UNICODE version!
    hKey,
    subKey,
    nullptr,
    &type,
    reinterpret_cast<BYTE*>(&byteArray),
    &dataSize) == 0)

    switch (type)
    
        case REG_DWORD:
        
            LPDWORD value = reinterpret_cast<LPDWORD>(&byteArray);
            // use *value as needed ...
            break;
        

        case REG_SZ:
        case REG_MULTI_SZ:
        case REG_EXPAND_SZ:
        
            // note the W in LPWSTR!  That means 'WCHAR' is used...
            LPWSTR text = reinterpret_cast<LPWSTR>(&byteArray);
            // use text as needed, up to (dataSize/sizeof(WCHAR)) number
            // of WCHARs. This is because RegQueryValueExW() does not
            // guarantee the output data has a null terminator.  If you
            // want that, use RegGetValueW() instead...
            break;
        
    

如果您想要其他格式的文本,您必须:

    在将其读取为 Unicode 后将其转换为 Unicode,例如使用 WideCharToMultiByte() 或等价的。

    根据文档,直接使用RegQueryValueExA()(或RegGetValueA()),它将以用户当前语言环境中的ANSI文本形式返回字符串数据:

    如果数据具有REG_SZREG_MULTI_SZREG_EXPAND_SZ 类型,并且使用此函数的ANSI 版本(通过显式调用RegQueryValueExA 或在包含@987654338 之前不定义UNICODE @file),此函数将存储的 Unicode 字符串转换为 ANSI 字符串,然后再将其复制到 lpData 指向的缓冲区。

    BYTE byteArray[MAX];
    DWORD dataSize = sizeof(byteArray);
    DWORD type = 0;
    if (RegQueryValueExA( // <-- calling the ANSI version
        hKey,
        subKey,
        nullptr,
        &type,
        reinterpret_cast<BYTE*>(&byteArray),
        &dataSize) == 0)
    
        switch (type)
        
            case REG_DWORD:
            
                LPDWORD value = reinterpret_cast<LPDWORD>(&byteArray);
                // use *value as needed ...
                break;
            
    
            case REG_SZ:
            case REG_MULTI_SZ:
            case REG_EXPAND_SZ:
            
                // note the lack of T in LPSTR! That means 'char' is used...
                LPSTR text = reinterpret_cast<LPSTR>(&byteArray);
                // use text as needed, up to dataSize number of chars. This
                // is because RegQueryValueExA() does not guarantee the
                // output data has a null terminator.  If you want that,
                // use RegGetValueA() instead...
                break;
            
        
    
    

无论哪种方式,请注意,您将面临丢失您决定转换为的目标字符集中不存在的任何非 ASCII 字符的风险。因此,最好坚持使用 Unicode,并将缓冲区数据作为 WCHAR 数据处理(TCHAR 映射到 UNICODE 定义时的内容)。

【讨论】:

太棒了!我实际上想将它作为 DWORD 存储回来,所以现在我正在将它从 LPDWORD value = reinterpret_cast&lt;LPDWORD&gt;(&amp;byteArray); DWORD output = _ttoi(value); 转换如果有更有效的方法,请告诉我!我对这些类型的转化不太熟悉 您不能将REG_SZ 缓冲区转换为LPDWORD 指针(当然可以,但它没有意义),并且您不能传递LPDWORD 指针到_ttoi(),因为它需要一个空终止的TCHAR* 指针。并且RegQueryValueEx() 不保证空终止符将出现在输出缓冲区中。因此,请改用RegGetValue(),然后您可以使用LPTSTR text = reinterpret_cast&lt;LPTSTR&gt;(&amp;byteArray); DWORD value = _ttoi(text);

以上是关于将 RegQueryValueEx 用于可能是 REG_DWORD 或 REG_SZ 的注册表值的主要内容,如果未能解决你的问题,请参考以下文章

使用 RegQueryValueEx 将 reg_sz 作为输入并将其用作 char 数组

从 RegQueryValueEx 获取正确的值

RegQueryValueEx 返回 ERROR_SUCCESS 但它没有给我数据缓冲区。为啥?

RegQueryValueEx正确使用方法

使用 RegQueryValueEx 和 HKEY_PERFORMANCE_COUNTER 获取“Disk Bytes/sec%

RegQueryValueEx 的奇怪行为与另一个寄存器的返回值有关