【问题标题】:In-Proc COM object sharing across another Process跨另一个进程的进程内 COM 对象共享
【发布时间】:2011-07-22 11:57:15
【问题描述】:

在我问这个问题之前,我想明确表示我知道有用于进程间通信的库和技术。不过,这是一个关于 COM 的学习问题。 我也知道进程外服务器,但这不是我想要的。

问题:

我想知道,因为我不知道,是否有可能,如果是的话,如何共享一个进程中的进程内 COM 对象(在 DLL 中定义的对象)(已在进程)跨越另一个进程?即,如何从进程 B 中的进程 A 获取指向进程内对象的指针?

提前致谢。

【问题讨论】:

  • 您能描述一下您要解决的真正问题吗?

标签: c++ interprocess com


【解决方案1】:

这就是 CoRegisterClassObject 和 CoGetClassObject 的用途。

【讨论】:

  • 不是只有 exe(进程外)服务器的 CoRegisterClassObject 吗?我有进程内服务器。
  • 我认为他是在谈论共享一个对象的特定实例,而不是同一个类的两个单独实例,每个进程一个实例。
  • @ActiveX 您可以为进程内服务器制作进程外包装器
  • 这听起来像 hack 不像 COM。我正在寻找已发布的解决方案。你有这方面的例子吗?
【解决方案2】:

是的,这是可能的。无论您是在单个进程中的公寓之间还是在不同进程之间共享单个对象实例,基本原理都是相同的。

这里有两种方法:也许最简单的方法是使用Running Object Table:这本质上是一个工作站范围的命名 COM 对象表。您让一个进程将一个具有众所周知名称的对象添加到表中,并让另一个进程查找该对象。

另一种方法是使用编组。封送处理是使用 COM API 获取描述对象位置的一系列字节的过程。然后,您可以使用任何您想要的方式(共享内存、文件、管道等)将该系列字节复制到另一个进程,然后在接收进程中使用另一个 COM API 来解组对象; COM 然后在该进程中创建一个合适的远程代理,该代理与原始代理通信。查看 API CoMarshalInterfaceCoUnmarshalInterface 了解更多详情。

请注意,这两者都要求您为对象提供适当的远程支持;您使用的接口需要在 IDL 中进行描述,并进行适当的编译和注册。

--

不幸的是,我手头没有用于这两种情况的代码。

对于 CoMarshalInterface 方法,过程类似于:

  • 使用 CreateStreamOnHGlobal(hglobal 为 NULL)创建一个 IStream,该 IStream 由 COM 根据需要分配的 HGLOBAL 支持
  • 使用 CoMarshalInterface 将接口指针编组到流(进而将其写入由 HGLOBAL 支持的内存)
  • 使用 GetHGlobalFromStream 从流中获取 HGLOBAL
  • 使用 GlobalLock/GlobalSize 锁定 HGLOBAL 并访问封送数据(完成后 GlobalUnlock)
  • 使用您想将字节复制到目标进程的任何方式。

在远端,使用:

  • GlobalAlloc/GlobalLock/GlobalUnlock 创建一个新的 HGLOBAL 并用封送数据填充它
  • 使用您的新 HGLOBAL 创建StreamOnHGlobal
  • 将此流传递给 CoUnmarshalInterface

普通的 COM 和 Windows 引用计数/资源规则适用于所有这些; AddRef/Release 视情况而定;使用 GlobalFree 释放您分配的任何 HGLOBAL 等。

【讨论】:

  • 我正在寻找的答案。你有完整的 GetRunningObjectTable 代码示例吗?还是 CoMarshallInterface?
  • 实际上,假设我使用 CoMarshallInterface 将我的接口指针编组到流中......然后呢?如何将流传递给另一个进程?通过命名管道/套接字/内存映射文件等进程间通信方法?如果是这种情况,那么编组真的不会为我节省任何工作。
  • 我没有任何代码可用于这些场景;几年前,我在一个项目中使用了 CoMarshal 方法的变体;已经更新了上面的答案,提供了有关所涉及步骤的更多详细信息。
  • @ActiveX:它为您节省了大量工作,因为您只需在一个方向上执行一次,即可将对象传递给另一个进程。然后,DCOM 会为每个方法调用和属性访问来回传递参数。
  • 是的,你说得对。它确实为我节省了一些工作。我期待 COM 有更多的本地支持,就像 COM 服务方法 CoCreateSharedInstance() 为我完成所有工作:) 无论如何,感谢您的回答,非常有帮助。我还在网上找到了一个 gem (msdn.microsoft.com/en-us/magazine/cc302324.aspx) 我将探索替代方案。结合您的想法的客户类工厂看起来很有前途
【解决方案3】:

还有另一种可能的解决方案,使用窗口消息WM_GETOBJECT

在具有对象的应用程序中,您只需使用自己的类创建一个窗口。在处理程序中,您需要像这样处理窗口消息(我使用 IDispatch 作为示例接口):

LRESULT WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_GETOBJECT:
        {
            if(lParam == OBJID_NATIVEOM)
            {
                return LresultFromObject(IID_IDispatch, wParam, g_MyGlobalIDispatchPointer);
            }
            else
            {
                // Not handled
                break;
            }
        }
        return 0;
    }

    // Default
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

其他应用程序必须找到该特定窗口并通过AccessibleObjectFromWindow获取对象

例如:

HWND hWndCommunicator = FindWindow(_T("MyWindowClassOfTheOtherApplication"), _T("MyWindowTitleOfTheOtherApplication"));
if(hWndCommunicator)
{
    IDispatch* poObject = nullptr;
    HRESULT hr = AccessibleObjectFromWindow(hWndCommunicator, static_cast<DWORD>(OBJID_NATIVEOM), IID_IDispatch, &poWindow);
    if(SUCCEEDED(hr))
    {
        // Do something with the object of the other process
        // i. e. poObject->Invoke
    }
}

使用此解决方案自动完成编组。

【讨论】:

    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2012-07-22
    • 2015-11-30
    • 2012-08-13
    相关资源
    最近更新 更多