【问题标题】:Reconnect to Process Started Via COM重新连接到通过 COM 启动的进程
【发布时间】:2010-11-25 02:02:06
【问题描述】:

首先,我想指出我需要使用 COM/OLE2 API,低级别的东西,可以放在 C Windows 控制台程序中的东西。我无法使用 MFC。我不能使用 .NET。

我的问题是:

给定以下代码:

CLSID clsid;    
HRESULT hr;

hr = CLSIDFromProgID(L"InternetExplorer.Application", &clsid);
assert(SUCCEEDED(hr));

hr = CoCreateInstance(clsid,
                      NULL,
                      CLSCTX_LOCAL_SERVER,
                      IID_IDispatch,
                      (void **)&(iePtr_));
assert(SUCCEEDED(hr));

有没有办法将一些信息写入磁盘,以便我以后可以重新连接到同一个 IE 实例?基本上可以将“iePtr_”字符串化,以便稍后通过其他进程重构?

谢谢。

----稍后添加-----

我要解决的更广泛的问题是我想启动一个 AutoCAD 应用程序,将一些数据加载到其中,然后让它运行以供我的客户与之交互。稍后他会回到我的应用程序,我想重新连接到同一个 AutoCAD 会话并为其提供更多数据。

现在,我完全意识到我可以将 IDispatch 指针保存在我的应用程序的内存中,并且我将能够继续与同一个 AutoCAD 进程进行交互。这是我的后备位置。

但是,我使用“包装器”程序来完成我的 COM 工作。所以包装器是瞬态的。我的主应用程序启动包装器,然后包装器进行通信,然后退出。我只希望后续包装进程能够重新连接到同一个 AutoCAD 进程。

为什么要使用包装器?这是工作的原因:我的主要应用程序是 32 位应用程序,但我可以使用 64 位包装器并与 64 位 AutoCAD 通信。我需要能够与 64 位 AutoCAD 通信,并且可能无法轻松移植我的主应用程序(500K+ 行 C++)与我的包装程序(几百行)。

【问题讨论】:

  • 您要解决的更广泛的问题是什么?
  • 您应该使用 SUCCEEDED() 而不是 !FAILED() - 这就是它的用途。我将编辑代码。
  • 在主帖中添加了“更广泛”的图片内容。
  • 这听起来很奇怪。 Autocad COM 服务器是作为 out-proc (exe) 启动的,不是吗。如果是这样,您不在乎它是 32 位还是 64 位。

标签: c++ c windows com ole


【解决方案1】:

不,这是不可能的。 COM 的整个想法是,COM 服务器是透明启动的,并且只保留状态,直到您停止使用它的对象。释放 COM 对象后,COM 子系统可以完全停止服务器,并且无法重新创建相同的进程。可能产生类似结果的唯一方法是拥有一个带有序列化方法的 COM 对象,该方法允许将状态保存到流中并从流中恢复它。但即便如此,您也必须再次 CoCreateInstance(),获取一个新的 COM 对象接口指针并调用该对象的恢复方法。

你从CoCreateInstance得到的指针只对当前进程有效,如果你把它保存在磁盘上稍后恢复它就会失效。

【讨论】:

  • 这似乎是对 COM 的一种相当幼稚/最纯粹的看法 - 如果真正的 COM 代码只有这样的行为,也许世界会变得更好。
  • @morechilli:这就是模型所暗示的行为。当然,实现会做它做的事情。
【解决方案2】:

CoMarshalInterface(和相关 API)可用于将接口编组到网络上的另一个线程、进程或不同 PC。我不知道在完成封送处理之前允许您等待多长时间,但原则上,如果您封送接口的对象尚未关闭,则封送处理可以稍后完成。

能够销毁 OLE 对象然后恢复“同一个对象”与所谓的 Moniker 相关联,如果您(能够)理解这些,那么您的 OLE/COM Juju 确实很强大。

【讨论】:

  • 据称,DCOM 有一个“垃圾收集”机制,可以在 4 分钟后终止对象的存根,因此需要注意超时。如果对象托管在其自己的进程中,您应该能够将接口 ptr 编组为流,将其写入磁盘,然后在另一个进程中重构,前提是您在这 4 个中执行此操作分钟。
【解决方案3】:

如果应用程序在运行对象表中注册了自己,您可以使用GetActiveObject 函数来获取对应用程序对象的引用。

IUnknown *pUnknown;

hr = GetActiveObject(clsid, NULL, &pUnknown);
assert(SUCCEEDED(hr));

hr = pUnknown->QueryInterface(IID_IDispatch, (void **)&(iePtr_));
assert(SUCCEEDED(hr));

【讨论】:

    【解决方案4】:

    我建议让包装层长期存在而不是瞬态,因此它可以轻松保存对第三个应用程序的单个引用。

    包装器在客户端代码中仍然可能是暂时的。 如果您将包装器设为 COM 单例,那么每次共同创建它时,您都会返回相同的实例。

    为了确保包装器在您的客户端的整个生命周期内都存在,请保留从启动到关闭的引用。此引用不需要连接到其他代码。所有其他代码只需在每次需要时创建单例。

    【讨论】:

      猜你喜欢
      • 2015-07-25
      • 1970-01-01
      • 1970-01-01
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 2014-04-20
      • 1970-01-01
      • 2015-05-21
      相关资源
      最近更新 更多