Porting COM to Linux

I like COM technology. But this is not about technology, praise or disadvantages of COM, but the experience of porting and implementing on Linux. Bicycle? Feasibility?Let's not focus on this.


COM Object (1)

In general terms, a class object that implements at least one COM interface. The object implementation is basically hidden in a dynamically linked library called a COM server (2) , interfaces are published and distributed for use.


COM interface, an abstract class containing only pure virtual functions. A special IUnknown interface is allocated, any COM object is required to implement this interface.


Each COM-interface must contain a certain identifier. In COM, it is determined by the GUID structure and here we encounter the first drawback of COM. GUID is incomprehensible and do not read well, and everything else described on the Wiki. We need it the same, but in a more readable and understandable form (let's call it uiid).


IUnknown and uiid

#define define_uiid(name) \
	inline static const std::string& guid() { const static std::string idn(dom_guid_pre_name #name); return idn; }namespace Dom {
	using uiid = std::string;
	using clsuid= std::string;
	structIUnknown
	{virtuallongAddRef()= 0;
		virtuallongRelease()= 0;
		virtualboolQueryInterface(const uiid&, void **ppv)= 0;
		define_uiid(Unknown)
	};
}

In addition to the interface identifier, the class identifier (clsuid) is also highlighted, which is required to create an object. In our case, because this is a less readable identifier that can determine the essence, you can forget about publishing them for now (perhaps this is not good).


Summary A
COM object contains a single class identifier. Implements at least one COM interface - IUnknown (any COM interface has a unique interface identifier). Different implementations of a COM object may have the same class identifier (example: release and debug version).



COM server (2)

Dynamically connected library (for Linux it is Shared object - so) that implements at least one COM object. The server must export a specific set of functions:


extern"C"boolDllCreateInstance(const uiid& iid, void** ppv)
Creates a class object by clsuid, increases the number of references to so, each time the object is successfully created. Calling IUnknown :: AddRef should also increase the reference count for so, and IUnknown :: Release should decrease.

extern"C"boolDllCanUnloadNow()

If the number of references to SO is 0, then the library can be unloaded.

extern"C"boolDllRegisterServer(IUnknown* unknown)

Registers in the “registry” all clsuid server. Called once when installing a COM server.

extern"C"boolDllUnRegisterServer(IUnknown* unknown)

Removes from the “registry” records on the registered clsuid server. Called once when uninstalling a COM server.

SimpleHello example, declare the IHello interface:

structIHello :publicvirtual Dom::IUnknown {
	virtualvoidPrint()= 0;
	define_uiid(Hello)
};

Interface implementation:

/* COM-объект */classSimpleHello :public Dom::Implement<SimpleHello, IHello> {
public:
	SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); }
	~SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); }
	virtualvoidPrint(){
		printf("Hello from %s\n",__PRETTY_FUNCTION__);
	}
	define_clsuid(SimpleHello)
};
/* COM-сервер */namespace Dom {
	DOM_SERVER_EXPORT_BEGIN
		EXPORT_CLASS(SimpleHello)
	DOM_SERVER_EXPORT_END
	DOM_SERVER_INSTALL(IUnknown* unknown){
		Interface<IRegistryServer> registry;
		if (unknown->QueryInterface(IRegistryServer::guid(), registry)) {
// Дополнительные действия при инсталляции сервера
		}
		returntrue;
	}
	DOM_SERVER_UNINSTALL(IUnknown* unknown) {
		Interface<IRegistryServer> registry;
		if (unknown->QueryInterface(IRegistryServer::guid(), registry)) {
// Дополнительные действия прии деинсталляции сервера
		}
		returntrue;
	}
}

A set of macros hides implementations of functions, providing a more structured declaration and logic.


Dom :: Implement <SimpleHello, IHello> - hides the implementation of IUnknown interface methods, adds “sugar”, when declaring interfaces implemented by an object (C ++ 11 and variadic templates):



template <typename T, typename ... IFACES>
	structImplement :virtualpublic IUnknown, virtualpublic IFACES… {
...
};

Interface IRegistryServer - defines a set of methods for working with the "registry" of COM-servers.


“Registry” of COM servers (3)

The importance of the registry can be underestimated, but it is probably the main pillar of COM. Microsoft writes to the registry, creates a complex structure for the description of interfaces and their attributes (idl), I went a little different way.


In the implementation of the registry is based on the file system.
What are the buns? Understanding, simplicity, possibility of recovery, a special bonus when registering a server, you can specify some kind of namespace (a directory relative to the base registry in which server objects will be registered), thereby you can implement the integrity and versioning of applications using technology.


Of the shortcomings, possible security problems, the substitution of implementations of objects.


How to use sample application (4)

In order to make everything work, you will need a small “library” and a small “program”.


“Library” is nothing more than a wrapper that implements and integrates everything into a single whole, working with the registry, loading / unloading SO, creating objects.
It is the only one that should be specified when building the application. Everything else, “I want to believe,” she will do herself.


The “program” - regsrv is actually an analogue of the Microsoft RegSrv32 program that performs the same actions (+ the ability to specify a namespace, + the ability to get a list of registered clsuid and COM servers).



sample

#include"../include/dom.h"#include"../../skel/ihello.h"intmain(){
	Dom::Interface<Dom::IUnknown>	unkwn;
	Dom::Interface<IHello>		hello;
	if (Dom::CreateInstance(Dom::clsid("SimpleHello"), unkwn)) {
		unkwn->QueryInterface(IHello::guid(), hello);
		hello->Print();
	}
	else {
		printf("[WARNING] Class `SimpleHello` not register.\nFirst execute command\n\tregsrv <fullpath>/libskel.so\n... and try again.");
	}
	return0;
}

Dom (5)

Dom (Dynamic Object Model), my implementation for Linux.

git clone


Thank.

Also popular now: