我正在开发一个实用程序,以挂接不同应用程序使用的Windows API的各个部分。该项目的目的是,目前通过使用easyhook和boost(特别是property_tree库(将文件系统和注册表调用重定向到自定义位置,使任何应用程序都可以移植。
我目前正在该项目的注册表部分工作,我已经成功地创建了RegCreateKey(ExA/ExW/A/W(、RegOpenKey(ExA/ExW/A/W(和RegCloseKey函数的类似物,它们运行良好(我制作了一个虚拟句柄系统来创建和翻译hKey句柄(。它们的工作原理基本上是将所有内容转换为字符串,并将其保存在boost属性树中(然后将树写入.info文件(。
我开始研究RegSetValue和RegQueryValue函数,它们实际上处理数据,但遇到了一个主要问题。以下是两个函数。请注意,easyhook使用与原始winapi调用相同的参数来调用这些函数。
LSTATUS WINAPI myRegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
VirtualRegistry.put(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) + '\' + lpValueName), '\'), reinterpret_cast<const char*>(lpData));
boost::property_tree::write_info("VirtualRegistry.info", VirtualRegistry);
return ERROR_SUCCESS;
}
这适用于REG_SZ调用,但其他类型的数据没有正确保存。
LSTATUS WINAPI myRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
try
{
*lpData = reinterpret_cast<const BYTE*>VirtualRegistry.get_child(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) + "\" + lpValueName), '\')).data();
return ERROR_SUCCESS;
}
catch (const boost::property_tree::ptree_bad_path& e1)
{
std::cout << "n" << "ENTRY NOT FOUND" << "n";
return ERROR_FILE_NOT_FOUND;
}
}
这不起作用。第6行上的重新解释强制转换无效,因此无法编译。
问题是我的函数处理不同类型数据的方式。注册表调用可以有许多不同的值类型,而我编写myRegSetValue的方式似乎只适用于REG_SZ。在向文件写入调用时,我还必须保存值类型,但这并不能解决问题。
因此,我的问题是,是否有任何方法可以将调用的原始数据保存为字符串,而不必将其强制转换为字符串,以便它适用于所有类型的数据,然后从文件中从字符串中读取回原始数据并将其传递给应用程序?
我想我可以为每种键类型编写一个单独的解释器,但我真的不愿意这样做,因为这会非常棘手,也会破坏那些没有正确使用注册表API的应用程序,并在注册表中存储无效值(例如,Unity游戏Sunless Sea(。
谢谢你,我希望我对此解释得足够详细。
看起来真正的问题已经是myRegSetValueExA
的实现了。当您获得lpData
时,您不能假设它指向的数据将保持有效。您必须存储的不是指针,而是指向的数据。
这也是为什么cbData
是必要的;您需要知道要存储多少数据。您不能依赖strlen
,因为类型可能不是REG_SZ
。
请注意,您关于This works fine for REG_SZ
的假设是正确的,只是因为VirtualRegistry.put(std::string key, const char* value)
是一个方便的重载,它为您调用strlen(buf)
。
解决方案是显式创建std::string data(static_cast<const char*>(lpData), cbData)
并在put
中使用它。要检索它,请使用.get<std::string>(key)
而不是get_child(key).data()
。