如何使用COM在两个进程之间传输数据 [英] How COM can be use to transfer Data between two process

查看:209
本文介绍了如何使用COM在两个进程之间传输数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在COM的平均知识,并希望了解COM如何帮助数据传输。假设有两个进程,Process-A和Process-B,并且他们都想要彼此共享一些数据,当然有很多RPC机制,但我想使用COM。


  1. 您无法创建COM dll,因为它将变得特定于处理,不能使用

  2. 我们可以创建一个单吨COM EXE服务器并将结构包装在COM CoClass中并将其成员作为属性公开,然后...不知道如何?

,你们中的任何人能帮我清楚我对这个话题的理解吗?基本上我想在两个进程之间共享一个数据结构使用COM

解决方案

COM是一个巨大的话题,它以溢出答案的格式。我将尝试做的是在Visual Studio ATL向导(在标签中提及ATL)的帮助下,展示最简单的本地out of process COM服务器和COM客户端(尽可能短)的示例,它将生成大多数代码,这提供了测试COM方法和调查样板源的可能性。但是为了更好的理解,我推荐找到没有ATL的inproc COM服务器实现 - 只需使用C ++。


  1. p>


    • 使用名称COMStructProvider创建新的ATL项目(在Visual C ++中选择ATL项目模板)。在向导中选择可执行应用程序类型(不是DLL)。默认为其他选项。向导将生成项目文件。

    • 选择项目 - >添加类 - > ATL简单对象 - >添加。在短名称字段中输入任意名称,例如MyStruct。点击完成。这将添加头和MyStruct coclass的实现文件。另外MyStruct.rgs将被添加以帮助注册您的coclass在注册表中。现在你有最小的COM服务器,并可以构建解决方案,但要做到这一点你需要以管理员身份运行VS(因为它会在注册表中注册你的服务器),否则注册失败。

    • 添加两个数据CMyStruct的成员(默认情况下为VS的前缀类)C:
      private:
      std :: string m_name;
      int m_age;

    • 在上一步骤中,向导创建了接口IMyStruct(您可以在idl文件中查看它)。现在我们要为这个接口添加方法:getters和setter我们的两个私有数据成员。选择Class View选项卡,选择IMyStruct接口(从IDispatch派生),在上下文菜单中选择添加方法。例如,方法名称getAge具有参数LONG *,参数属性out和参数名称:age(单击添加以添加参数)。这为idl文件和头和impl文件添加了新的方法。为setAge(在LONG类型的参数中),getName(out,BSTR *),setName(in,BSTR)重复添加方法。

在idl文件中,您将有一些东西像这样 - 我提供这个检查点,所有步骤都正确完成:

  importoaidl.idl 
importocidl.idl;

[
object,
uuid(AA2DA48C-CD1E-4479-83D4-4E61A5F188CB),
dual,
不可扩展,
pointer_default唯一)
]
接口IMyStruct:IDispatch {
[id(1)] HRESULT getAge([out] LONG * age);
[id(2)] HRESULT setAge([in] LONG age);
[id(3)] HRESULT getName([out] BSTR * name);
[id(4)] HRESULT setName([in] BSTR name);
};
[
uuid(E7A47886-D580-4853-80AE-F10FC69E8D73),
版本(1.0),
]
库COMStructProviderLib
{
importlib(stdole2.tlb);
[
uuid(CC51EFFE-C8F4-40FA-AEA3-EB6D1D89926E)
]
coclass MyStruct
{
[default] interface IMyStruct;
};
};




  • 添加实施:



  STDMETHODIMP CMyStruct :: getAge(LONG * age){* age = m_age; return S_OK;} STDMETHODIMP CMyStruct :: setAge(LONG age){m_age = age;返回S_OK;} STDMETHODIMP CMyStruct :: getName(BSTR * name){* name = SysAllocString(m_name.c_str());返回S_OK;} STDMETHODIMP CMyStruct :: setName(BSTR name){m_name.assign(name); return S_OK;}  


  1. 创建客户端。将新的Win32控制台应用程序项目MyStructClient添加到解决方案(可执行文件)。添加以下代码:

  #include< iostream> //检查tlb库的正确路径。将创建tlh,tli文件,提供智能指针等。#import..\\COMStructProvider\\Debug\\COMStructProvider.tlbno_namespace named_guidusing namespace std; int main(){// initialize COM runtime CoInitialize(NULL); {//智能指针简化工作,将调用CoCreateInstance激活COM服务器IMyStructPtr spMyStruct(__ uuidof(MyStruct)); BSTR name = SysAllocString(LJohn); spMyStruct-> setName(name); SysFreeString(name); BSTR retreivedName; spMyStruct-> getName(& retreivedName); wcout<< name<< retreivedName<< endl; SysFreeString(retreivedName); spMyStruct-> setAge(5); long age = 0; spMyStruct-> getAge(& age); cout < age<年龄< endl; } CoUninitialize(); return 0;}  



服务器,它提供对可访问相同结构的结构和客户端的访问(您可以并行运行更多的客户端进程。所有客户端访问同一服务器进程 - 可以被认为是单例 - 但是可以在每次激活时产生单独的进程) 。客户端可以更改和获取此结构的值(如需要)。在引擎盖下,客户端可以访问其自身地址空间中coclass的代理,COM运行时支持所有进程间通信。这些代理/存根(以C / C ++源的形式)由MIDL编译器从上面提到的接口idl文件生成。只要您专注于在两个进程之间传输数据,您应该知道有三种类型的COM封送:自定义,标准和通用。在本例中,通用是足够的,因为我只使用 VARIANT 兼容类型作为方法参数。要传递任意类型,你应该使用标准编组(在代理/存根dll的帮助下,在创建COM服务器时在第一步中生成)。项目名称是带有后缀PS的服务器的名称。标准编组的缺点 - 您应该将这些PS dll与您的COM服务器一起部署。


i have a average knowledge in COM and will like to understand how COM helps in data transfer. Assuming there are two processes, Process-A and Process-B and both of them wants share some data with each other, of course there are many RPC mechanisms but i would like to use COM.

  1. you cannot create a COM dll because then it would become specific to process and cannot be used
  2. can we create a Single ton COM EXE server and wrap the structure in COM CoClass and expose it members as properties and then ...no idea how to ?

Above is my understanding, can anyone of you help me clear my understanding on this topic? basically i would like to share a data structure between two process using COM

解决方案

COM is huge topic and it is not possible to explain it in format of overflow answer. What I will try to do is to demonstrate simplest example of local out of process COM server and COM client (as short as possible) with help of Visual Studio ATL wizards(as far as you mentioned ATL in tags) that will generate most of the code and this gives the possibility to test COM approach and investigate boilerplate sources. But for better understanding I recommend to find inproc COM server implementation without ATL - just with C++.

  1. Creating Structure provider:

    • Create new ATL project with name COMStructProvider (select ATL project template in Visual C++). In wizard select "Executable" application type (not DLL). Other option by default. Wizard will generate project files.
    • Select Project -> Add class -> ATL simple object -> Add. In short name field type arbitrary name, for example MyStruct. Click "Finish". This will add header and implementation file for MyStruct coclass. Also MyStruct.rgs will be added to help register your coclass in registry. Now you have minimal COM server and can build solution but to do it you need to run VS as administrator (because it will register your server in registry), otherwise registration fail.
    • Add two data members to CMyStruct(VS prepend class with C by default) class: private: std::string m_name; int m_age;
    • During previous steps wizard created interface IMyStruct (you can see it in idl file). Now we want to add methods to this interface: getters and setters to our two private data members. Select Class View tab, select IMyStruct interface (derived from IDispatch), select in context menu "add method". For example method name getAge with parameter LONG*, parameter attributes "out" and parameter name: age (click Add to add parameter). This adds new method to idl file and to header and impl file. Repeat adding of methods for setAge (in parameter of type LONG), getName (out, BSTR* ), setName(in, BSTR). Name of parameters doesn’t matter.

In idl file you will have something like that - I provide this as checkpoint that all steps are done correctly:

import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(AA2DA48C-CD1E-4479-83D4-4E61A5F188CB),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IMyStruct : IDispatch{
    [id(1)] HRESULT getAge([out] LONG* age);
    [id(2)] HRESULT setAge([in] LONG age);
    [id(3)] HRESULT getName([out] BSTR* name);
    [id(4)] HRESULT setName([in] BSTR name);
};
[
    uuid(E7A47886-D580-4853-80AE-F10FC69E8D73),
    version(1.0),
]
library COMStructProviderLib
{
    importlib("stdole2.tlb");
    [
        uuid(CC51EFFE-C8F4-40FA-AEA3-EB6D1D89926E)      
    ]
    coclass MyStruct
    {
        [default] interface IMyStruct;
    };
};

  • Add implementation:

STDMETHODIMP CMyStruct::getAge(LONG* age)
{
	*age = m_age;
	return S_OK;
}


STDMETHODIMP CMyStruct::setAge(LONG age)
{
	m_age = age;
	return S_OK;
}


STDMETHODIMP CMyStruct::getName(BSTR* name)
{
	*name = SysAllocString(m_name.c_str());
	return S_OK;
}


STDMETHODIMP CMyStruct::setName(BSTR name)
{
	m_name.assign(name);
	return S_OK;
}

  1. Creating client. Add new Win32 Console application project MyStructClient to solution (executable). Add following code:

#include <iostream>
// check for correct path to tlb library. Will create tlh, tli files that provide smart pointers, etc.
#import "..\\COMStructProvider\\Debug\\COMStructProvider.tlb" no_namespace named_guid

using namespace std;

int main()
{
    // initialize COM runtime
	CoInitialize(NULL);
	{
        // smart pointer simplifies work, will invoke CoCreateInstance to activate COM server
		IMyStructPtr spMyStruct(__uuidof(MyStruct));
		BSTR name = SysAllocString(L"John");
		spMyStruct->setName(name);
		SysFreeString(name);

		BSTR retreivedName;
		spMyStruct->getName(&retreivedName);
		wcout << "name " << retreivedName << endl;
		SysFreeString(retreivedName);

		spMyStruct->setAge(5);

		long age = 0;
		spMyStruct->getAge(&age);

		cout << "age " << age << endl;
	}
	CoUninitialize();

	return 0;
}

So, you have two processes running simultaneously: server that provides access to structure and client that has access to the same structure (you can run more client processes in parallel. All clients access the same server process - can be considered as singleton - but it's possible to spawn separate process with each activation). Client can change and get values of this structure (as was required). Under the hood client has access to proxy of coclass in its own address space and COM runtime support all interprocess communication. Those proxy/stubs (in the form of C/C++ sources) are generated by MIDL compiler from interface idl file mentioned above. As far as you focused on transfering Data between two process you should know that there are three types of COM marshaling: custom, standard and universal. In this example universal is sufficient because I use only VARIANT compatible types as method parameters. To pass arbitrary types you should use standard marshaling (with help of proxy/stub dlls, generated in separate project on first step when creating COM server. name of project is the name of project with server with suffix PS). Disadvantage of standard marshaling - you should deploy those PS dlls with your COM server.

这篇关于如何使用COM在两个进程之间传输数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆