How to use COM to transfer Data between two proces

2020-02-12 07:01发布

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

2条回答
时光不老,我们不散
2楼-- · 2020-02-12 07:15

Updated: when one object call method of another object (passing information in parameters) we say that first object sends message to second one. Usually this happen s within one process address space. COM allows object in one process to call method of object in another process - thus enabling interprocess communication.

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.

查看更多
淡お忘
3楼-- · 2020-02-12 07:28

COM exe out-of-process servers are notably difficult to write, but Microsoft has created COM+ Component service to ease this out.

It contains a lot of services, but here we're interested by the Application service that allows you to host in-process servers (DLL) in an out-of-process surrogate host.

It's quite simple, just write a standard ATL DLL (or use any other language/framework you like). I recommand using Automation types for the interface so you don't need special proxies, for example with an IDL interface defined like this:

interface ISharedMap : IDispatch{
    [id(1)]
    HRESULT PutData([in] BSTR key, [in] VARIANT value);

    [id(2)]
    HRESULT GetData([in] BSTR key, [out, retval] VARIANT *pValue);
};

Then create a new COM+ application, as described here: Creating COM+ Applications, and declare it as a server application. This is what you should see once this is done:

enter image description here

Your DLL will now be hosted automatically in a specific process (the famous dllhost.exe) which will be started as soon as clients try to connect. By default, the same process will be used for various out-of-process COM clients. It will shutdown after some time, but you can configure the COM+ application in a various ways, for example with the 'Leave running when idle' flag set':

enter image description here

Now you will be able to use your cross process memory cache for all COM clients you'll like, for example, like this from a simple javascript .js code:

var map = new ActiveXObject("SharedMap");
map.PutData("mykey", "mydata")
var data = map.GetData("mykey")

Note: implementation of the cache is left to the reader, but it could reuse another of COM+ services: the COM+ Shared Property Manager

查看更多
登录 后发表回答