3

我正在使用这个 exe com 服务器:

https://cfx.svn.codeplex.com/svn/Visual%20Studio%202008/CSExeCOMServer/ExeCOMServer.cs

  • 我的 prog 是一个 com 应用程序
  • 我的 com 方法采用另一个 com 对象是void Init(AppsScriptRunningContext rc);
  • 在这种方法中,我尝试读出一个属性并得到这个错误

无法将“AppsScriptLib.AppsScriptRunningContextClass”类型的 COM 对象转换为接口类型“AppsScriptLib.IAppsScriptRunningContext”。此操作失败,因为 IID 为“{4D2E5723-87C2-49C1-AA28-ED2D88275100}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:不支持此类接口(来自 HRESULT 的异常:0x80004002 (E_NOINTERFACE))

如果我的应用程序不是 com 服务器而是普通的 com 应用程序,则没有错误。这就是为什么我认为错误是由 exe com 服务器产生的。

https://cfx.svn.codeplex.com/svn/Visual%20Studio%202008/CSExeCOMServer/ExeCOMServer.cs

问候,克里斯

4

2 回答 2

7

这是一个非常令人遗憾的代码示例,成功的几率非常接近于零。它是 MSDN 论坛支持小组的产品,他们的工作未在 Microsoft 进行同行评审。一名团队成员后来承认这不是正确的做法。

该代码的一个问题是它完全忽略了 MSDN 文档中关于 RegistrationServices.RegisterTypeForComClients() 方法的备注:

请注意,不支持使用平台调用调用非托管 CoRegisterClassObject 和 CoDisconnectObject 方法注册和注销 COM 对象。

不幸的是,没有解释为什么不支持它。关键问题是 COM 接口总是需要在进程外激活情况下进行编组。这是通过在客户端创建一个代理来完成的,该代理具有与原始接口相同的所有方法,但其实现的方法通过 RPC 将方法的参数发送到另一个进程。在服务器端,存根执行相同但相反的角色,使用方法参数构建堆栈框架并进行实际的方法调用。

在 .NET 中创建代理和存根非常容易,反射使它变得简单。由框架中内置的 Remoting 管道完成。然而这在 COM 中并不容易,它没有任何类似于反射的东西。它有两种基本的实现方式,第一种是用 IDL 语言编写 COM 接口定义,然后用 midl.exe 编译它。它可以自动生成执行编组的 C 源代码,您可以从中构建 DLL。然后需要在 HKCR\Interface 注册表项中正确注册该 DLL,以便 COM 可以在需要封送接口时找到并加载 DLL。如果您的接口派生自 IDispatch 并将其自身限制为与 OLE 自动化兼容的参数类型,则可以使用第二种方法。然后,您可以生成类型库并使用标准编组器。

这是 .NET 进程外服务器中不会​​发生的部分。您没有 midl.exe 来帮助您生成代理/存根 DLL,并且您没有获得使用标准编组器的注册帮助。这就是错误消息的真正含义,这里的 E_NOINTERFACE 确实意味着它找不到任何方法来编组接口。是的,糟糕的错误信息。

.NET 中官方支持的创建进程外 COM 服务器的方法是将其注册到 COM+。使用 System.EnterpriseServices.ServicedComponent 类作为基类。MSDN 库文章在此处

于 2012-05-27T13:31:46.930 回答
1

我得到了一个改变主线程的建议,它帮助了我!

在主线程(主要在“Program.cs”)中找到 [STAThread] 行并将其更改为 [MTAThread]。

于 2013-06-25T12:24:53.667 回答