【发布时间】:2021-10-25 22:38:27
【问题描述】:
我们有一个 .NET DLL,其中包含合作伙伴公司可以使用的多个 COM 类和对象。我们目前使用regasm 在注册表中注册COM 类。这已经工作了多年。
我们现在想摆脱 COM 注册并使用side by side assemblies。我目前正在尝试进行这种过渡,但我似乎在终点线上失败了。我们提供了一个使用我们的 COM 类的 C++ 示例应用程序,我尝试让它在没有 COM 注册的情况下运行。
.NET DLL
在我们的 .NET DLL 中,我有一个这样的类:
namespace MyNamespace
{
[ComVisible(true)]
[Guid("ef828ade-b459-4446-80db-956715588601")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyVendor.MyClass")]
public partial class MyClass
{
}
}
应用程序组装
应与该 COM 类一起使用的 C++ 示例应用程序具有如下清单:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"
uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
DLL 程序集
而且 .NET DLL 本身有一个清单来将 COM 类暴露给外界:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
<file name="MyComDll.dll">
<comClass description="MyVendor.MyClass"
clsid="{ef828ade-b459-4446-80db-956715588601}"
progid="MyVendor.MyClass.1"
threadingModel="Both">
<progid>MyVendor.MyClass</progid>
</comClass>
</file>
</assembly>
使用 COM
我显然在上面的代码示例中使用了代理名称,但我确保原始代码中的所有名称都是有效的。
在我们的示例 C++ 代码中,我们以这种方式获取 CLSID 并创建类的实例:
HRESULT hr = CLSIDFromProgID(OLESTR("MyVendor.MyClass"), &clsid);
hr = CoCreateInstance(clsid, nullptr, CLSCTX_SERVER, IID_IDispatch, (void**)(&_pMyClass));
出了什么问题
我使用一些调试输出来检查从CLSIDFromProgID() 返回的 GUID 并检查返回值。如果 COM 类是使用regasm 注册的,则返回值为S_OK,clsid 与我在 .NET DLL 中为该类指定的 GUID 相同。
但是,如果我删除 COM 注册并使用带有清单的并行程序集,如上所示,我也会得到 S_OK 返回值,但 GUID 完全不同,因此我无法创建这节课。我在任何地方都没有找到从 CLSIDFromProgID() 获得的 GUID - 无论是在注册表中还是在我的开发解决方案中。
你知道我做错了什么吗?
- 我知道我的 C++ 示例应用程序通常可以很好地处理我们的 COM 对象,因为如果注册了 COM 类,它就可以完美运行。
- 我检查了我使用 Microsoft's specification 和各种指南创建的清单的每个部分。
- 我在 Windows 事件日志中没有收到任何 SideBySide 错误,因此我知道清单格式正确。
- 我确实从
CLSIDFromProgID()得到了一个S_OK,所以我知道找到了 ProgID - 它只是提供了错误的 CLSID。 - 我使用函数
StringFromCLSID()来比较由`CLSIDFromProgID() 找到的CLSID。
【问题讨论】:
-
在调用
CLSIDFromProgID()时使用MyVendor.MyClass.1而不是MyVendor.MyClass是否也有同样的问题?或者如果您将清单中的progid设置为MyVendor.MyClass而不是MyVendor.MyClass.1? -
您的“COM”组件实际上是一个 .NET 程序集,对吗?您使用 comClass 而不是 clrClass 是否有原因?要通过清单向 COM 公开 .NET 程序集,我认为您应该改用 clrClass ???
-
使用 sysinternals 中的 Procmon,按注册表访问和您的 .exe 进行过滤,您应该会看到该 guid 的来源。
-
@Endgegner85 你看到这篇解释现象的文章了吗:manifestmaker.com/sxs/help/confclsid.htm