之前写过一篇使用COM组件的3种方法的文章:启动COM组件的三种机制,其中后来补充了一个用免注册的方式使用进程外COM组件的方法,因为只是文字补充,没有实例,可能对于怎么实现大家不是很清楚,陆续收到一些同学的信,希望能给个例子。 所以干脆补充一篇,自己也恰好复习一下。

步骤大概是这样的:

我有一个com.exe的进程外com组件,暴露出一个ITestObject的接口。现在CustomizedWay.exe要调用这个com组件,但不希望通过注册表那一套。 虽然微软提供了registry-free的com组件机制,但目前只支持进程内COM组件(具体参考前文),但由于我们知道一个COM组件被调用的来龙去脉,我们可以跳过MS那一套,自己来完成这个工作 (如果你愿意,写一个专门针对registry-free COM的库也不是问题)。这个过程的代码为:

HRESULT CreateMyRemoteHost(ITestObject** ppResult)
{
// Get the COM Server's full path (assume they are in the same folder)
wchar_t file[MAX_PATH] = {0};
if (!GetModuleFileName(NULL, file, MAX_PATH))
return E_FAIL;
wchar_t drive[_MAX_DRIVE] = {0};
wchar_t dir[_MAX_DIR] = {0};
_wsplitpath_s(file, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
_wmakepath_s(file, MAX_PATH, drive, dir, L"Com", L"exe");

// Start process (It will insert its class factory object into a global table held by OS)
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpTitle = NULL;
si.lpDesktop = NULL;
si.dwX = si.dwY = si.dwYSize = si.dwXSize = 0;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
BOOL ret = CreateProcess(file, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (!ret) return E_FAIL;
WaitForInputIdle(pi.hProcess, 30000);

// Get class factory (from class table)
CComPtr<IClassFactory> pFactory;
HRESULT hr = CoGetClassObject(CLSID_TestObject, CLSCTX_LOCAL_SERVER, NULL, __uuidof(pFactory), reinterpret_cast<void**>(&pFactory));
if (FAILED(hr)) return hr;

// Query interface by class factory
return pFactory->CreateInstance(NULL, __uuidof(*ppResult), reinterpret_cast<void**>(ppResult));

}

这个过程中有几点需要注意:

  • manifest的创建
    我们需要创建一个manifest来包含接口与tlb的信息,因为两个进程间交互的时候,COM指针是需要marshalling的,而这个是通过tlb完成的。创建tlb的命令为:

mt.exe -tlb:com.tlb -dll:com.exe -out:com.exe.manifest

对于产生出来的manifest,我们需要做一些修改:一是把coclass和com.exe的信息去掉,这一块我们是自己通过代码CreateProcess实现的,我们需要指定的是tlb文件和其GUID,以及其支持的所有接口(参考代码中的com.exe.manifest);二是mt.exe 产生的文件默认是单行的,为了阅读方便,需要手工换行。

manifest的集成
然后我们需要将这个manifest文件嵌入到com.exe和CustomizedWay.exe中,原因是进程间通信双方都需要知道如何marshalling。如果直接使用一下命令:

mt.exe -manifest com.exe.manifest -outputresource:com.exe
mt.exe -manifest com.exe.manifest -outputresource:CustomizedWay.exe

在启动程序时,会提示找不到:ATL##.dll和MSVCR##.dll,原因在于此处会把默认的manifest内容覆盖掉,而那些内容,则包含了MFC,CRt的一些DLL的信息。所以我们需要先merge这两个manifest,在嵌入到exe中去(mt.exe -manifest ...),但另外一个简单的方法,就是把com.exe.manifest直接加入到两个工程中,这样在build的时候,就会将该manifest的内容添加进去 - 你可以用VS打开exe文件,查看里面的 RT_MANIFEST项。

具体可以下载sample:RegistryFree_COMExe

参考:

  • 启动COM组件的三种机制
  • Mt.exe
  • Assembly Manifest

进程外COM组件的一个实例相关推荐

  1. docker 主进程 日志_[docker]从一个实例,一窥docker进程管理

    在Docker中,进程管理的基础是Linux内核的PID命名空间技术.在不同的PID命名空间下,可以有相同的PID. Linux内核为所有的PID命名空间维护了一个树状的数据结构,最顶层是系统初始化时 ...

  2. REDIS实践之请勿踩多进程共用一个实例连接的坑

    最近在做一个主进程fork出多个子进程的项目时候,一开始,想在主进程之前 new redis出一个实例,让fork出的多个子进程共用这个实例,但是总感觉有哪里不妥! 思来想去,想到这么个例子来证明这么 ...

  3. 用C#编写一个进程外的COM组件示例代码讲解

    代码的链接在<用C#编写一个进程外的COM组件>,小技巧:如果你要同时看示例代码和讲解的话,可以用浏览器分别打开示例代码和这篇文章,然后使用Windows提供的纵向平铺窗口功能就可同时看两 ...

  4. 12.编写COM进程外组件

    相比进程内组件,进程外组件的编写较为麻烦,在前面已经讲的IDL和进程外组件原理基础上,本节以一个简单实例讲解进程外组件的编写步骤和注意事项. 1.IDL生成代理/存根 假如我们需要实现一个猫猫翻译的接 ...

  5. 10.COM进程外组件和列集、散集

    前面讲的都是进程内组件,实际上COM是进程透明的,就是使用COM的时候,不管当前连接的是进程内组件还是进程外组件,使用方法一样,所有的差异都被COM中间屏蔽了.这一节详细讲解COM进程外组件的列集/散 ...

  6. COM/DCOM开发之远程进程外组件(DCOM)

    一 目的 使用VC++的ATL编程实现远程进程外组件.同时实现客户端这些组件的调用. 二 要求 1)使用C++语言实现远程进程外组件,组建提供加.减.乘.除.判断是否素数等计算服务:客户端部分包括录入 ...

  7. 从一个实例,一窥docker进程管理

    在Docker中,进程管理的基础是Linux内核的PID命名空间技术.在不同的PID命名空间下,可以有相同的PID. Linux内核为所有的PID命名空间维护了一个树状的数据结构,最顶层是系统初始化时 ...

  8. 主进程退出后子进程还会存在吗?_[docker]从一个实例,一窥docker进程管理

    在Docker中,进程管理的基础是Linux内核的PID命名空间技术.在不同的PID命名空间下,可以有相同的PID. Linux内核为所有的PID命名空间维护了一个树状的数据结构,最顶层是系统初始化时 ...

  9. 一个Servlet同一时刻只有一个实例。 当多个请求发送到同一个Servlet,服务器会为每个请求创建一个新线程来处理。

    Servlet是一种独立于操作系统平台和网络传输协议的服务器端的Java应用程序.  相同点:  1. 不是独立的应用程序,没有main()方法.  2. 不是由用户调用,由另一个应用程序(容器)调用 ...

最新文章

  1. UVA 1415 - Gauss Prime(数论,高斯素数拓展)
  2. ios php 序列化,PHP常见的序列化与反序列化操作实例分析
  3. Intel 平台编程总结----缓存的优化
  4. 关闭页面刷新上层页面的几种方式
  5. 小程序获取sessionkey_小程序,足不出户获取更多客源
  6. php 动态切换数据库,thinkphp多数据库动态切换
  7. 巧用词语角色:基于目标自适应图的跨目标立场检测
  8. 聚集索引、辅助索引、覆盖索引、联合索引
  9. C++Builder编程中动态更改自定义打印纸张
  10. pythondef元组参数传递_Python参数传递(传值传引用)
  11. MySQL分页查询方法及优化
  12. [转载] Java中使用new构造数组时会不会自动调用类的默认构造函数
  13. v4l2接口,结构图
  14. Rust: 为什么同样的情况,有时不需要解引用?
  15. 51单片机300个proteus仿真实例下载
  16. kindeditor php 漏洞,KindEditor漏洞、优化以及漏洞、BUG修复方案汇总
  17. 数仓OLAP(一)--即席查询 Kylin
  18. 创业之前你要先了解3大要点!!
  19. 课程向:深度学习与人类语言处理 ——李宏毅,2020 (P9)
  20. fastadmin更改访问入口文件路径

热门文章

  1. 软键盘挡住输入框问题的终极解决方案
  2. [转]linux下TCP连接占用的资源
  3. 使用 requests 配置代理服务
  4. 进程分析命令(持续更新中)
  5. Visula Basic程序设计理论与实践pdf
  6. elasticsearch 自定义routing
  7. poj1182(食物链)续
  8. ActiveReports 9 新功能:借助目录(TOC)控件为报表添加目录功能
  9. 用户 'NT AUTHORITY/NETWORK SERVICE' 登录失败 的解决方法(转)
  10. 小程序 textarea ios兼容解决