无需管理特权扫描COM DLL注册表



我正在尝试创建一个程序来扫描com dll并创建必要注册表键的reg文件,而无需致电regsvr32,而不必具有管理权限。p>为此,我正在使用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 SUBKEY下。无需管理特权。

这是重建代码:

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_classes_root包含所有预期的键。但是hkey_current_user tempkey hklm(rempaped hkey_local_machine(仅包含我创建自己的空键"软件类"。它缺少DllRegisterServer应该创建的" Typelib"one_answers"接口"键。

这不是重新设计或权限问题,因为我可以在没有管理员权利的情况下在HKEY_LOCAL_MACHINE下创建空的"软件类"。

奇怪的是,在另一台计算机上测试dllRegisterserver失败了。

我还尝试调用LoadTypelib((和registertypelib((,我将获得错误代码" 0x8002801c错误访问OLE注册"。"

如果我然后重新启动Visual Studio作为管理员并再次运行该程序,我将获得所有预期的注册表密钥,包括HKLM下的注册表密钥。

关于为什么失败以及如何使此东西工作的任何想法?

我知道可以在无需担任管理员的情况下获取所有注册表键,因为Wix的Harvest Tool Heat.exe成功地做到了。我已经检查了他们的源代码,我相信我已经在做他们正在做的所有事情。而且我不想将WIX Toolset作为我的构建环境的要求,也只是因为我需要将其文件格式解析到 *.reg文件中。

我找到了解决方案:我们必须在进行重新映射之前调用函数oaenableperusertlibregistration((。

https://msdn.microsoft.com/en-us/library/windows/desktop/cc713570(v = vs.85(.aspx

调用该函数后,com dll的回调dllregisterserver((将尝试在HKCR下而不是HKLM下创建Typelib键。