COMオブジェクト(1)
一般的に、少なくとも1つのCOMインターフェイスを実装するクラスのオブジェクト。 オブジェクトの実装は、主にCOMサーバーと呼ばれる動的に接続されたライブラリに隠されており(2) 、インターフェースは公開され、使用のために配布されます。
COMインターフェイス。純粋に仮想的な関数のみを含む抽象クラス。 特別なIUnknownインターフェイスが強調表示され、COMオブジェクトはこのインターフェイスを実装する必要があります。
各COMインターフェイスには、独自の識別子が含まれている必要があります。 COMでは、GUIDの構造によって決定され、ここでCOMの最初の欠点に直面します。 GUIDは理解不能であり、読み取り可能ではありません。 同じ必要がありますが、より読みやすく理解しやすい方法(uiidと呼びましょう)です。
IUnknownおよび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) }; }
インターフェイス識別子に加えて、オブジェクトの作成に必要なクラス識別子(clsuid)も割り当てられます。 私たちの場合、 これは本質を判断できる読みにくい識別子であり、今のところそれらの公開を忘れることができます(これは良くないかもしれません)。
まとめ
COMオブジェクト。単一のクラス識別子が含まれます。 少なくとも1つのCOMインターフェイスを実装します-IUnknown(すべてのCOMインターフェイスには一意のインターフェイス識別子があります)。 COMオブジェクトの異なる実装は、同じクラス識別子を持つことができます(例:リリースとデバッグバージョン)。
COMサーバー(2)
少なくとも1つのCOMオブジェクトを実装するダイナミックリンクライブラリ(Linuxの場合、共有オブジェクトです)。 サーバーは、特定の機能セットをエクスポートする必要があります。
extern "C" bool DllCreateInstance(const uiid& iid, void** ppv)
オブジェクトが正常に作成されるたびに、clsuidによってクラスオブジェクトを作成し、そのオブジェクトへの参照の数を増やします。 IUnknown :: AddRefの呼び出しもそのための参照カウントを増やし、IUnknown :: Releaseは減らす必要があります。
extern "C" bool DllCanUnloadNow()
SOへの参照の数が0の場合、ライブラリをアンロードできます。
extern "C" bool DllRegisterServer(IUnknown* unknown)
すべてのclsuidサーバーを「レジストリ」に登録します。 COMサーバーのインストール中に1回だけ呼び出されます。
extern "C" bool DllUnRegisterServer(IUnknown* unknown)
登録済みのclsuidサーバーに関する「レジストリ」エントリから削除します。 COMサーバーをアンインストールするときに1回呼び出されます。
SimpleHelloの例では、IHelloインターフェイスを宣言します。
struct IHello : public virtual Dom::IUnknown { virtual void Print() = 0; define_uiid(Hello) };
インターフェースの実装:
/* COM- */ 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) }; /* 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)) { // } return true; } DOM_SERVER_UNINSTALL(IUnknown* unknown) { Interface<IRegistryServer> registry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) { // } return true; } }
マクロのセットは、より構造化された宣言とロジックを提供することにより、関数の実装を隠します。
Dom ::実装<SimpleHello、IHello>-IUnknownインターフェイスメソッドの実装を非表示にし、オブジェクト(C ++ 11および可変長テンプレート)によって実装されたインターフェイスを宣言するときに「シュガー」を追加します。
template <typename T, typename ... IFACES> struct Implement : virtual public IUnknown, virtual public IFACES… { ... };
IRegistryServerインターフェイス-COMサーバーの「レジストリ」を操作するための一連のメソッドを定義します。
COMサーバーの「登録」 (3)
レジストリの重要性は過小評価されていますが、おそらくCOMの主要な柱です。 Microsoftはレジストリに書き込み、インターフェイスとその属性(idl)を記述するための複雑な構造を作成しますが、私は少し違った方法を取りました。
実装では、レジストリはファイルシステムに基づいています。
どんなパン? 理解しやすさ、シンプルさ、回復機能、サーバー登録時の特別なパン、ある種の名前空間(サーバーオブジェクトが登録されるベースレジストリに関連するディレクトリ)を設定できます。これにより、このテクノロジーを使用してアプリケーションの整合性とバージョン管理を実装できます。
欠点のうち、考えられるセキュリティ問題、オブジェクト実装の代替。
使用方法、サンプルアプリケーション(4)
すべてを機能させるには、小さな「ライブラリ」と小さな「プログラム」が必要です。
「ライブラリ」は、レジストリを操作し、SOをロード/アンロードし、オブジェクトを作成し、すべてを1つの全体に実装および収集するラッパーにすぎません。
これは、アプリケーションをビルドするときに指定する必要がある唯一のものです。 他のすべて、「信じたい」、彼女は自分でやります。
「 Programka 」 -regsrvは、実際には同じアクションを実行するMicrosoft RegSrv32プログラムの類似物です(+名前空間を指定する機能、登録済みのclsuidおよびCOMサーバーのリストを取得する機能)。
サンプル
#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; }
ドム(5)
Dom(動的オブジェクトモデル)、Linux用の私の実装。
git clone
ありがとう