为什么这个代码在具有多字节字符集的visual studio中完美运行,但是没有unicode字符集?

时间:2016-06-10 22:19:00

标签: c++ windows api

当我在g ++上运行此代码时,它运行顺利,但是当我在visual studio上使用unicode char set选项运行此代码时,它不会打印产品ID。 你能解释我如何解决这个问题以及它为什么会发生?

#include <windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

wchar_t* GetRegistryKeyValue(const char* RegKey, const char* pPIDName)
{
    HKEY        Registry;
    long        ReturnStatus;
    DWORD       regType = 0;
    DWORD       regSize = 0;
    char*       pPID = 0;
    ReturnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKey, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &Registry);
    if (ReturnStatus == ERROR_SUCCESS)
    {
        ReturnStatus = RegQueryValueEx(Registry, pPIDName, 0, &regType, 0, &regSize);
        pPID = new char[regSize];

        /* Get Value. */
        ReturnStatus = RegQueryValueEx(Registry, pPIDName, 0, &regType, (LPBYTE)pPID, &regSize);


        RegCloseKey(Registry);

        if (pPID[regSize] > 127 || pPID[regSize] < 32)
        {
            pPID[regSize] = '\0';
        }

        if (regSize > 1)
        {

            int s = 0;
            int i=0;
            while (pPID[i] != NULL)
            {
                s++;
                i++;
            }


            const size_t cSize = s ;
            wchar_t* wc = new wchar_t[cSize];
            mbstowcs(wc, pPID, cSize);  

            return wc;
        }
        else
        {
            printf("Size not > 1 (%d)\n", regSize);
            return NULL;
        }
    }
    else
    {
        RegCloseKey(Registry);
        return NULL;
    }
}
int main()
{
    wchar_t * resultData=NULL;  
    resultData = GetRegistryKeyValue("SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion", "ProductId");
    wcout << resultData;
    cout << endl;
    delete resultData;
    system("PAUSE");
    return 0;
}

2 个答案:

答案 0 :(得分:1)

在编译Unicode时编译MBCS和TCHAR数据时,您正在使用基于char*的依赖wchar_t*数据的API。您没有正确考虑这一差异。在为Unicode设置时,您的代码甚至不应该编译,因为您将ANSI参数传递给Unicode函数。由于您想要返回Unicode字符串,因此您应该首先使用Unicode API函数。

代码中还有其他逻辑错误,例如泄漏内存,没有为wc缓冲区分配正确的字节数,错误处理不足等等。

尝试更像这样的东西:

#include <windows.h>
#include <stdio.h>
#include <iostream>

using namespace std;

wchar_t* GetRegistryKeyValue(const wchar_t* RegKey, const wchar_t* pValueName)
{
    long        ReturnStatus;
    DWORD       regType = 0;
    DWORD       regSize = 0;
    DWORD dwFlags = RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ | RRF_RT_REG_EXPAND_SZ | RRF_SUBKEY_WOW6464KEY;
    wchar_t* ws = 0;

    ReturnStatus = RegGetValueW(HKEY_LOCAL_MACHINE, RegKey, pValueName, dwFlags, &regType, 0, &regSize);
    if (ReturnStatus == ERROR_SUCCESS)
    {
        ws = new wchar_t[regSize / sizeof(WCHAR)];

        ReturnStatus = RegGetValueW(HKEY_LOCAL_MACHINE, RegKey, pValueName, dwFlags, &regType, ws, &regSize);
        if (ReturnStatus != ERROR_SUCCESS)
        {
            delete[] ws;
            ws = NULL;
        }
    }

    return ws;
}

int main()
{
    wchar_t* resultData = GetRegistryKeyValue(L"SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion", L"ProductId");
    wcout << resultData << endl;
    delete[] resultData;
    system("PAUSE");
    return 0;
}

可替换地:

#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

wstring GetRegistryKeyValue(const wchar_t* RegKey, const wchar_t* pValueName)
{
    long        ReturnStatus;
    DWORD       regType = 0;
    DWORD       regSize = 0;
    DWORD dwFlags = RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ | RRF_RT_REG_EXPAND_SZ | RRF_SUBKEY_WOW6464KEY;

    ReturnStatus = RegGetValueW(HKEY_LOCAL_MACHINE, RegKey, pValueName, dwFlags, &regType, 0, &regSize);
    if (ReturnStatus == ERROR_SUCCESS)
    {
        vector<BYTE> buf;
        buf.resize(regSize);

        ReturnStatus = RegGetValueW(HKEY_LOCAL_MACHINE, RegKey, pValueName, dwFlags, &regType, &buf[0], &regSize);
        if (ReturnStatus == ERROR_SUCCESS)
            return wstring((wchar_t*)&buf[0], (regSize / sizeof(WCHAR)) - 1);
    }

    return wstring();
}

int main()
{
    wcout << GetRegistryKeyValue(L"SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion", L"ProductId") << endl;
    system("PAUSE");
    return 0;
}

答案 1 :(得分:0)

根据此文件:

http://www.cplusplus.com/reference/cstdlib/mbstowcs/

  

如果成功翻译了最大字符数,则存储在dest中的结果字符串不会以空值终止。

您尝试计算字符串长度的棘手方法(顺便说一下,可以用strlen(pPID)替换)将跳过第一个字符串中的'\0',因此结果可能没有最后'\0'。为什么不在那里使用regSize