J'aime la technologie COM. Mais nous ne parlerons pas de la technologie, des éloges ou des lacunes de COM, mais de l'expérience du portage et de la mise en œuvre sur Linux. Un vélo? Opportunité?
Ne nous concentrons pas là-dessus.
Objet COM (1)En termes généraux, un objet d'une classe qui implémente au moins une interface COM. L'implémentation de l'objet est principalement cachée dans une bibliothèque connectée dynamiquement appelée serveur COM (2) , les interfaces sont publiées et distribuées pour utilisation.
Interface COM, une classe abstraite contenant uniquement des fonctions virtuelles pures. Une interface IUnknown spéciale est mise en évidence, tout objet COM doit implémenter cette interface.
Chaque interface COM doit contenir son propre identifiant. Dans COM, il est déterminé par la structure du GUID et nous allons ici faire face au premier inconvénient de COM. Le GUID est incompréhensible et ne se lit pas bien, et tout le reste décrit sur le Wiki. Nous en avons besoin de la même manière, mais d'une manière plus lisible et compréhensible (appelons-la uiid).
IInconnu et 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; struct IUnknown { virtual long AddRef() = 0; virtual long Release() = 0; virtual bool QueryInterface(const uiid&, void **ppv) = 0; define_uiid(Unknown) }; }
En plus de l'identifiant d'interface, l'identifiant de classe (clsuid), nécessaire à la création de l'objet, est également alloué. Dans notre cas, car c'est un identifiant moins lisible qui peut déterminer l'essence, vous pouvez oublier leur publication pour l'instant (peut-être que ce n'est pas bon).
Résumé
Un objet COM qui contient un identificateur de classe unique. Il implémente au moins une interface COM - IUnknown (toute interface COM a un identifiant d'interface unique). Différentes implémentations d'un objet COM peuvent avoir le même identificateur de classe (exemple: version de publication et de débogage).
Serveur COM (2)Une bibliothèque liée dynamiquement (pour Linux, c'est un objet partagé - donc) qui implémente au moins un objet COM. Le serveur doit exporter un ensemble spécifique de fonctions:
extern "C" bool DllCreateInstance(const uiid& iid, void** ppv)
Crée un objet de classe par clsuid, augmente le nombre de références à ainsi, chaque fois que l'objet est créé avec succès. L'appel à IUnknown :: AddRef doit également augmenter le nombre de références pour ainsi, et IUnknown :: Release doit diminuer.
extern "C" bool DllCanUnloadNow()
Si le nombre de références à SO est 0, vous pouvez décharger la bibliothèque.
extern "C" bool DllRegisterServer(IUnknown* unknown)
Enregistre tous les serveurs clsuid dans le «registre». Appelé une fois lors de l'installation du serveur COM.
extern "C" bool DllUnRegisterServer(IUnknown* unknown)
Supprime des entrées de «registre» sur le serveur clsuid enregistré. Appelé une fois lors de la désinstallation du serveur COM.
Exemple SimpleHello, déclarez l'interface IHello: struct IHello : public virtual Dom::IUnknown { virtual void Print() = 0; define_uiid(Hello) };
Implémentation de l'interface: class SimpleHello : public Dom::Implement<SimpleHello, IHello> { public: SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } ~SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } virtual void Print() { printf("Hello from %s\n",__PRETTY_FUNCTION__); } define_clsuid(SimpleHello) }; 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)) {
Un ensemble de macros masque les implémentations de fonctions en fournissant une déclaration et une logique plus structurées.
Dom :: Implement <SimpleHello, IHello> - masque l'implémentation des méthodes d'interface IUnknown, ajoute du «sucre» lors de la déclaration des interfaces implémentées par un objet (C ++ 11 et modèles variadic):
template <typename T, typename ... IFACES> struct Implement : virtual public IUnknown, virtual public IFACES… { ... };
Interface IRegistryServer - définit un ensemble de méthodes pour travailler avec le «registre» des serveurs COM.
«Registre» des serveurs COM (3)L'importance du registre peut être sous-estimée, mais il s'agit probablement du principal pilier de COM. Microsoft écrit dans le registre, crée une structure complexe pour décrire les interfaces et leurs attributs (idl), je suis allé un peu différemment.
Dans l'implémentation, le registre est basé sur le système de fichiers.
Quel genre de petits pains? Comprendre, simplicité, la possibilité de récupération, un chignon spécial lors de l'enregistrement d'un serveur, vous pouvez définir une sorte d'espace de noms (un répertoire par rapport au registre de base dans lequel les objets serveur seront enregistrés), vous pouvez ainsi implémenter l'intégrité et la gestion des versions des applications à l'aide de la technologie.
Parmi les lacunes, les problèmes de sécurité possibles, la substitution des implémentations d'objets.
Comment utiliser, exemple d'application (4)Pour que tout fonctionne, vous aurez besoin d'une petite «bibliothèque» et d'un petit «programme».
La «bibliothèque» n'est rien de plus qu'un wrapper qui implémente et collecte tout dans un seul ensemble, travaillant avec le registre, chargeant / déchargeant le SO, créant des objets.
C'est le seul qui doit être spécifié lors de la construction de l'application. Tout le reste, «je veux croire», elle le fera elle-même.
" Programka " - regsrv est en fait un analogue du programme Microsoft RegSrv32 qui effectue les mêmes actions (+ la possibilité de spécifier un espace de noms, + la possibilité d'obtenir une liste des clsuid enregistrés et des serveurs COM).
échantillon #include "../include/dom.h" #include "../../skel/ihello.h" int main() { 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."); } return 0; }
Dom (5)Dom (Dynamic Object Model), mon implémentation pour Linux.
git clone
Je vous remercie