أنا أحب تقنية COM. لكننا لن نتحدث عن التكنولوجيا أو الثناء أو أوجه القصور في COM ، ولكن تجربة النقل والتنفيذ على Linux. دراجة؟ النفعية؟
دعونا لا نركز على هذا.
كائن COM (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 يحتوي على معرف فئة واحد. يقوم بتنفيذ واجهة COM واحدة على الأقل - IUnknown (أي واجهة COM لها معرف واجهة فريد). يمكن أن يكون للتطبيقات المختلفة لكائن COM نفس معرف الفئة (مثال: إصدار الإصدار وتصحيحه).
خادم COM (2)مكتبة مرتبطة ديناميكيًا (بالنسبة إلى Linux فهي كائن مشترك - لذا) تنفذ كائن COM واحدًا على الأقل. يجب على الخادم تصدير مجموعة محددة من الوظائف:
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.
extern "C" bool DllUnRegisterServer(IUnknown* unknown)
حذف من إدخالات "التسجيل" حول خادم clsuid المسجل. يتم استدعاؤه مرة واحدة عند إلغاء تثبيت خادم COM.
مثال SimpleHello ، أعلن عن واجهة IHello: struct IHello : public virtual Dom::IUnknown { virtual void Print() = 0; define_uiid(Hello) };
تنفيذ الواجهة: 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)) {
تقوم مجموعة من وحدات الماكرو بإخفاء عمليات تنفيذ الوظائف من خلال توفير تعريف ومنطق أكثر تنظيمًا.
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 ، وإنشاء كائنات.
هو الوحيد الذي يجب تحديده عند إنشاء التطبيق. كل شيء آخر ، "أريد أن أصدق ،" ستفعل نفسها.
" Programka " - regsrv هو في الواقع تناظري من برنامج Microsoft RegSrv32 الذي يقوم بتنفيذ نفس الإجراءات (+ القدرة على تحديد مساحة الاسم ، + القدرة على الحصول على قائمة خوادم مسجلة وخوادم 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.
استنساخ بوابة
شكرا لك