【问题标题】:convert std::string to const BYTE* for RegSetValueEx()为 RegSetValueEx() 将 std::string 转换为 const BYTE*
【发布时间】:2010-10-25 08:53:32
【问题描述】:

我有一个获取 std::string 的函数。该函数调用

RegSetValueEx

第 5 个参数是注册表值,需要一个 const BYTE* 类型的变量。 所以我必须将 std::string 转换为 const BYTE* 并将结果数组的长度作为第 6 个参数。

我找到了一种方法,但感觉很难看,我真的不明白发生了什么。这是该功能的精简版:

void function(const std::string& newValue)
{
    HKEY keyHandle;
    if(RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("some key"),0,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
    {
        std::wstring wNewValue;
        wNewValue.assign(newValue.begin(),newValue.end());

        if (RegSetValueEx(keyHandle, TEXT("some value"), NULL, REG_SZ, (const BYTE*)(LPCTSTR)(wNewValue.c_str()), wNewValue.size()*2)==ERROR_SUCCESS)
        {
            //do something
        }
        RegCloseKey(keyHandle);
    }
}

如您所见,我首先制作一个宽字符串(定义了UNICODE),然后使用双重转换,并且对于长度我必须做*2,否则它只会设置输入字符串的一半。

这种形式的演员表是正常/最好的方式吗?

为什么是* 2,有什么更好的方法?

【问题讨论】:

  • 由于你使用了wstring,你知道底层类型是wchar_t,c_str()会返回wchar_t*。所以不需要转换为 LPCTSTR。

标签: c++ windows winapi stl registry


【解决方案1】:

您也可以将 unicode 字符串复制到字节数组中:

LPWSTR pData = L"SampleGrabber";
int dwSize = wcslen(pData)*sizeof(TCHAR);
BYTE slump[256];
memset((void*) slump, 0, 256*sizeof(BYTE));
memcpy((void*) slump, (const void *) pData, dwSize*sizeof(BYTE));

globit = RegSetValueEx(hKey, NULL, 0, REG_SZ, (const BYTE*) slump, dwSize);

如果您不幸为 WINCE 5.0 设备编写代码并且缺少部分 regedit API。

【讨论】:

    【解决方案2】:

    不应该是wNewValue.size()*2+2 吗?空字符的+2? MSDN 说:lpData 参数指向的信息的大小,以字节为单位。如果数据的类型为 REG_SZ、REG_EXPAND_SZ 或 REG_MULTI_SZ,cbData 必须包含终止空字符的大小。

    【讨论】:

      【解决方案3】:
      void function(const std::string& newValue)
      {
          HKEY keyHandle;
          if(RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("some key"),0,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
          {
      
              if (RegSetValueExA(keyHandle, "some value", NULL, REG_SZ, (const BYTE*)newValue.c_str(), newValue.size() + 1)==ERROR_SUCCESS)
              {
                      //do something
              }
              RegCloseKey(keyHandle);
          }
      }
      

      我删除了将字符串转换为 wstring 的部分,而是显式使用 ANSI 版本的 RegSetValueEx。

      引用 MSDN 中 RegSetValueEx 的评论:

      如果 dwType 是 REG_SZ,REG_MULTI_SZ, 或 REG_EXPAND_SZ 类型和 ANSI 使用此函数的版本 (或者通过显式调用 RegSetValueExA 或不定义 包含 Windows.h 之前的 UNICODE 文件),由指向的数据 lpData 参数必须是 ANSI 字符串。字符串是 转换为 Unicode 之前 存储在注册表中。

      另请注意,cbData 参数还应包括空终止的大小。

      【讨论】:

      • 如果您明确使用 ANSI 版本,则不应使用 TEXT() 宏,如果定义了 UNICODE,它将扩展为 L"foo"。
      • 所以只要我不使用任何非 ANSI 字符我就可以使用 ANSI 版本的 winapi 函数吗? (这似乎合乎逻辑,但我没有想到)
      • 需要文本的 Win32API 函数分为 ANSI(函数名中以 A 结尾)和 Unicode(以 W 结尾),反正大部分都是。所以你可以使用带有 A 的 std::string 和带有 W 的 std::wstring。
      • @ejac:如果您的输入包含(可能)ASCII 之外的字符,那么您的示例将不起作用,因为您正在使用wNewValue.assign(newValue.begin(), newValue.end()) 进行按位扩展。请记住,wNewValue 是一个 UNICODE 字符序列,因此仅当 newValue 中的所有字符点都是有效的 UNICODE 代码点时,按位分配才有效。换句话说,newValue 仅包含 ISO-8859-1 字符。
      【解决方案4】:

      * 2 是因为RegSetValueEx 想知道要写入的字节数,而 wstring 中的每个字符 (wchar_t) 都是两个字节宽。所以得到的字节数组的大小是原来的两倍!

      【讨论】:

      • 使用 "sizeof _TCHAR" insetad of 2 更便携。:-D
      • 所以最好写成 wNewValue.size()*sizeof(wchar_t) 来说明是怎么回事。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-11
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多