【问题标题】:Issue with converting a filesystem path to a const BYTE*将文件系统路径转换为 ​​const BYTE* 的问题
【发布时间】:2021-02-15 12:34:49
【问题描述】:

我想要实现的是使用注册表在 Windows 启动时执行我的程序。当我尝试放置文件位置时,编译器抱怨它无法从filesystem::path 转换为const BYTE*。我不知道如何解决这个问题,因为我是 C++ 的初学者。我提供了以下代码:

HKEY newValue;
RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &newValue);
RegSetValueEx(newValue, "myprogram", 0, REG_SZ, fs::temp_directory_path().append(filename), sizeof("tes3t")); // This line is the issue. fs::temp_directory_path().append(filename)
RegCloseKey(newValue);
return 0;

例外:不存在从“std:filesystem::path”到“const BYTE *”的合适转换函数

【问题讨论】:

  • 帮自己一个忙,将所需的值存储到中间变量中。然后,您将轻松地将路径操作与注册表访问函数调用分开。
  • 对不起,但就像我之前所说的,我对 c++ 很陌生,我不知道你的意思是什么,我更像是一个视觉人。你能举个例子吗?
  • 他的意思是你把太多东西塞进了太小的空间。如果您单独执行每个步骤,将结果存储到临时变量中,您可以更轻松地准确查看问题所在。隔离错误后,修复错误通常很容易。

标签: c++ winapi filesystems c++17 registry


【解决方案1】:

根据RegSetValueExA() documentation,该函数不接受std::filesystem::path 对象。这就是错误消息所抱怨的内容。

LSTATUS RegSetValueExA(
  HKEY       hKey,
  LPCSTR     lpValueName,
  DWORD      Reserved,
  DWORD      dwType,
  const BYTE *lpData, // <-- here
  DWORD      cbData
);

第 5 个参数采用 const BYTE* 指向 以空结尾的 C 样式字符串的指针。第6个参数取字符串中的字符数,包括空终止符:

lpData

要存储的数据。

对于基于字符串的类型,例如 REG_SZ,字符串必须以 null 结尾。对于 REG_MULTI_SZ 数据类型,字符串必须以两个空字符结束。

注意lpData表示空值是有效的,但是,如果是这种情况,cbData必须设置为'0'。

cbData

lpData 参数指向的信息的大小,以字节为单位。 如果数据的类型为 REG_SZ、REG_EXPAND_SZ 或 REG_MULTI_SZ,cbData 必须包含终止空字符的大小

std::filesystem::path 没有到const BYTE*隐式 转换,因此会出现编译器错误。您需要先显式path 转换为std::stringstd::wstring(首选后者,因为注册表在内部将字符串存储为Unicode),然后才能将该字符串值保存到注册表,例如:

// using std::string...

HKEY newValue;

// don't use RegOpenKey()! It is provided only for backwards compatibility with 16bit apps...
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_SET_VALUE, &newValue) == 0)
{
    // this may lose data for non-ASCII characters!
    std::string s = fs::temp_directory_path().append(filename).string();

    // this will convert the ANSI string to Unicode for you...
    RegSetValueExA(newValue, "myprogram", 0, REG_SZ, reinterpret_cast<LPCBYTE>(s.c_str()), s.size()+1);

    RegCloseKey(newValue);
}

return 0;
// using std::wstring...

HKEY newValue;

// don't use RegOpenKey()! It is provided only for backwards compatibility with 16bit apps...
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_SET_VALUE, &newValue) == 0)
{
    // no data loss here!
    std::wstring s = fs::temp_directory_path().append(filename).wstring();

    // no ANSI->Unicode conversion is performed here...
    RegSetValueExW(newValue, L"myprogram", 0, REG_SZ, reinterpret_cast<LPCBYTE>(s.c_str()), (s.size()+1) * sizeof(WCHAR));

    RegCloseKey(newValue);
}

return 0;

【讨论】:

  • 您好!非常感谢你帮我解决这个问题......我有点难过,我不理解代码......但我学习了......最终。我接受这个作为答案,因为您为我提供了 2 个解决方案,并且您提供了有关它为什么不起作用的信息。这是非常有话题的,我只想问看不懂代码是否正常?因为它让我觉得自己很愚蠢啊哈,再次感谢。编辑:我不明白的行“reinterpret_cast
  • 这是半正常的,但很危险。如果您不了解代码,则无法在代码中断时对其进行修复。你需要以一种你能理解的方式来描述问题,通常是这样做by making smaller problems,并一次解决一个较小的问题..
  • @JakeNiledon LPCBYTE 只是 const BYTE* 的别名。 reinterpret_cast 是因为 std::(w)string::c_str() 返回一个 const char*/const wchar_t*,它必须从一种类型转换为另一种类型。
【解决方案2】:

WinAPI 函数不接受 std::filesystem::path 类型的参数,因此您需要以某种方式将其转换为 const BYTE*

这是一个例子:

std::string fullpath = (fs::temp_directory_path() / filename).string();

RegSetValueEx(
    newValue,
    "myprogram",
    0,
    REG_SZ,
    reinterpret_cast<LPCBYTE>(fullpath.c_str()), // returns a "const char*" then cast
    fullpath.size() + 1  // + 1 for null terminator
);

【讨论】:

    猜你喜欢
    • 2010-11-17
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多