是否可以使用反射将 COM 对象从 C# 传递到 C++?

Is It Possible To Use Reflection To Pass A COM Object From C# to C++?

我有一个 C# 程序集,它执行一些工作并将工作结果发送回 C++ 核心。我正在尝试使用反射将其传回,因为 C# 程序集运行在与它从 C++ 核心初始化的线程不同的线程上。我试过使用COM接口作为参数类型。

IDL:

    HRESULT SendEvent([in] IEventData *pEventData);

C#:

    WECOInspectionCoreIDL.IEventData eventData = new EventData() as WECOInspectionCoreIDL.IEventData;
    var parameters = new object[1];
    parameters[0] = eventData;
    _piInspectionCore.GetType().InvokeMember("SendEvent", BindingFlags.InvokeMethod, null, _piInspectionCore, parameters);

这在 atlcom.h hRes = m_pInfo->Invoke(...) 调用中出现错误“0x80020005 类型不匹配”,显然最终会转换为“无法转换类型的 COM 对象” 'System.__ComObject' ...不支持这样的接口。

我也试过将参数设为 IDispatch*,然后调用转到 C++,但它似乎不是真正的对象。

IDL:

    HRESULT SendEvent([in] IDispatch *pEventData);

C++:

    STDMETHODIMP CInspectionCore::SendEvent(IDispatch *pEventData)
    {
       IEventData *pIEventData = (IEventData *)pEventData;

即使调用 pIEventData->GetIDsOfNames() 也会失败。

当从不同的 C++ 线程调用 C# 对象时,是否可以将 C# 创建的 COM 对象传递给 C++?

对于 COM,您应该永远不要像这样将一个 COM 接口转换为另一个 COM 接口:

STDMETHODIMP CInspectionCore::SendEvent(IDispatch *pEventData)
{
    IEventData *pIEventData = (IEventData *)pEventData; // wrong!
}

必须 使用 QueryInterface,这很好用:

STDMETHODIMP CInspectionCore::SendEvent(IDispatch *pEventData)
{
    IEventData* pIEventData;
    HRESULT hr = pEventData->QueryInterface(&pIEventData);
    if (FAILED(hr)) // etc.
}

在某些情况下(实际上经常),原始转换可能会产生这样的错误印象,即它没问题。

在您的情况下,它不起作用,因为您使用不同的线程创建隐式代理 (COM apartments, etc.)。你可以看到,如果你在 SendEvent 中设置断点,在调用时查看调用堆栈,它都是 COM 编组的东西。