| التغذية: ملاحظات الاحتكار العنوان: ملاحظات الدراسة على "مبادئ كوم والتطبيقات" | المؤلف: FGS_FGS تعليقات |
| ملاحظات الدراسة "مبادئ كوم وتطبيقات" - الجزء 1 مبادئ كوم http://savetime.delphibs.com وقت البدء: 2004.1.30 آخر تعديل: 2004.2.1 شكل هذا المقال هو: يتم لف النص تلقائيًا بواسطة النافذة ؛ (محتوى هذه المقالة مقتطف بشكل أساسي من كتاب "مبادئ وتطبيقات كوم". حقوق الطبع والنشر مملوكة للمؤلف بان إيمين. يرجى عدم استخدامه في وسائل الإعلام العامة) جدول المحتويات ================================================== ==================== =============================== ========= ⊙ الفصل 1 نظرة عامة ما هو كوم كوم الكائنات والواجهات نموذج العملية كوم إعادة استخدام ⊙ الفصل 2 نموذج كائن كوم معرف فريد من نوعه على مستوى العالم كوم كائن com واجهة الواجهة الوصف لغة IDL واجهة iunknown مبادئ واجهة كائنات com ⊙ الفصل 3 تنفيذ com معلومات تسجيل مكون com تسجيل مكونات com فئة المصنع ودالة dllgetObjectClass وظيفة cogetClassObject وظائف cocreateinstance / cocreateinstanceex تهيئة مكتبة كوم إدارة ذاكرة مكتبة كوم برامج التحميل وإلغاء تثبيت برامج المكونات وظائف شائعة لمكتبة كوم نوع hresult ⊙ الفصل 4 ميزات com قابلية إعادة الاستخدام: التضمين والتجميع شفافية العملية (المراد تعلمها) السلامة (المراد تعلمها) ميزات القراءة المتعددة (المراد تعلمها) ⊙ الفصل 5 تطوير تطبيقات com مع Visual C ++ وصف لبعض ملفات الرأس التي توفرها Win32 SDK بعض وحدات الماكرو المتعلقة بواجهة com ================================================== ==================== =============================== ========= نص ================================================== ==================== =============================== ========= ⊙ الفصل 1 نظرة عامة ================================================== ==================== =============================== ========= ما هو كوم ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- COM هو معيار مكون يقترحه Microsoft. في COM Standard ، يُطلق على برنامج المكون أيضًا وحدة نمطية. يمكن أن يحتوي برنامج المكون على كائن واحد أو أكثر من المكونات. ) هو حامل رمز يوفر كائنات com. تختلف كائنات COM عن مفهوم الكائن في اللغات الموجه نحو الكائنات (مثل C ++). كائنات كوم مستقلة عن اللغة. من الممكن التفاعل مع هذه الميزة مع كائنات المكونات التي تم تطويرها بواسطة لغات برمجة مختلفة. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- كوم الكائنات والواجهات ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- على غرار مفهوم الكائن في C ++ ، فإن الكائن هو مثيل للفئة ؛ يُطلق على التطبيق الذي يستخدم كائن (أو كائن آخر) عميلًا ، وأحيانًا يسمى مستخدم الكائن. الواجهة هي مجموعة من الوظائف ذات الصلة منطقياً ، وتسمى وظائفها أيضًا وظائف عضو الواجهة. وفقًا للعرف ، غالبًا ما يتم تسبق أسماء الواجهة بـ "I". توفر الكائنات للعملاء أشكالًا مختلفة من الخدمات من خلال وظائف أعضاء الواجهة. في نموذج COM ، يكون الكائن نفسه غير مرئي للعميل ، وعندما تطلب العميل خدمة الخدمة ، لا يمكن تنفيذها إلا من خلال الواجهة. يتم تحديد كل واجهة من خلال معرف فريد من نوعه على مستوى عالمي 128 بت (GUID). يحصل العميل على مؤشر الواجهة من خلال GUID ، ثم يمرر مؤشر الواجهة ، ويمكن للعميل استدعاء وظيفة العضو المقابلة. على غرار الواجهات ، يتم تحديد كل مكون أيضًا بواسطة GUID 128 بت ، يسمى CLSID (معرف الفئة ، معرف الفئة أو معرف الفئة). في الواقع ، بعد أن يقوم العميل بإنشاء الكائن بنجاح ، يحصل على مؤشر إلى واجهة للكائن. كل الخدمات. وفقًا لمواصفات COM ، إذا قام كائن COM بتنفيذ واجهات متعددة ، فيمكن الحصول على أي واجهة أخرى للكائن من واجهة معينة. من هذه العملية ، يمكننا أيضًا أن نرى أن العميل يتعامل فقط مع كائن COM من خلال واجهات ، والكائن هو مجرد مجموعة من واجهات العميل. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- نموذج العملية ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تحتوي كائنات مكون الخدمة التي توفرها COM على نموذجين للعملية عند التنفيذ: الكائنات في العملية والكائنات الخارجية. إذا كان كائنًا في العملية ، فإنه يعمل في مساحة عملية العميل ؛ برنامج الخدمة في العملية: يتم تحميل برنامج الخدمة في مساحة عملية العميل. برامج الخدمة المحلية: يعمل برنامج الخدمة على نفس الجهاز مثل برنامج العميل. برنامج الخدمة عن بُعد: يعمل برنامج الخدمة على جهاز مختلف عن العميل ، ويمكن أن يكون إما وحدة DLL أو ملف EXE. إذا تم تنفيذ برنامج الخدمة عن بُعد في نموذج DLL ، فإن الجهاز البعيد ينشئ عملية وكيل. على الرغم من أن كائنات COM لها نماذج عملية مختلفة ، إلا أن هذا الاختلاف شفاف لبرامج العميل. ومع ذلك ، عند تطبيق كائنات COM ، لا يزال يتعين عليك اختيار نموذج العملية بعناية. تتمثل ميزة النماذج في العملية في أنها فعالة ، لكن المكونات غير المستقرة ستؤدي إلى تعطل عملية العميل ، وبالتالي فإن المكونات قد تعرض العميل للخطر ؛ -سيواجه نموذج العمليات أيضًا مشاكل ، والتي قد تكون لأن المكونات والعملاء في هذه العملية في نفس مساحة العنوان ، وهناك احتمال كبير للصراع؟ لا يمكن لعملية المكونات أن تقدم عملية مكونات واحدة لعملية العميل. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- كوم إعادة استخدام ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- نظرًا لأن معيار COM يعتمد على مستوى التعليمات البرمجية الثنائية ، فإن إعادة استخدام كائنات COM تختلف عن عملية إعادة استخدام الكائنات باللغات العامة الموجهة للكائنات مثل C ++. بالنسبة لبرنامج عميل كائن COM ، فإنه يستخدم الخدمات التي يوفرها الكائن فقط من خلال الواجهة ، ولا يعرف عملية التنفيذ داخل الكائن. بدلاً من التنفيذ المحدد. يستخدم COM آليتين لتحقيق إعادة استخدام الأشياء. نحن نفترض أن هناك كائنين com ، ويأمل الكائن 1 إعادة استخدام وظيفة الكائن 2. نسمي الكائن 1 كائن خارجي وكائن 2 كائن داخلي. (1) طريقة شاملة. الكائن 1 يحتوي على كائن 2. عندما يحتاج الكائن 1 إلى استخدام وظيفة الكائن 2 ، يمكنه ببساطة تسليم التنفيذ إلى الكائن 2 ، يسمى تنفيذ الكائن 2. (2) طريقة التجميع. لا يقوم الكائن 1 بتقديم واجهة الكائن 2 إلى العميل. يخرج. ================================================== ==================== =============================== ========= ⊙ الفصل 2 نموذج كائن كوم ================================================== ==================== =============================== ========= معرف فريد من نوعه على مستوى العالم ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تستخدم مواصفات COM معرفًا فريدًا من 128 بت على مستوى عالمي لتحديد الكائنات والواجهات ، وهي أرقام عشوائية ولا تتطلب وكالات متخصصة لتخصيص وإدارة. نظرًا لأن GUID هو رقم عشوائي ، فإن التفرد ليس مضمونًا تمامًا ، لكن إمكانية مضاعفة المعرفات صغيرة جدًا. من الناحية النظرية ، إذا كانت الآلة تولد 100،000،000 GUIDS في الثانية ، فيمكن ضمان عدم تكرار 3240 عامًا (بمعنى الاحتمال). يمكن وصف GUID في C/C ++ باستخدام هذا الهيكل: Typedef struct _guid { DWORD DATA1 ؛ بيانات Word2 ؛ Word Data3 ؛ Byte Data4 [8] ؛ } guid ؛ مثال: {64BF4372-1007-B0AA-444553540000} يمكنك تحديد GUID على النحو التالي: extern "C" const guid clsid_myspellchecker = {0x54bf0093 ، 0x1048 ، 0x399d ، {0xb0 ، 0xa3 ، 0x45 ، 0x33 ، 0x43 ، 0x90 ، 0x47 ، 0x47}} ؛ يوفر Visual C ++ برنامجين لإنشاء GUIDS: uuidgen.exe (سطر الأوامر) و Guidgen.exe (مربع الحوار). توفر مكتبة COM وظائف API التالية التي يمكن أن تولد GUIDS: Hresult CoCreateguid (Guid *pguid) ؛ إذا تم إنشاء GUID بنجاح ، فإن الدالة تُرجع S_OK و PGUID إلى قيمة GUID الناتجة. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- كوم كائن ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- في مواصفات COM ، لا يتم تعريف كائنات COM بدقة ، ولكن يوفر COM نموذج مكون موجه نحو الكائن ، وتوفر مكونات COM للعملاء كيانات مغلفة في شكل كائن. الكيان الذي يتفاعل فيه برنامج العميل مع برنامج COM هو كائن COM. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- com واجهة ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- من الناحية الفنية ، فإن الواجهة هي بنية بيانات تحتوي على مجموعة من الوظائف ، يمكن من خلالها رمز العميل استدعاء وظائف كائنات المكونات. تحدد الواجهة مجموعة من وظائف الأعضاء ، والتي تعتبر جميع المعلومات المكشوفة بواسطة كائنات مكونة. عادةً ما نسمي جدول الوظائف الظاهرية لجدول وظيفة الواجهة (VTABLE) ، والمؤشر إلى VTABLE هو PVTABLE. بالنسبة للواجهة ، يتم تحديد جدول الوظائف الافتراضية ، وبالتالي فإن عدد وظائف الأعضاء في الواجهة لم يتغير ، كما أن ترتيب وظائف الأعضاء لم يتغير أيضًا ؛ في تعريف الواجهة ، يجب تحديد كل هذه المعلومات على المستوى الثنائي. Interface Pointer ----> Pvtable ----> Pointer function 1-> | ----------- | M_DATA1 مؤشر وظيفة 2 -> | وظيفة مؤشر M_DATA2 3-> | ------------ | المعلمة الأولى لكل وظيفة عضو في الواجهة هي مؤشر إلى مثيل الكائن (= هذا). معلومات. في وظائف عضو الواجهة ، يجب أن تستخدم متغيرات السلسلة مؤشرات أحرف Unicode. لذلك ، إذا تم استخدام أحرف ANSI داخل برنامج المكون ، فيجب تحويل تعبيرين من الأحرف. بالطبع ، في حالة إنشاء برامج المكونات وبرامج العميل ، يمكنك استخدام أنواع المعلمات التي تحددها نفسك طالما أنها متوافقة مع أنواع المعلمات التي يمكن أن تتعرف عليها COM. يوفر Visual C ++ تحويلين للسلسلة: مساحة الاسم _com_util { BSTR ConvertStringTobstr (const char *psrc) رمي (_com_error) ؛ BSTR ConvertBStRttring (BSTR PSRC) رمي (_com_error) ؛ } BSTR عبارة عن سلسلة عرض مزدوجة ذات عرض مزدوج ، وهي نوع البيانات الآلي الأكثر استخدامًا. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- الواجهة الوصف لغة IDL ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تستخدم مواصفات COM مواصفات DCE لـ OSF لوصف واجهة الاتصال عن بُعد IDL (لغة الوصف الواجهة) وتتوسع لتشكيل لغة الوصف لواجهة COM. توفر لغة الواجهة طريقة الوصف للواجهات التي لا تعتمد على أي لغة ، بحيث يمكن أن تصبح لغة شائعة بين برامج المكونات وبرامج العميل. لا يمكن استخدام لغة الوصف IDL المستخدمة في مواصفات COM لتحديد واجهة COM ، ولكن أيضًا تحديد بعض أنواع البيانات الشائعة الاستخدام وهياكل البيانات المخصصة. الميزات ، حتى أوصاف المصفوفات المتغيرة. يدعم IDL أنواع المؤشرات ، والتي تشبه إلى حد كبير C/C ++. على سبيل المثال: interface idictionary { HRESULT تهيئة () Hresult LoadLibrary ([في] سلسلة) ؛ Hresult insertword ([in] string ، [in] string) ؛ Hresult Deleteword ([in] string) ؛ Hresult Lookupword ([in] string ، [out] string *) ؛ Hresult Restorelibrary ([في] سلسلة) ؛ hresult freelibrary () ؛ } يوفر Microsoft Visual C ++ أدوات MIDL التي يمكنها تجميع ملفات الوصف IDL في C/C ++-واجهة متوافقة وصفات رأس الوصف (.H). ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- واجهة iunknown ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تعريف IDL Iunknown: واجهة iunknown { hresult queryInterface ([in] refiid iid ، [out] void ** ppv) ؛ Ulong Addref (void) ؛ legong relear (void) ؛ } تعريف Iunkown's C ++: الفصل iunknown { فيروس hresult _stdcall QueryInterface (const iid & iid ، void ** ppv) = 0 ؛ الافتراضية Ulong _StdCall AddRef () = 0 ؛ فيروس Ulong _StdCall release () = 0 ؛ } ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- مبادئ واجهة كائنات com ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تحدد مواصفات COM القواعد التالية لوظيفة QueryInterface: 1. بالنسبة إلى مؤشرات واجهة مختلفة من نفس الكائن ، يجب أن تكون واجهة iunknown التي تم الحصول عليها عن طريق الاستعلام هي نفسها تمامًا. وهذا هو ، مؤشر واجهة iunknown لكل كائن فريد من نوعه. لذلك ، بالنسبة لمؤشري الواجهة ، يمكننا تحديد ما إذا كانت تشير إلى نفس الكائن من خلال الحكم على ما إذا كانت واجهات iunknown التي يستفسرونها متساوية. 2. يجب أن ينجح الاستعلام عن واجهة نفسها دائمًا ، على سبيل المثال: piirictionary-> QueryInterface (IID_Dictionary ، ...) يجب أن يعيد S_OK. 3. تماثل الواجهة. إذا قمت بالاستعلام من مؤشر واجهة إلى مؤشر واجهة آخر ، فيجب أن تنجح العودة من مؤشر الواجهة الثاني إلى مؤشر الواجهة الأول ، على سبيل المثال: PIIDICTINARY-> QueryInterface (iid_spellcheck ، (void **) & pispellcheck) ؛ إذا نجح البحث ، فسيكون التحقق من واجهة IID_Dictionary من Pispellcheck ناجحًا مرة أخرى. 4. واجهة العبور. إذا قمت بالاستعلام عن مؤشر الواجهة الثانية من مؤشر الواجهة الأول ومؤشر الواجهة الثالث يمكن الاستعلام عنه من مؤشر الواجهة الثاني ، فيمكنك بالتأكيد الاستعلام عن مؤشر الواجهة الأول من مؤشر الواجهة الثالث. 5. واجهة الاستعلام الوقت غير ذي صلة. إذا كان من الممكن العثور على مؤشر واجهة معين في لحظة معينة ، فسيتم فحص مؤشر الواجهة نفسه في أي وقت في المستقبل ، وسيكون الاستعلام ناجحًا بالتأكيد. باختصار ، بغض النظر عن الواجهة التي نبدأ منها ، يمكننا دائمًا الوصول إلى أي واجهة ، ويمكننا دائمًا العودة إلى الواجهة الأصلية. ================================================== ==================== =============================== ========= ⊙ الفصل 3 تنفيذ com ================================================== ==================== =============================== ========= معلومات تسجيل مكون com ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- معلومات حول جميع المكونات على الجهاز الحالي HKEY_CLASS_ROOT/CLSID مكون في العملية HKEY_CLASS_ROOT/CLSID/GUID/Inprocserver32 مكون خارج العملية HKEY_CLASS_ROOT/CLSID/GUID/OLCALSERVER32 الفئة التي المكون (CATID) HKEY_CLASS_ROOT/CLSID/GUID/فئات تنفيذها معلومات تكوين واجهة com hkey_class_root/واجهة وكيل DLL/Stub DLL HKEY_CLASS_ROOT/CLSID/GUID/PROXYSTUBCLSID HKEY_CLASS_ROOT/CLSID/GUID/PROXYSTUBCLSID32 معلومات حول نوع المكتبة hkey_class_root/typelib سلسلة تسمية progid hkey_class_root/ (على سبيل المثال "comctl.treectrl") مكون Guid Hkey_class_root/comtrl.treecontrol/clsid رقم الإصدار الافتراضي HKEY_CLASS_ROOT/COMTRL.TREECONTROL/CURVER (على سبيل المثال curver = "comtrl.treectrl.1" ، ثم hkey_class_root/comtrl.treecontrol.1 موجود أيضًا) جميع فئات المكونات من الجهاز الحالي HKEY_CLASS_ROOT/COMPONENT يوفر COM وظيفتين API clsidfromprogid و progidFromClsid لتحويل progid و clsid. إذا كان مكون COM يدعم نفس مجموعة الواجهات ، فيمكن تصنيفها في نفس الفئة ، ويمكن تصنيف المكون في فئات متعددة. على سبيل المثال ، إذا كانت جميع كائنات الأتمتة تدعم واجهة Idispatch ، فيمكن تصنيفها على أنها "كائنات أتمتة". يتم وصف معلومات الفئة أيضًا بواسطة GUID ، تسمى Catid. الغرض الرئيسي من فئات المكونات هو أنه يمكن للعملاء اكتشاف أنواع محددة من الكائنات المكونة بسرعة على الجهاز. يمكن للواجهة ، التي تستخدم الآن فئات المكونات ، حفظ عملية الاستعلام. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تسجيل مكونات com ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- يتم استخدام REGSRV32.EXE لتسجيل مكون في العملية ، والذي يطلق على وظائف DLLREGISTERSERVER و DLLUNREGISTERSERVER من DLL لإكمال تسجيل وإلغاء برنامج المكون. إذا كانت العملية ناجحة ، فأعود صحيحًا ، وإلا عد كاذبة. بالنسبة لبرامج المكونات خارج العملية ، يكون الموقف مختلفًا قليلاً لأنه برنامج قابل للتنفيذ بحد ذاته ولا يمكنه توفير وظائف دخول لاستخدام البرامج الأخرى. لذلك ، تنص مواصفات COM على أن المكونات خارج العملية التي تدعم التسجيل الذاتي يجب أن تدعم معلمات سطر الأوامر /regserver و /unregserver لإكمال عمليات التسجيل والإلغاء. تعتمد معلمات سطر الأوامر على الحالات ، و "/" يمكن استبدالها بـ "-". إذا نجحت العملية ، فإن البرنامج يعود 0 ، وإلا ، فإن إرجاع عدم 0 يعني الفشل. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- فئة المصنع ودالة dllgetObjectClass ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- Class Factory هي قاعدة إنتاج كائنات COM. يعد المصنع للصف نفسه أيضًا كائن COM ، والذي يدعم واجهة خاصة ICLASSFACTORY: فئة iclassfactory: عام iunknown { الافتراضي hresult _stdcall createInstance (iunknown *punknownouter ، const iid & iid ، void ** ppv) = 0 ؛ الافتراضية hresult _stdcall lockserver (bool block) = 0 ؛ } يتم استخدام وظيفة CreateInstance Member لإنشاء كائن COM المقابل. يتم استخدام المعلمة الأولى PunkNownouter للحالة التي يتم فيها تجميع فئة الكائن ، ويتم ضبطها بشكل عام على المعلمة الثانية IID هي الواجهة الأولية التي يجب أن تحصل عليها العميل بعد أن يتم إنشاء الكائن ؛ مؤشر واجهة. يتم استخدام وظائف عضو Lockserver للتحكم في عمر المكون. يتم إنشاء كائن مصنع الفصل بواسطة الدالة المشتقة من DLL dllgetClassObject: Hresult dllgetClassObject (const clsid & clsid ، const iid & iid ، (void **) ppv) ؛ المعلمة الأولى من دالة dllgetClassObject هي clsid للكائن المراد إنشاؤه. نظرًا لأن المكون قد ينفذ فئات كائن COM متعددة ، فمن الضروري تحديد CLSID في معلمات وظيفة dllgetClassObject لإنشاء مصنع الفئة الصحيح. تشير المعلمتان الأخريان IID و PPV إلى الواجهة المحددة IID ومؤشر واجهة مصنع فئة التخزين ، على التوالي. بعد تلقي التعليمات لإنشاء كائن ، تقوم مكتبة COM باستدعاء وظيفة dllgetClassObject للمكون في العملية ، وإنشاء كائن مصنع الفصل من الوظيفة ، وإرجاع مؤشر الواجهة لكائن مصنع الفصل. بمجرد أن يكون لدى مكتبة COM أو عميل مؤشر واجهة إلى مصنع الفصل ، يمكنهم إنشاء كائن COM المقابل من خلال وظيفة الأعضاء إنشاء ICLASSFACTORY. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- وظيفة cogetClassObject ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- في مكتبة COM ، هناك ثلاثة واجهات برمجة التطبيقات التي يمكن استخدامها لإنشاء الكائنات ، وهي CogetClassObject و CoCreateInstnace و CoCreateinstanceEx. عادة ، يقوم برنامج العميل باستدعاء أحدهم لإكمال إنشاء الكائن وإرجاع مؤشر الواجهة الأولي للكائن. تتفاعل مكتبة COM ومصنع الفصل أيضًا من خلال هذه الوظائف الثلاث. Hresult CogetClassObject (const clsid & clsid ، dword dwclscontext ، CoserverInfo *pserverInfo ، const iid & iid ، (void **) ppv) ؛ تجد وظيفة CogetClassObject أولاً مصنع الفئة من فئة COM المحددة بواسطة CLSID ، ثم تتصل بكائن مصنع الفصل. إذا كان كائن مكون في العملية ، فإن CogetClassObject يستدعي dllgetClassObject لوحدة DLL لإدخال الوظيفة ، وتمرير المعلمات CLSID و IID و PPV إلى دالة dllgetClassObject ، وإرجاع مؤشر الواجهة لكائن مصنع الفئة. عادة ، IID هو معرف IID_ICLASSFACTORY من ICLASSFACTORY. إذا كان كائن مصنع الفصل يدعم أيضًا واجهات أخرى يمكن استخدامها لإنشاء عمليات ، فيمكن أيضًا استخدام معرفات الواجهة الأخرى. على سبيل المثال ، قد يُطلب من واجهة ICLASSFACTORY2 التحقق من حالة ترخيص المستخدم في وقت الإنشاء. واجهة ICLASSFACTORY2 هي امتداد لـ ICLASSFACTORY ، مما يعزز أمان إنشاء المكون. تحدد المعلمة DWCLSContext فئة المكون ، والتي يمكن تحديدها كمكون في العملية ، أو مكونًا خارج العمليات أو كائن تحكم في العملية (على غرار كائن الوكيل لمكون خارج العملية ، يستخدم بشكل رئيسي في التكنولوجيا OLE). تتوافق المعلمات IID و PPV مع معلمات dllgetClassObject ، على التوالي ، وتستخدم لتحديد الواجهة IID ومؤشر الواجهة لتخزين كائن الفئة. يتم استخدام المعلمة pserverInfo لتحديد معلومات الخادم عند إنشاء كائنات عن بُعد عند إنشاء كائنات مكون في العملية أو مكونات محلية خارج العملية. يكون الموقف أكثر تعقيدًا إذا كان كائن مصنع الفصل الذي تم إنشاؤه بواسطة وظيفة CogetClassObject موجودة في مكون خارج العملية. أولاً ، تبدأ وظيفة CogetClassObject عملية المكون ثم تنتظر حتى تقوم عملية المكون بتسجيل مصنع الفئة لكائن فئة COM الذي يدعمه COM. وبالتالي فإن وظيفة cogetClassObject تُرجع معلومات مصنع الفصل المقابلة في com. لذلك ، عندما يتم بدء عملية خارج المكون من قبل مكتبة COM (مع معلمة سطر الأوامر "/تضمين") ، يجب أن تسجل كائنات مصنع COM المدعومة في COM من خلال وظيفة CoreGisterClassObject حتى تتمكن مكتبة COM إنشاء كائنات com للاستخدام. عندما تخرج العملية ، يجب استدعاء وظيفة CoreVokEcleSoBject لإخطار كوم بأن كائن مصنع الفصل الذي تم تسجيله لم يعد صالحًا. يستدعي برنامج المكون وظيفة CoreGisterClassObject وينبغي إقران وظيفة CoreVokEcLassObject لضمان اتساق معلومات COM. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- وظائف cocreateinstance / cocreateinstanceex ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- Hresult Cocreateinstance (Const Clsid & Clsid ، Iunknown *Punknownouter ، dword dwclscontext ، const iid & iid ، (void **) ppv) ؛ CoCreateInstance هي وظيفة مساعد ملفوفة تستدعي فعليًا وظيفة CogetClassObject بداخلها. إن معنى المعلمات CLSID و DWCLSContext من coCreateinStance يتوافق مع المعلمات المقابلة لـ CogetClassObject (معلمات IID و PPV في cocreateinstance تختلف عن الفئة CogetClassObject ، والمرء هو معلومات الواجهة التي تمثل الكائن ، والآخر هو معلومات الواجهة هي التي تمثل الفئة مصنع). يتوافق المعلمة PunkNownouter مع المعلمات المقابلة في إنشاء واجهة مصنع الفصل ، ويستخدم بشكل رئيسي في الحالة التي يتم فيها تجميع الكائنات. تُغلف وظيفة Cocreateinstance عملية إنشاء كائنات من خلال مصنع الفصل. يمكن تنفيذ cocreateinstance مع الكود التالي: (ملاحظة التوقيت: يبدو أن تطبيق مؤشر PPV في الكود التالي باطلة **) Hresult Cocreateinstance (Const Clsid & Clsid ، Iunknown *Punknownouter ، dword dwclscontext ، const iid & iid ، void *ppv) { iclassfactory *PCF ؛ Hresult HR ؛ HR = CogetClassObject (clsid ، dwclscontext ، null ، iid_iclassfactory ، (void *) PCF) ؛ إذا (فشل (HR)) إرجاع الموارد البشرية ؛ hr = pcf-> createInstance (punknownouter ، iid ، (void *) ppv) ؛ pfc-> regle () ؛ إرجاع الموارد البشرية ؛ } من هذا الرمز ، يمكننا أن نرى أن وظيفة Cocreateinstance تستخدم أولاً وظيفة CogetClassObject لإنشاء كائن مصنع الفصل ، ثم يستخدم مؤشر واجهة كائن مصنع الفصل لإنشاء كائن COM حقيقي. عاد ، بحيث يتم استخدام الفصل. ومع ذلك ، فإن استخدام CoCreateInstance لا ينشئ كائنًا على الجهاز البعيد ، لأنه عند استدعاء CogetClassObject ، يتم تعيين المعلمة الثالثة المستخدمة لتحديد معلومات الخادم على NULL. إذا كنت ترغب في إنشاء كائن بعيد ، فيمكنك استخدام وظيفة تمديد CoCreateInstance CoCreateInstanceEx: Hresult CoCreateinstanceEx (const clsid & clsid ، iunknown *punknownouter ، DWORD DWCLSCONTEXT ، COSERVERINFO *pserverInfo ، DWORD DWCOUNT ، multi_qi *rgmultiqi) ؛ المعلمات الثلاثة الأولى هي نفس المعلمات CoCreateInstance. المؤشرات الواجهة. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تهيئة مكتبة كوم ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- قبل استدعاء وظائف مكتبة COM ، من أجل جعل الوظيفة صالحة ، يجب أن تسمى وظيفة تهيئة مكتبة COM: hresult coinitialize (imalloc *pmalloc) ؛ يتم استخدام PMALLOC لتحديد مخصص الذاكرة ، ويمكن تحديد مبدأ تخصيص الذاكرة بواسطة التطبيق. بشكل عام ، إذا قمنا بتعيين المعلمة مباشرة على NULL ، فستستخدم مكتبة COM جهاز الذاكرة الافتراضي المتوفر. قيمة الإرجاع: S_OK تعني التهيئة ناجحة يشير S_False إلى أن التهيئة ناجحة ، لكن هذه المكالمة ليست هي المرة الأولى التي يتم فيها استدعاء وظيفة التهيئة في هذه العملية. يشير S_Unexed إلى حدوث خطأ أثناء عملية التهيئة ولا يمكن للتطبيق استخدام مكتبة COM. عادةً ما تقوم العملية بتهيئة مكتبة COM مرة واحدة فقط ، وليس من المنطقي تهيئة مكتبة COM عدة مرات في نفس وحدة الوحدة. الوظيفة الوحيدة التي لا تحتاج إلى تهيئة مكتبة COM هي الحصول على إصدار مكتبة COM: dword cobuildversion () ؛ قيمة الإرجاع: رقم الإصدار الرئيسي ذي 16 بت مرتفع رقم الإصدار أقل من 16 رقمًا بعد أن يستخدم برنامج COM خدمة مكتبة COM ، عادة قبل خروج البرنامج ، من الضروري استدعاء وظيفة خدمة مكتبة COM المنتهية لتحرير الموارد التي تحتفظ بها مكتبة COM: void couninitialize (void) ؛ ملاحظة: يجب أن يكون لدى أي عملية أو وحدة برنامج تستدعي وظيفة coinitialize وإرجاع S_OK استدعاء وظيفة couninitialize المقابلة لضمان استخدام مكتبة COM بشكل فعال الموارد. (؟ إذا تم استدعاء Coinitialize في وحدة نمطية وإرجاع S_OK ، فهل ستحصل الوحدات الأخرى التي تستخدم مكتبة COM أيضًا على أخطاء بعد استدعاء وظيفة counitialize؟ أو هل ستتحقق مكتبة COM تلقائيًا من الوحدات المستخدمة؟) ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- إدارة ذاكرة مكتبة كوم ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- نظرًا لأن برامج مكونات COM وبرامج العميل متصلة من خلال معايير المستوى الثنائي ، فإن جميع العمليات التي تتضمن تفاعلات الذاكرة بين العملاء ومكتبات COM ومكونات (التخصيص والإصدار ليست في نفس الوحدة) في تطبيقات COM يجب استخدامها مدير ذاكرة ثابت. معيار إدارة الذاكرة الذي توفره COM هو في الواقع واجهة imalloc: // IID_IMALLOC: {00000002-0000-0000-C000-00000000000046} فئة imalloc: عام iunknown { void * inloc (Ulong CB) = 0 ؛ void * realloc (void * pv ، ulong cb) = 0 ؛ void free (void *pv) = 0 ؛ GetSize (void *pv) = 0 ؛ int didalloc (void *pv) = 0 ؛ void heapminimize () = 0 ؛ // نظام التشغيل لتحسين الأداء } الحصول على مؤشر واجهة imalloc: Hresult CogetMalloc (Dword dwmemcontext ، imalloc ** ppmalloc) ؛ يتم استخدام المعلمة الأولى لدالة CogetMalloc DWMemContext لتحديد نوع مدير الذاكرة. تحتوي مكتبة COM على مديري الذاكرة ، أحدهما هو مدير الذاكرة المحدد أثناء التهيئة أو مديرها الافتراضي الداخلي ، المعروف أيضًا باسم مدير المهام (تخصيص المهمة). MEMCTX_TASK في معلمة DWMEMCONTEXT ؛ العملية ونقلها إلى عملية ثانية ، باستخدام هذه الذاكرة في العملية الثانية أو حتى إطلاقها. طالما أن قيمة الإرجاع للوظيفة هي S_OK ، تشير PPMALLOC إلى مؤشر واجهة MEMORMENT لمكتبة COM ، ويمكنك استخدامها لأداء عمليات الذاكرة. تقوم مكتبة COM بتغليف ثلاث وظائف API التي يمكن استخدامها لتخصيص الذاكرة وإصدارها: void * cotaskMemalloc (Ulong CB) ؛ void cotaskfree (void *pv) ؛ void cotaskmemrealloc (void *pv ، ulong cb) ؛ يتم تعيين هذه الوظائف الثلاثة لثلاث وظائف أعضاء تتوافق مع imalloc: incloc ، realloc ، و free. مثال: كيف يجد برنامج COM قيمة progid المقابلة من قيمة CLSID: wchar *pwprogid ؛ char pszprogid [128] ؛ hresult = :: progIdFromClsid (clsid_dictionary ، & pwprogid) ؛ if (hresult! = s_ok) { ... } wcstombs (pszprogid ، pwprogid ، 128) ؛ CotaskMemfree (pwprogid) ؛ بعد استدعاء وظيفة com progidfromclsid للعودة ، لأن مكتبة COM تخصص مساحة الذاكرة لمتغير الإخراج pwprogid ، يجب أن يتصل التطبيق بوظيفة cotaskmemfree لتحرير الذاكرة بعد استخدام متغير pwprogid. يوضح هذا المثال الموقف الذي يتم فيه تخصيص الذاكرة في مكتبة COM ويتم تحرير الذاكرة في برنامج الاتصال. تحتوي بعض الوظائف الأخرى في مكتبة COM أيضًا على خصائص مماثلة ، خاصة بعض الوظائف التي تحتوي على معلمات إخراج الطول غير المحددة. ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- برامج التحميل وإلغاء تثبيت برامج المكونات ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- تحميل المكونات في العملية: يستدعي برنامج العميل وظيفة CocreateInstance أو CogetClassObject لمكتبة COM لإنشاء كائن COM في COGETCLASSOBJECT the system registry, and then calls LoadLibrary( It is actually a CoLoadLibrary function, and calls the DllGetClassObject of the component program to introduce the function. DllGetClassObject 函数创建相应的类厂对象,并返回类厂对象的IClassFactory 接口。至此CoGetClassObject 函数的任务完成,然后客户程序或者CoCreateInstance 函数继续调用类厂对象的CreateInstance 成员函数,由它负责COM 对象的创建工作。 CoCreateInstance |-CoGetClassObject |-Get CLSID -> DLLfile path |-CoLoadLibrary |-DLLfile.DllGetClassObject |-return IClassFactory |-IClassFactory.CreateInstnace 进程外组件的装载: 在COM 库的CoGetClassObject 函数中,当它发现组件程序是EXE 文件(由注册表组件对象信息中的LocalServer 或LocalServer32 值指定)时,COM 库创建一个进程启动组件程序,并带上“/Embedding”命令行参数,然后等待组件程序;而组件程序在启动后,当它检查到“/Embedding”命令行参数后,就会创建类厂对象,然后调用CoRegisterClassObject 函数把类厂对象注册到COM 中。当COM 库检查到组件对象的类厂之后,CoGetClassObject 函数就把类厂对象返回。由于类厂与客户程序运行在不同的进程中,所以客户程序得到的是类厂的代理对象。一旦客户程序或COM 库得到了类厂对象,它就可以完成组件对象的创建工作。 进程内对象和进程外对象的不同创建过程仅仅影响了CoGetClassObject 函数的实现过程,对于客户程序来说是完全透明的。 CoGetClassObject |-LocalServer/LocalServer32 |-Execute EXE /Embedding |-Create class factory |-CoRegisterClassObject ( class factory ) |-return class factory (proxy) 进程内组件的卸载: 只有当组件程序满足了两个条件时,它才能被卸载,这两个条件是:组件中对象数为0,类厂的锁计数为0。满足这两个条件时,DllCanUnloadNow 引出函数返回TRUE。COM 提供了一个函数CoFreeUnusedLibraries,它会检测当前进程中的所有组件程序,当发现某个组件程序的DllCanUnloadNow 函数返回TRUE 时,就调用FreeLibrary 函数(实际上是CoFreeLibrary 函数)把该组件从程序从内存中卸出。 该由谁来调用CoFreeUnusedLibraries 函数呢?因为在组件程序执行过程中,它不可能把自己从内存中卸出,所以这个任务应该由客户来完成。客户程序随时都可以调用CoFreeUnusedLibraries 函数完成卸出工作,但通常的做法是,在程序的空闲处理过程中调用CoFreeUnusedLibraries 函数,这样做既可以避免程序中处处考虑对CoFreeUnusedLibraries 函数的调用,又可以使不再使用的组件程序得到及时清除,提高资源的利用率,COM 规范也推荐这种做法。 进程外组件的卸载: 进程外组件的卸载比较简单,因为组件程序运行在单独的进程中,一旦其退出的条件满足,它只要从进程的主控函数返回即可。在Windows 系统中,进程的主控函数为WinMain。 前面曾经说过,在组件程序启动运行时,它调用CoRegisterClassObject 函数,把类厂对象注册到COM 中,注册之后,类厂对象的引用计数始终大于0,因此单凭类厂对象的引用计数无法控制进程的生存期,这也是引入类厂对象的加锁和减锁操作的原因。进程外组件的载条件与DllCanUnloadNow 中的判断类似,也需要判断COM 对象是否还存在、以及判断是否锁计数器为0,只有当条件满足了,进程的主函数才可以退出。 从原则上讲,进程外组件程序的卸载就是这么简单,但实际上情况可能复杂一些,因为有些组件程序在运行过程中可以创建自己的对象,或者包含用户界面的程序在运行过程中,用户手工关闭了进程,那么进程对这些动作的处理要复杂一些。例如,组件程序在运行过程中,用户又打开了一个文件并进行操作,那么即使原先创建的对象被释放了,而且锁计数器也为0,进程也不能退出,它必须继续为用户服务,就像是用户打开的进程一样。对这种程序,可以增加一个“用户控制”标记flag,如果flag 为FALSE,则可以按简单的方法直接退出程序即可;如果flag 为TRUE,则表明用户参与了控制,组件进程不能马上退出,但应该调用CoRevokeClassObject 函数以便与CoRegisterClassObject 调用相响呼应,把进程留给用户继续进行。 如果组件程序在运行过程中,用户要关闭进程,而此时并不满足进程退出条件,那么进程可以采取两种办法:第一种方法,把应用隐藏起来,并把flag 标记设置为FALSE,然后组件程序继续运行直到卸载条件满足为止;另一种办法是,调用CoDisconnectObject 函数,强迫脱离对象与客户之间的关系,并强行终止进程,这种方法比较粗暴,不提倡采用,但不得已时可以也使用,以保证系统完成一些高优先级的操作。 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- COM 库常用函数 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- 初始化函数CoBuildVersion 获得COM 库的版本号 CoInitialize COM 库初始化 CoUninitialize COM 库功能服务终止 CoFreeUnusedLibraries 释放进程中所有不再使用的组件程序 GUID 相关函数IsEqualGUID 判断两个GUID 是否相等 IsEqualIID 判断两个IID 是否相等 IsEqualCLSID 判断两个CLSID 是否相等(*为什么要3个函数) CLSIDFromProgID 字符串组件标识转换为CLSID 形式 StringFromCLSID CLSID 形式标识转化为字符串形式 IIDFromString 字符串转换为IID 形式 StringFromIID IID 形式转换为字符串 StringFromGUID2 GUID 形式转换为字符串(*为什么有2) 对象创建函数CoGetClassObject 获取类厂对象 CoCreateInstance 创建COM 对象 CoCreateInstanceEx 创建COM 对象,可指定多个接口或远程对象 CoRegisterClassObject 登记一个对象,使其它应用程序可以连接到它 CoRevokeClassObject 取消对象的登记 CoDisconnectObject 断开其它应用与对象的连接 内存管理函数CoTaskMemAlloc 内存分配函数 CoTaskMemRealloc 内存重新分配函数 CoTaskMemFree 内存释放函数 CoGetMalloc 获取COM 库内存管理器接口 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- HRESULT 类型 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- 大多数COM 函数以及一些接口成员函数的返回值类型均为HRESULT 类型。HRESULT 类型的返回值反映了函数中的一些情况,其类型定义规范如下: 31 30 29 28 16 15 0 |-----|--|------------------------|-----------------------------------| 类别码(30-31) 反映函数调用结果: 00 调用成功 01 包含一些信息 10 警告 11 错误 自定义标记(29) 反映结果是否为自定义标识,1 为是,0 则不是; 操作码(16-28) 标识结果操作来源,在Windows 平台上,其定义如下: #define FACILITY_WINDOWS 8 #define FACILITY_STORAGE 3 #define FACILITY_RPC 1 #define FACILITY_SSPI 9 #define FACILITY_WIN32 7 #define FACILITY_CONTROL 10 #define FACILITY_NULL 0 #define FACILITY_INTERNET 12 #define FACILITY_ITF 4 #define FACILITY_DISPATCH 2 #define FACILITY_CERT 11 操作结果码(0-15) 反映操作的状态,WinError.h 定义了Win32 函数所有可能返回结果。 以下是一些经常用到的返回值和宏定义: S_OK 函数执行成功,其值为0 (注意,其值与TRUE 相反) S_FALSE 函数执行成功,其值为1 S_FAIL 函数执行失败,失败原因不确定 E_OUTOFMEMORY 函数执行失败,失败原因为内存分配不成功 E_NOTIMPL 函数执行失败,成员函数没有被实现 E_NOTINTERFACE 函数执行失败,组件没有实现指定的接口 不能简单地把返回值与S_OK 和S_FALSE 比较,而要用SECCEEDED 和FAILED 宏进行判断。 ================================================== ==================== =============================== ========= ⊙ 第四章COM 特性 ================================================== ==================== =============================== ========= 可重用性:包容和聚合 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- 包容模型: 组件对象在接口的实现代码中执行自身创建的另一个组件对象的接口函数(客户/服务器模型)。这个对象同时实现了两个(或更多)接口的代码。 聚合模型: 组件对象在接口的查询代码中把接口传递给自已创建的另一个对象的接口查询函数,而不实现该接口的代码。另一个对象必须实现聚合模型(也就是说,它知道自己正在被另一个组件对象聚合),以便QueryInterface 函数能够正常运作。 在组件对象被聚合的情况下,当客户请求它所不支持的接口或者请求IUnknown 接口时,它必须把控制交给外部对象,由外部对象决定客户程序的请求结果。 聚合模型体现了组件软件真正意义上的重用。 聚合模型实现的关键在CoCreateInstance 函数和IClassFactory 接口: HRESULT CoCreateInstance(const CLSID& clsid, IUnknown *pUnknownOuter, DWORD dwClsContext, const IID& iid, (void **)ppv); // class IClassFactory : public IUnknown virtual HRESULT _stdcall CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv) = 0; 其中pUnknownOuter 参数用于指定组件对象是否被聚合。如果pUnknownOuter 参数为NULL,说明组件对象正常使用,否则说明被聚合使用,pUnknownOuter 是外部组件对象的接口指针。 聚合模型下的被聚合对象的引用计数成员函数也要进行特别处理。在未被聚合的情况下,可以使用一般的引用计数方法。在被聚合时,由客户调用AddRef/Release 函数时,必须转向外部组件对象的AddRef/Release 方法。这时,外部组件对象要控制被聚合的对象必须采用其它的引用计数接口。 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- 进程透明性(待学) 安全性(待学) 多线程特性(待学) ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- ================================================== ==================== =============================== ========= ⊙ 第五章用Visual C++ 开发COM 应用 ================================================== ==================== =============================== ========= Win32 SDK 提供的一些头文件的说明 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- Unknwn.h 标准接口IUnknown 和IClassFacatory 的IID 及接口成员函数的定义 Wtypes.h 包含COM 使用的数据结构的说明 Objidl.h 所有标准接口的定义,即可用于C 语言风格的定义,也可用于C++ 语言 Comdef.h 所有标准接口以及COM 和OLE 内部对象的CLSID ObjBase.h 所有的COM API 函数的说明 Ole2.h 所有经过封装的OLE 辅助函数 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- 与COM 接口有关的一些宏 ------------------------------------------------- ------------------------------------------------- ------------------------------------------------- ----------------------------- DECLARE_INTERFACE(iface) 声明接口iface,它不从其他的接口派生 DECLARE_INTERFACE_(iface, baseiface) 声明接口iface,它从接口baseiface 派生 STDMETHOD(method) 声明接口成员函数method,函数返回类型为HRESULT STDMETHOD_(type, method) 声明接口成员函数method,函数返回类型为type ================================================== ==================== =============================== ========= ⊙ 结束 ================================================== ==================== =============================== ========= |