在已注册的类上出现“80041054未注册的类”错误。

5

我正在从非托管代码调用CoCreateInstance到一个已注册的托管类(HKEY_CLASSES_ROOT\CLSID{xxxxx-xxxxxx-xxxxxx-xxxxx-xxxxxx-xxxxx} 注册表项存在,并且文件从另一个程序正确加载)。

以下是代码:

    HRESULT hRC;
    CoInitialize(NULL);

    char* sUTProgID = "My.Utilities";

    CLSID UTClassID;
    hRC = CLSIDFromProgID(
        _CW(sUTProgID),             // Pointer to the ProgID
        &UTClassID );               // Pointer to the CLSID
    if ( S_OK != hRC )
    {
        DOTRACE((_T("    CLSIDFromProgID error 0x%X\n", hRC)));
    }
    IUnknown* pUnknown;
    hRC = CoCreateInstance(
    UTClassID,                  // Class identifier (CLSID) of the object
        0,                          // Pointer to whether object is or isn't part of an aggregate
        CLSCTX_ALL,                 // Context for running executable code
        IID_IUnknown,               // Reference to the identifier of the interface
        (void**) &pUnknown);        // Address of output variable that receives the interface pointer requested in riid
    if ( S_OK != hRC )
    {
    //code makes it here with an 80040145 class not registered error
    }

同样的代码也适用于其他应用程序。该代码是为x86编译的,并在x86机器上运行。

编辑:这是一个Windows XP机器,所以我认为UAC不适用。我已经记录了ClassID,并且确实是正确的。我还检查了ProcMon日志,显示成功访问了注册表键,并且在注册表键中访问了以下路径: InProcServer32-成功 InProcServerx86-找不到名称 LocalServer32-找不到名称 InProcHandler32-找不到名称 AppId-找不到名称 InProcServer32\ThreadingModel-成功 InProcServer32\1.0.0.0-成功 InProcServer32\1.0.0.0\assembly-缓冲区溢出 InProcServer32\1.0.0.0\assembly-成功 InProcServer32\1.0.0.0\class-成功 InProcServer32\1.0.0.0\RuntimeVersion-成功 InProcServer32\CodeBase-成功(返回文件路径)

然后检查GAC缓存,再访问几个目录,然后才能访问DLL。

CLIENT.EXE 1092 RegQueryKey HKCR\CLSID{...} SUCCESS查询:名称 CLIENT.EXE 1092 RegOpenKey HKCR\CLSID{...}\InprocHandler NAME NOT FOUND 所需访问权限:最大允许 CLIENT.EXE 1092 RegCloseKey HKCR\CLSID{9935FEE6-39FD-4EF0-87DB-8372B0992610} SUCCESS CLIENT.EXE 1092 RegOpenKey HKLM\Software\Policies\Microsoft\Windows\App Management NAME NOT FOUND 所需访问权限:查询值 CLIENT.EXE 1092 CreateFile LogFile.txt

我认为最后一个日志消息记录了错误。

编辑2: 使用以下代码注册Dll:

            Assembly asm = Assembly.LoadFile(dll_name);
            RegistrationServices regAsm = new RegistrationServices();
            bool bResult = regAsm.RegisterAssembly(asm,   AssemblyRegistrationFlags.SetCodeBase);

编辑3: 运行 CorFlags.exe 在(我的)失败的 DLL 上输出:

 Version   : v2.0.50727
 CLR Header: 2.5
 PE        : PE32
 CorFlags  : 11
 ILONLY    : 1
 32BIT     : 1
 Signed    : 1

在调用DLL的EXE上运行相同代码会输出:

 Version   : v1.1.4322
 CLR Header: 2.0
 PE        : PE32
 CorFlags  : 9
 ILONLY    : 1
 32BIT     : 0
 Signed    : 1

1
如果出现故障,那是因为它缺少所需的注册。这有多种原因:x86与x64(在此处看起来相似),以及安全性(注册表权限、UAC激活等)。我建议您使用Sysinternals Procmon来监视访问的注册表键。您应该能够找到问题所在。 - Simon Mourier
1
你应该使用DOTRACE跟踪CLSIDFromProgID返回的classid。也许不是你想要的那个。 - manuell
@manuell 感谢您的建议- 尝试了一下,但没有产生任何意外的结果。更新问题以反映最新情况。 - probably at the beach
2
这两个应用程序是否以相同的位数(32位或64位)运行?您的程序集标记为“Both”还是32/64特定? - acelent
1
还有几件事情需要检查:使用的 .net 运行时版本(尝试在配置中明确设置),检查 coinitializeEx 并查找公寓模型。 - Mikl X
显示剩余5条评论
1个回答

4
在运行 EXE 文件时出现了问题... 你遇到了 CLR 版本不匹配的问题。该 EXE 目标为 .NET 1.1,并将加载 v1.1 版本的 CLR。该版本无法加载 DLL,因为它的目标是 v2 版本的 CLR,即 .NET 2.0 到 3.5 中使用的版本。
一种解决方法是编写一个 .config 文件,强制使用正确版本的 CLR。将其与 .exe 文件放在同一目录中,并将其命名为 somefile.exe.config,将 "somefile" 替换为 .exe 文件的名称。
<configuration>
   <startup>
      <supportedRuntime version="v2.0.50757"/>
   </startup>
</configuration>

是的,感觉不错,谢谢你的帮助。不幸的是,调用exe第三方遗留代码并将其标记放入配置中会导致崩溃。还有其他解决方法吗? - probably at the beach
嗯,我至少能想到三种方法,其中没有一种涉及按下按钮来轻松解决你的问题。那个按钮已经被按了11年了,肯定已经完全磨损了。如果你想再次按下它,那么你必须比“它崩溃了”做得更好。 - Hans Passant
是的,我明白了,并且很抱歉没有提供有用的信息 - 我会尝试调试它。不幸的是,这是一台运行自助服务软件的生产机器,像资源管理器这样的有用工具都没有,所以这并不像应该那么简单。 - probably at the beach
感谢您的回答 - 我将其标记为正确并授予赏金,因为它确实帮助我解决了所提出的问题。 - probably at the beach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接