c# - 绝对 COM 混淆 - C# 与早期绑定(bind)的互操作

标签 c# com interop com-interop

我整天都在与 VStudio、Google 和各种其他工具和网站作斗争,但没有找到解决方案 - 求助!!

我有两个 COM 接口(interface)(纯 COM,无 ATL):

具有相应实现的 IMyClassFactory 和 IMyClass

我想在 C# 中使用它们,但不使用 regsvr32 注册 COM 服务器。 我使用 CoRegisterClassObject 公开了类工厂,并且我可以从非托管代码中使用 CoCreateInstance 成功创建 IMyClass 的对象。

所以 C# 互操作...

我使用 tlbimp myComServer.tlb 创建了一个 .NET 包装器并将其加载为对我的 C# 客户端的引用。

然后,当我尝试创建 IMyClass 的实例时,我得到:

An unhandled exception of type 'System.InvalidCastException' occurred in COMTestClient.exe

Additional information: Unable to cast COM object of type 'MyComServerLib.MyClass' to interface type 'MyComServerLib.IMyClass'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{9F8CBFDC-8117-4B9F-9BDC-12D2E6A92A06}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

现在,我已经向 QueryInterface 添加了跟踪,并且我返回 E_NOINTERFACE 的唯一情况是它请求任何与 Marshal 相关的接口(interface)或 IManagedObject。

我该如何解决这个问题??

编辑:我的 IDL 文件:

import "unknwn.idl";

[
    object, 
    uuid(...), 
    nonextensible,
    pointer_default(unique)
]
interface IMyClass : IUnknown
{
    HRESULT(SetFirstNumber)(long nX1);

    HRESULT(SetSecondNumber)(long nX2);

    HRESULT(DoTheAddition)([out,retval] long *pBuffer);
};

[
    uuid(...)
]
library MyLib
{
    importlib("stdole2.tlb");

    [
        uuid(...)
    ]
    coclass IMyClassImpl
    {
        [default] interface IMyClass;
    };
}

最佳答案

您需要允许您的接口(interface)被编码(即,通过在 .idl 文件中将其标记为非“本地”,以便它最终出现在类型库和代理/ stub 中),或聚合自由线程编码器,如果你这样做的话。

为了聚合 FTM,我做了这样的事情:

#define DECLARE_FTM() \
protected: CComPtr<IUnknown> _m_Marshal; \
DECLARE_GET_CONTROLLING_UNKNOWN() \
public: HRESULT FinalConstruct() \
{ return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&_m_Marshal); }

#define COM_INTERFACE_ENTRY_FTM() COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal,_m_Marshal.p)

然后,在您的 COM 映射中:

BEGIN_COM_MAP(Blah)
    COM_INTERFACE_ENTRY(IBlah)
    COM_INTERFACE_ENTRY_FTM()
END_COM_MAP()
DECLARE_FTM()

我注意到您没有使用 ATL 等 - 您需要修改它,以便您的 QueryInterface 实现在查询 IMarshal 时返回 FTM 指针。

请注意,聚合 FTM 并不是一件轻而易举的事情 - 它会做出一些并不总是有效的不安全假设。例如,您的类不能使用任何本身不是自由线程的接口(interface)。

另一种选择基本上如@[Franci Penov] 所说,您需要确保您的接口(interface)能够被编码。按照我的理解,有一个标准编码器能够编码类型库中的任何接口(interface),或者您(即 midl 编译器或多或少地自动执行)可以制作代理/ stub dll(或合并代码用于将代理/ stub 放入您自己的 dll 中),它能够为您编码它。

本文here describes the process of building and registering the proxy/stub更详细。

关于c# - 绝对 COM 混淆 - C# 与早期绑定(bind)的互操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1528503/

相关文章:

haskell - Elixir 和 Haskell 互操作性

c# - ASP.NET C# 验证用户名和密码

c# - 查询语法有效,但 lambda 语法不适用于 linq select 语句

C# 从数据库列中获取所有电话号码并用逗号分隔并显示在文本框中

c# - MS Office COM 与多个 UAC 用户的互操作和线程安全

c# - 在 Windows 窗体中托管 IDeskBand

c# - 带有 OpenRasta 和 ASP.NET MVC 的 REST API

c# - 在 C# COM 项目中,我应该引用 DLL 还是 TLB? (主要是 SolidWorks)

c# - 为什么从 C# 4.0 开始使用的 COM 库需要大量使用动态类型?

php - 如何将一些用 Ruby 编写的功能混合到 WordPress 站点中?