我试图创建一个扫描COM dll并创建必要注册表项的reg文件的程序,而不必调用regsvr32而不必拥有管理权限。
为此,我使用RegOverridePredefKey重新映射HKEY_CURRENT_USER子项中的Windows注册表配置单元。
https://msdn.microsoft.com/pt-br/library/windows/desktop/ms724901(v=vs.85).aspx
重新映射正在运行。我知道,因为我可以,例如,调用一个Windows api函数在HKEY_LOCAL_MACHINE下创建一个虚假的注册表项,它实际上出现在我的HKEY_CURRENT_USER子项下。无需管理员权限。
这是重新映射的代码:
if (reg::remapRegistry(HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, basekey + "hkcr"))
{
if (reg::remapRegistry(HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, basekey + "hklm"))
{
if (reg::remapRegistry(HKEY_USERS, HKEY_CURRENT_USER, basekey + "hku"))
{
if (reg::remapRegistry(HKEY_CURRENT_USER, HKEY_CURRENT_USER, basekey + "hkcu"))
{
reg::createKey(HKEY_LOCAL_MACHINE, "Software\\Classes");
reg::createKey(HKEY_CURRENT_USER, "Software\\Classes");
ret = scan(args);
reg::cancelRemapedRegistry(HKEY_CURRENT_USER);
}
reg::cancelRemapedRegistry(HKEY_USERS);
}
reg::cancelRemapedRegistry(HKEY_LOCAL_MACHINE);
}
reg::cancelRemapedRegistry(HKEY_CLASSES_ROOT);
}
我的扫描功能的args参数只是一个带有我的dll路径的结构。 reg :: 函数只是围绕windows api的包装。
这是我的扫描功能:
int scan(const Args &args)
{
typedef HRESULT (__stdcall *pDllRegisterServer) (void);
try
{
HMODULE hDLL = LoadLibrary(args.dll.c_str());
if (hDLL == NULL)
{
LOGERROR("Cannot load dll");
return 1;
}
pDllRegisterServer DllRegisterServer = (pDllRegisterServer) GetProcAddress(hDLL, "DllRegisterServer");
if (DllRegisterServer == NULL)
{
LOGERROR("Cannot find function DllRegisterServer in dll");
FreeLibrary(hDLL);
return 2;
}
HRESULT res = DllRegisterServer();
DWORD err = GetLastError();
switch (res)
{
case S_OK:
LOGINFO("successfully called DllRegisterServer");
return 0;
case SELFREG_E_TYPELIB:
LOGERROR("DllRegisterServer error SELFREG_E_TYPELIB");
return 3;
case SELFREG_E_CLASS:
LOGERROR("DllRegisterServer error SELFREG_E_CLASS");
return 4;
case E_OUTOFMEMORY:
LOGERROR("DllRegisterServer error E_OUTOFMEMORY");
return 5;
case E_UNEXPECTED:
LOGERROR("DllRegisterServer error E_UNEXPECTED");
return 6;
default:
LOGERROR("DllRegisterServer really unexpected error");
}
return 7;
}
catch (...)
{
LOGERROR("unknown error loading dll or function");
return -1;
}
}
DllRegisterServer返回S_OK,但只创建了一半的注册表项。我在HKEY_CURRENT_USER \ tempkey \ hkcr下重新映射的HKEY_CLASSES_ROOT包含所有预期的键。但HKEY_CURRENT_USER \ tempkey \ hklm(重映射HKEY_LOCAL_MACHINE)仅包含空键" Software \ Classes"我自己创造的。它缺少" TypeLib"和"界面" DllRegisterServer应该创建的密钥。
这不是重映射或权限问题,因为我可以创建空的" Software \ Classes"在没有管理员权限的HKEY_LOCAL_MACHINE下。
奇怪的是,使用SELFREG_E_TYPELIB在另一台机器上测试DllRegisterServer失败。
我也尝试调用LoadTypeLib()和RegisterTypeLib(),我得到了错误代码" 0x8002801c访问OLE注册表时出错。"
如果我以管理员身份重新启动visual studio并再次运行该程序,我将获得所有预期的注册表项,包括HKLM下的注册表项。
关于为什么会失败以及如何让这件事发挥作用的任何想法?
我知道可以在不成为管理员的情况下获取所有注册表项,因为wix的收获工具heat.exe成功完成了。我已经检查了他们的源代码,我相信我已经做了他们正在做的所有事情。而且我不希望将wix工具集作为构建环境的一项要求,这也是因为我需要将其文件格式解析为* .reg文件。
答案 0 :(得分:0)
我找到了解决方案:在进行重映射之前,我们必须调用函数OaEnablePerUserTLibRegistration()。
https://msdn.microsoft.com/en-us/library/windows/desktop/cc713570(v=vs.85).aspx
调用该函数后,来自COM dll的回调DllRegisterServer()将尝试在HKCR而不是HKLM下创建类型库键。