| ฟีด: บันทึกการผูกขาด ชื่อเรื่อง: บันทึกการศึกษาเกี่ยวกับ "หลักการและแอปพลิเคชัน" COM " | ผู้แต่ง: fgs_fgs ความเห็น |
| "หลักการ com และการใช้งาน" หมายเหตุการศึกษา - ส่วนที่ 1 หลักการ com หลักการ http://savetime.delphibs.com เวลาเริ่มต้น: 2004.1.30 แก้ไขล่าสุด: 2004.2.1 รูปแบบของบทความนี้คือ: ข้อความถูกห่อหุ้มด้วยหน้าต่างโดยอัตโนมัติ (เนื้อหาของบทความนี้เป็นข้อความที่ตัดตอนมาจากหนังสือ "COM Principles and Applications" ลิขสิทธิ์เป็นเจ้าของโดย Pan Aimin ผู้เขียนโปรดอย่าใช้ในสื่อสาธารณะ) สารบัญ ====================================================== ==================== ================================== ========= ⊙บทที่ 1 ภาพรวม com คืออะไร COM วัตถุและอินเทอร์เฟซ โมเดลกระบวนการ com com reusinability ⊙บทที่ 2 โมเดลวัตถุ com GUID ตัวระบุที่ไม่ซ้ำกันทั่วโลก com วัตถุ com อินเตอร์เฟส อินเตอร์เฟสคำอธิบายภาษา IDL อินเทอร์เฟซ iunknown หลักการอินเทอร์เฟซสำหรับวัตถุ COM ⊙บทที่ 3 การใช้งาน Com ข้อมูลการลงทะเบียนคอมโพเนนต์ com ลงทะเบียนส่วนประกอบ COM ฟังก์ชั่น Class Factory และ DllGetObjectClass ฟังก์ชัน CogetClassObject ฟังก์ชั่น cocreateinstance / cocreateinstanceex การเริ่มต้นของ COM Library การจัดการหน่วยความจำของ COM Library การโหลดและถอนการติดตั้งโปรแกรมส่วนประกอบ ฟังก์ชั่นทั่วไปสำหรับห้องสมุด com ประเภท HRESULT ⊙บทที่ 4 คุณสมบัติ com ความสามารถในการนำกลับมาใช้ใหม่: การรวมและการรวม กระบวนการโปร่งใส (เพื่อเรียนรู้) ความปลอดภัย (เพื่อเรียนรู้) คุณสมบัติมัลติเธรด (เพื่อเรียนรู้) ⊙บทที่ 5 การพัฒนาแอปพลิเคชัน COM ด้วย Visual C ++ คำอธิบายของไฟล์ส่วนหัวที่จัดทำโดย Win32 SDK แมโครบางส่วนที่เกี่ยวข้องกับอินเตอร์เฟส com ====================================================== ==================== ================================== ========= ข้อความ ====================================================== ==================== ================================== ========= ⊙บทที่ 1 ภาพรวม ====================================================== ==================== ================================== ========= com คืออะไร ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ COM เป็นมาตรฐานส่วนประกอบที่เสนอโดย Microsoft ในมาตรฐาน COM โปรแกรมส่วนประกอบนี้เรียกว่าโมดูล โปรแกรมส่วนประกอบสามารถมีวัตถุส่วนประกอบอย่างน้อยหนึ่งรายการ ) เป็นผู้ให้บริการรหัสที่มีวัตถุ COM วัตถุ COM แตกต่างจากแนวคิดของวัตถุในภาษาที่มุ่งเน้นวัตถุทั่วไป (เช่น C ++) วัตถุ COM เป็นภาษาที่ไม่ขึ้นกับภาษา คุณลักษณะนี้เป็นไปได้ที่จะโต้ตอบกับวัตถุส่วนประกอบที่พัฒนาโดยภาษาการเขียนโปรแกรมที่แตกต่างกัน ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ COM วัตถุและอินเทอร์เฟซ ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ คล้ายกับแนวคิดของวัตถุใน C ++ วัตถุเป็นอินสแตนซ์ของคลาส แอปพลิเคชันที่ใช้วัตถุ (หรือวัตถุอื่น) เรียกว่าลูกค้าบางครั้งก็เรียกว่าผู้ใช้ของวัตถุ อินเทอร์เฟซเป็นชุดของฟังก์ชั่นที่เกี่ยวข้องกับตรรกะและฟังก์ชั่นของมันเรียกว่าฟังก์ชั่นสมาชิกอินเตอร์เฟส ตามที่กำหนดเองชื่ออินเตอร์เฟสมักจะนำหน้าด้วย "ฉัน" วัตถุให้บริการแก่ลูกค้าในรูปแบบต่างๆผ่านฟังก์ชั่นสมาชิกอินเตอร์เฟส ในโมเดล COM วัตถุนั้นจะมองไม่เห็นลูกค้าและเมื่อลูกค้าร้องขอบริการมันสามารถดำเนินการผ่านอินเทอร์เฟซเท่านั้น แต่ละอินเตอร์เฟสจะถูกระบุโดยตัวระบุที่ไม่ซ้ำกันทั่วโลก 128 บิต (GUID) ไคลเอนต์ได้รับตัวชี้อินเตอร์เฟสผ่าน GUID จากนั้นผ่านตัวชี้อินเตอร์เฟสและไคลเอนต์สามารถเรียกฟังก์ชันสมาชิกที่เกี่ยวข้อง เช่นเดียวกับอินเทอร์เฟซแต่ละองค์ประกอบจะถูกระบุด้วย GUID 128 บิตที่เรียกว่า CLSID (ตัวระบุคลาส, ตัวระบุคลาสหรือ ID คลาส) ในความเป็นจริงหลังจากที่ไคลเอนต์สร้างวัตถุได้สำเร็จมันจะได้รับตัวชี้ไปยังอินเทอร์เฟซของวัตถุ มันบริการทั้งหมด ตามข้อกำหนดของ COM หากวัตถุ COM ใช้หลายอินเตอร์เฟสอินเทอร์เฟซอื่น ๆ ของวัตถุสามารถรับได้จากอินเทอร์เฟซที่แน่นอน จากกระบวนการนี้เรายังสามารถเห็นได้ว่าไคลเอนต์เกี่ยวข้องกับวัตถุ COM ผ่านอินเตอร์เฟสเท่านั้นและวัตถุเป็นเพียงชุดของอินเทอร์เฟซสำหรับไคลเอนต์ ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ โมเดลกระบวนการ com ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ วัตถุองค์ประกอบบริการที่จัดทำโดย COM มีสองโมเดลกระบวนการเมื่อนำไปใช้: วัตถุในกระบวนการและวัตถุนอกกระบวนการ หากเป็นวัตถุในกระบวนการมันจะทำงานในพื้นที่กระบวนการไคลเอนต์ โปรแกรมบริการในกระบวนการ: โปรแกรมบริการถูกโหลดลงในพื้นที่กระบวนการของลูกค้า โปรแกรมบริการท้องถิ่น: โปรแกรมบริการทำงานบนเครื่องเดียวกันกับโปรแกรมไคลเอนต์ โปรแกรมบริการระยะไกล: โปรแกรมบริการทำงานบนเครื่องที่แตกต่างจากไคลเอนต์และอาจเป็นโมดูล DLL หรือไฟล์ EXE หากโปรแกรมบริการระยะไกลถูกนำไปใช้ในรูปแบบ DLL เครื่องรีโมตจะสร้างกระบวนการพร็อกซี แม้ว่าวัตถุ COM จะมีโมเดลกระบวนการที่แตกต่างกันความแตกต่างนี้มีความโปร่งใสสำหรับโปรแกรมไคลเอนต์ อย่างไรก็ตามเมื่อใช้วัตถุ COM คุณควรเลือกแบบจำลองกระบวนการอย่างระมัดระวัง ข้อได้เปรียบของโมเดลในกระบวนการคือพวกเขามีประสิทธิภาพ แต่ส่วนประกอบที่ไม่เสถียรจะทำให้กระบวนการไคลเอ็นต์ผิดพลาดดังนั้นส่วนประกอบอาจเป็นอันตรายต่อลูกค้า -โมเดลของกระบวนการจะมีปัญหาซึ่งอาจเป็นเพราะส่วนประกอบและลูกค้าในกระบวนการอยู่ในพื้นที่ที่อยู่เดียวกันมีความเป็นไปได้สูงที่จะเกิดความขัดแย้ง? ความเสถียรและกระบวนการส่วนประกอบจะไม่เป็นอันตรายต่อโปรแกรมไคลเอนต์ ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ com reusinability ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ เนื่องจากมาตรฐาน COM ขึ้นอยู่กับระดับรหัสไบนารีความสามารถในการนำกลับมาใช้ใหม่ของวัตถุ COM จึงแตกต่างจากกระบวนการใช้ซ้ำของวัตถุในภาษาที่มุ่งเน้นวัตถุทั่วไปเช่น C ++ สำหรับโปรแกรมไคลเอนต์ของวัตถุ COM จะใช้บริการที่จัดทำโดยวัตถุผ่านอินเทอร์เฟซเท่านั้นและไม่ทราบว่ากระบวนการใช้งานภายในวัตถุ มากกว่าการใช้งานเฉพาะ com ใช้กลไกสองอย่างเพื่อตระหนักถึงการนำวัตถุกลับมาใช้ใหม่ เราคิดว่ามีวัตถุ COM สองชิ้นและวัตถุ 1 หวังว่าจะนำฟังก์ชั่นของวัตถุกลับมาใช้ซ้ำ 2 เราเรียกวัตถุ 1 วัตถุภายนอกและวัตถุ 2 วัตถุภายใน (1) วิธีรวม วัตถุ 1 มีวัตถุ 2. เมื่อวัตถุ 1 ต้องการใช้ฟังก์ชันของวัตถุ 2 มันสามารถส่งมอบการใช้งานกับวัตถุ 2 แม้ว่าวัตถุ 1 และวัตถุ 2 รองรับอินเตอร์เฟสเดียวกันวัตถุ 1 คือการใช้งานอินเตอร์เฟส การใช้งานวัตถุ 2 เรียกว่า (2) วิธีการรวม วัตถุที่ 1 เพียงแค่ส่งอินเทอร์เฟซของวัตถุ 2 ไปยังไคลเอนต์ มีอยู่. ====================================================== ==================== ================================== ========= ⊙บทที่ 2 โมเดลวัตถุ com ====================================================== ==================== ================================== ========= GUID ตัวระบุที่ไม่ซ้ำกันทั่วโลก ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ข้อกำหนดของ COM ใช้ GUID ตัวระบุที่ไม่ซ้ำกันทั่วโลก 128 บิตเพื่อระบุวัตถุและอินเทอร์เฟซซึ่งเป็นตัวเลขสุ่มและไม่จำเป็นต้องมีเอเจนซี่พิเศษในการจัดสรรและจัดการ เนื่องจาก GUID เป็นจำนวนสุ่มความเป็นเอกลักษณ์จึงไม่รับประกันอย่างแน่นอน แต่ความเป็นไปได้ของตัวระบุที่เพิ่มขึ้นเป็นสองเท่าจึงมีขนาดเล็กมาก ในทางทฤษฎีหากเครื่องสร้าง GUID 100,000,000 ต่อวินาทีสามารถรับประกันได้ว่า 3240 ปี (ในแง่ของความน่าจะเป็น) จะไม่ถูกทำซ้ำ GUID สามารถอธิบายได้ใน C/C ++ โดยใช้โครงสร้างนี้: typedef struct _guid - DWORD DATA1; Word Data2; Word Data3; BYTE DATA4 [8]; } Guid; ตัวอย่าง: {64BF4372-1007-B0AA-444553540000} คุณสามารถกำหนด GUID ได้ดังนี้: ภายนอก "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 ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ com อินเตอร์เฟส ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ในทางเทคนิคการพูดอินเทอร์เฟซเป็นโครงสร้างข้อมูลที่มีชุดของฟังก์ชั่นซึ่งรหัสไคลเอนต์สามารถเรียกฟังก์ชั่นของวัตถุส่วนประกอบได้ อินเทอร์เฟซกำหนดชุดของฟังก์ชั่นสมาชิกซึ่งเป็นข้อมูลทั้งหมดที่เปิดเผยโดยวัตถุส่วนประกอบ โดยปกติแล้วเราจะเรียกตารางฟังก์ชันฟังก์ชั่นอินเตอร์เฟส (vtable) และตัวชี้ไปยัง vtable คือ pvtable สำหรับอินเทอร์เฟซตารางฟังก์ชั่นเสมือนจริงจะถูกกำหนดดังนั้นจำนวนฟังก์ชั่นสมาชิกของอินเตอร์เฟสจะไม่เปลี่ยนแปลงและลำดับของฟังก์ชั่นสมาชิกก็ไม่เปลี่ยนแปลงเช่นกัน ในคำจำกัดความของอินเทอร์เฟซข้อมูลทั้งหมดนี้จะต้องถูกกำหนดในระดับไบนารี อินเตอร์เฟสตัวชี้ ----> pvtable ----> ฟังก์ชั่นตัวชี้ 1-> | ----------- | ฟังก์ชั่น M_DATA1 ตัวชี้ 2 -> | ฟังก์ชันตัวชี้ m_data2 3-> | ------------ | พารามิเตอร์แรกของแต่ละฟังก์ชันสมาชิกอินเตอร์เฟสเป็นตัวชี้ไปยังอินสแตนซ์ของวัตถุ (= สิ่งนี้) . ข้อมูลเมื่อเรียกว่าอินเทอร์เฟซสามารถรู้ได้ว่าวัตถุ COM ใดทำงานอยู่ ในฟังก์ชั่นสมาชิกอินเตอร์เฟสตัวแปรสตริงจะต้องใช้พอยน์เตอร์อักขระ Unicode ดังนั้นหากมีการใช้อักขระ ANSI ภายในโปรแกรมส่วนประกอบควรแปลงการแสดงออกของอักขระสองตัว แน่นอนในกรณีของการสร้างโปรแกรมส่วนประกอบและโปรแกรมไคลเอนต์คุณสามารถใช้ประเภทพารามิเตอร์ที่คุณกำหนดตัวเองตราบใดที่พวกเขาเข้ากันได้กับประเภทพารามิเตอร์ที่ Com สามารถรับรู้ได้ Visual C ++ มีการแปลงสตริงสองครั้ง: เนมสเปซ _com_util { BSTR ConvertStringTobstr (const char *psrc) โยน (_com_error); BSTR ConvertBstrToString (BSTR PSRC) โยน (_com_error); - BSTR เป็นสตริงสองไบต์ซึ่งเป็นประเภทข้อมูลอัตโนมัติที่ใช้กันมากที่สุด ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ อินเตอร์เฟสคำอธิบายภาษา IDL ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ข้อมูลจำเพาะของ COM ใช้ข้อกำหนด DCE ของ OSF เพื่ออธิบายอินเตอร์เฟสการโทรระยะไกล IDL (ภาษาคำอธิบายอินเตอร์เฟส) และขยายเพื่อสร้างภาษาคำอธิบายของอินเตอร์เฟส COM อินเตอร์เฟสคำอธิบายภาษาให้วิธีการคำอธิบายสำหรับอินเทอร์เฟซที่ไม่ได้ขึ้นอยู่กับภาษาใด ๆ ดังนั้นจึงสามารถกลายเป็นภาษาทั่วไประหว่างโปรแกรมส่วนประกอบและโปรแกรมไคลเอนต์ คำอธิบายอินเตอร์เฟส IDL ที่ใช้โดยข้อกำหนดของ COM ไม่เพียง แต่สามารถใช้เพื่อกำหนดอินเตอร์เฟส COM แต่ยังกำหนดประเภทข้อมูลที่ใช้กันทั่วไปและโครงสร้างข้อมูลที่กำหนดเอง . คุณสมบัติแม้กระทั่งคำอธิบายของอาร์เรย์ที่มีความยาวตัวแปร IDL รองรับประเภทตัวชี้ซึ่งคล้ายกับ C/C ++ มาก ตัวอย่างเช่น: อินเตอร์เฟส idictionary - HRESULT เริ่มต้น () HRESULT LOADLIBRARY ([ใน] สตริง); hresult insertword ([ใน] สตริง, [ใน] สตริง); HRESULT DELETEWORD ([ใน] สตริง); hresult lookupword ([ใน] สตริง [out] สตริง *); HRESULT RESTORELIBRARY ([ใน] สตริง); HRESULT FREELIBRARY (); - Microsoft Visual C ++ จัดเตรียมเครื่องมือ MIDL ที่สามารถรวบรวม IDL อินเตอร์เฟสคำอธิบายไฟล์ลงใน C/C ++-อินเตอร์เฟสที่เข้ากันได้คำอธิบายไฟล์ส่วนหัว (.H) ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ อินเทอร์เฟซ iunknown ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ คำจำกัดความ IDL ของ iunknown: อินเทอร์เฟซ iunknown - HRESULT QUERYINTERFACE ([ใน] refiid IID, [out] โมฆะ ** ppv); Ulong Addref (เป็นโมฆะ); Ulong Release (เป็นโมฆะ); - คำจำกัดความ C ++ ของ iunkown: คลาส 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. การสะท้อนกลับของอินเตอร์เฟส การสอบถามอินเทอร์เฟซนั้นควรประสบความสำเร็จเสมอเช่น: PIDICTIONARY-> QUERYINTERFACE (IID_DICTIONARY, ... ) ควรส่งคืน S_OK 3. ความสมมาตรของอินเตอร์เฟส หากคุณสอบถามจากตัวชี้อินเทอร์เฟซหนึ่งไปยังตัวชี้อินเทอร์เฟซอื่นจากนั้นการกลับจากตัวชี้อินเตอร์เฟสที่สองไปยังตัวชี้อินเทอร์เฟซตัวแรกจะต้องประสบความสำเร็จเช่น: PIDICTIONARY-> 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/LOCALSERVER32 หมวดหมู่ที่ส่วนประกอบ (catid) hkey_class_root/clsid/guid/หมวดหมู่ com Interface Configuration Information 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/ส่วนประกอบปัจจุบัน com จัดเตรียมฟังก์ชั่น API สองฟังก์ชั่น clsidfromprogid และ progidfromclsid เพื่อแปลง progid และ clsid หากคอมโพเนนต์ COM รองรับชุดอินเทอร์เฟซเดียวกันพวกเขาสามารถจำแนกได้เป็นคลาสเดียวกันและส่วนประกอบสามารถแบ่งออกเป็นหลายคลาส ตัวอย่างเช่นหากวัตถุอัตโนมัติทั้งหมดรองรับอินเตอร์เฟส IDISPATCH พวกเขาสามารถจัดเป็น "วัตถุอัตโนมัติ" ข้อมูลหมวดหมู่อธิบายโดย GUID ที่เรียกว่า Catid วัตถุประสงค์หลักของหมวดหมู่ส่วนประกอบคือลูกค้าสามารถค้นพบวัตถุประเภทเฉพาะของวัตถุในเครื่องได้อย่างรวดเร็ว อินเทอร์เฟซตอนนี้ใช้หมวดหมู่ส่วนประกอบสามารถบันทึกกระบวนการค้นหา ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ลงทะเบียนส่วนประกอบ COM ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ regsrv32.exe ใช้ในการลงทะเบียนส่วนประกอบในกระบวนการซึ่งเรียกฟังก์ชัน DllRegistERServer และ DllunRegistERServer ของ DLL เพื่อให้การลงทะเบียนและยกเลิกโปรแกรมส่วนประกอบเสร็จสมบูรณ์ หากการดำเนินการสำเร็จให้ส่งคืนจริงมิฉะนั้นจะส่งคืนเท็จ สำหรับโปรแกรมส่วนประกอบนอกกระบวนการสถานการณ์จะแตกต่างกันเล็กน้อยเนื่องจากเป็นโปรแกรมที่เรียกใช้งานได้เองและไม่สามารถให้ฟังก์ชั่นการป้อนข้อมูลสำหรับโปรแกรมอื่น ๆ ที่จะใช้ ดังนั้นข้อกำหนดของ COM จึงกำหนดว่าส่วนประกอบนอกกระบวนการที่สนับสนุนการลงทะเบียนตนเองจะต้องรองรับพารามิเตอร์บรรทัดคำสั่งสองตัว /regserver และ /unregserver เพื่อดำเนินการลงทะเบียนและยกเลิกการดำเนินการให้เสร็จสิ้น พารามิเตอร์บรรทัดคำสั่งนั้นขึ้นอยู่กับกรณีและ "/" สามารถแทนที่ด้วย "-" หากการดำเนินการสำเร็จโปรแกรมจะส่งกลับ 0 มิฉะนั้นการส่งคืนแบบไม่หมายถึงความล้มเหลว ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ฟังก์ชั่น Class Factory และ DllGetObjectClass ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ โรงงานชั้นเรียนเป็นฐานการผลิตของวัตถุ COM โรงงานคลาสเองก็เป็นวัตถุ COM ซึ่งรองรับอินเตอร์เฟสพิเศษ iClassFactory: คลาส iclassfactory: สาธารณะ iunknown - เสมือนจริง HRESULT _STDCALL CREATEINSTANCE (IUNKNOWN *PunkNownouter, const iid & iid, void ** ppv) = 0; HRESULT เสมือน _STDCALL Lockserver (bool block) = 0; - ฟังก์ชั่น Member CreateInstance ใช้เพื่อสร้างวัตถุ COM ที่เกี่ยวข้อง พารามิเตอร์แรก Punknownouter ใช้สำหรับกรณีที่คลาสวัตถุถูกรวมเข้าด้วยกันและโดยทั่วไปจะถูกตั้งค่าเป็น null; ตัวชี้อินเทอร์เฟซ ฟังก์ชั่นสมาชิก Lockserver ใช้เพื่อควบคุมอายุการใช้งานของส่วนประกอบ วัตถุโรงงานคลาสถูกสร้างขึ้นโดยฟังก์ชั่น DLL-DLLGETCLASSObject: HRESULT DLLGETCLASSOBJECT (const ClSID & ClSID, const iid & iid, (void **) ppv); พารามิเตอร์แรกของฟังก์ชัน dllgetClassObject คือ clsid ของวัตถุที่จะสร้าง เนื่องจากส่วนประกอบอาจใช้คลาส Object หลายคลาส COM จึงจำเป็นต้องระบุ CLSID ในพารามิเตอร์ของฟังก์ชัน DllGetClassObject เพื่อสร้างโรงงานคลาสที่ถูกต้อง อีกสองพารามิเตอร์ IID และ PPV อ้างถึงอินเทอร์เฟซที่ระบุ IID และตัวชี้อินเทอร์เฟซอินเตอร์เฟสโรงงานจัดเก็บตามลำดับ หลังจากได้รับคำสั่งเพื่อสร้างวัตถุไลบรารี COM เรียกฟังก์ชัน dllgetClassObject ของส่วนประกอบในกระบวนการสร้างวัตถุโรงงานคลาสจากฟังก์ชั่นและส่งคืนตัวชี้อินเตอร์เฟสของวัตถุโรงงานคลาส เมื่อไลบรารี COM หรือลูกค้ามีตัวชี้อินเทอร์เฟซไปยังโรงงานคลาสพวกเขาสามารถสร้างวัตถุ COM ที่สอดคล้องกันผ่านฟังก์ชั่นสมาชิก createInstance ของ iClassFactory ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ฟังก์ชัน CogetClassObject ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ในห้องสมุด COM มี API สามตัวที่สามารถใช้สำหรับการสร้างวัตถุ ได้แก่ CogetClassObject, Cocreateinstnace และ Cocreateinstanceex โดยทั่วไปแล้วโปรแกรมไคลเอนต์จะเรียกหนึ่งในนั้นเพื่อให้การสร้างวัตถุเสร็จสมบูรณ์และส่งคืนตัวชี้อินเทอร์เฟซเริ่มต้นของวัตถุ COM Library และ Class Factory ยังมีปฏิสัมพันธ์ผ่านฟังก์ชั่นทั้งสามนี้ 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 (ด้วยพารามิเตอร์บรรทัดคำสั่ง "/EMBEDDING สร้างวัตถุ COM สำหรับใช้งาน เมื่อกระบวนการออกจะต้องมีการเรียกใช้ฟังก์ชัน CoreVokeclassObject เพื่อแจ้งให้ทราบว่าวัตถุโรงงานคลาสที่ลงทะเบียนนั้นไม่ถูกต้องอีกต่อไป โปรแกรมส่วนประกอบเรียกฟังก์ชัน 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 สอดคล้องกับพารามิเตอร์ที่สอดคล้องกันใน createInstance ของอินเทอร์เฟซโรงงานคลาสและส่วนใหญ่จะใช้ในกรณีที่วัตถุถูกรวมเข้าด้วยกัน ฟังก์ชั่น COCREATEINSTANCE ห่อหุ้มกระบวนการสร้างวัตถุผ่านโรงงานคลาสเท่านั้น Cocreateinstance สามารถนำไปใช้กับรหัสต่อไปนี้: (หมายเหตุ Savetime: แอปพลิเคชันของตัวชี้ 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; HR = PCF-> CreateInstance (PunkNownouter, IID, (void *) PPV); pfc-> release (); กลับ HR; - จากรหัสนี้เราจะเห็นได้ว่าฟังก์ชัน 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 Library ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ ก่อนที่จะเรียกฟังก์ชั่นของไลบรารี COM เพื่อให้ฟังก์ชั่นถูกต้องฟังก์ชั่นการเริ่มต้นของไลบรารี COM จะต้องเรียก: HRESULT COINITIALIZE (IMALLOC *PMALLOC); PMALLOC ใช้เพื่อระบุการจัดสรรหน่วยความจำและหลักการจัดสรรหน่วยความจำสามารถระบุได้โดยแอปพลิเคชัน โดยทั่วไปหากเราตั้งค่าพารามิเตอร์โดยตรงเป็น NULL ไลบรารี COM จะใช้หน่วยความจำเริ่มต้นที่ให้มา ค่าส่งคืน: S_OK หมายถึงการเริ่มต้นสำเร็จ S_FALSE บ่งชี้ว่าการเริ่มต้นนั้นสำเร็จ แต่การโทรนี้ไม่ใช่ครั้งแรกที่ฟังก์ชั่นการเริ่มต้นเรียกใช้ในกระบวนการนี้ S_UNEXPECTION ระบุว่าเกิดข้อผิดพลาดในระหว่างกระบวนการเริ่มต้นและแอปพลิเคชันไม่สามารถใช้ไลบรารี COM ได้ โดยปกติกระบวนการเริ่มต้นไลบรารี COM เพียงครั้งเดียวและไม่สมเหตุสมผลที่จะเริ่มต้นไลบรารี COM หลายครั้งในหน่วยโมดูลเดียวกัน ฟังก์ชั่นเดียวที่ไม่จำเป็นต้องเริ่มต้นไลบรารี COM คือการรับเวอร์ชัน COM Library: DWORD COBUILDVERSION (); ค่าส่งคืน: หมายเลขรุ่นหลัก 16 บิตสูง หมายเลขรุ่นที่ต่ำกว่า 16 หลัก หลังจากโปรแกรม COM ใช้บริการ COM Library โดยปกติก่อนที่โปรแกรมจะออกแล้วจำเป็นต้องเรียกฟังก์ชันบริการ Library COM ที่สิ้นสุดเพื่อปลดปล่อยทรัพยากรที่ดูแลโดย COM Library: โมฆะ couninitialize (เป็นโมฆะ); หมายเหตุ: โมดูลกระบวนการหรือโปรแกรมใด ๆ ที่เรียกฟังก์ชั่น coinitialize และส่งคืน S_OK จะต้องมีการเรียกฟังก์ชั่นฟังก์ชั่น couninitialize ที่สอดคล้องกันเพื่อให้แน่ใจว่าไลบรารี COM ใช้ทรัพยากรอย่างมีประสิทธิภาพ (? ถ้า Coinitialize เรียกว่าในโมดูลและส่งคืน S_OK โมดูลอื่น ๆ ที่ใช้ห้องสมุด COM มีข้อผิดพลาดหลังจากเรียกฟังก์ชัน Countialize หรือไม่? ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ การจัดการหน่วยความจำของ COM Library ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ เนื่องจากโปรแกรม Component COM และโปรแกรมไคลเอนต์เชื่อมต่อผ่านมาตรฐานระดับไบนารีการดำเนินการทั้งหมดที่เกี่ยวข้องกับการโต้ตอบหน่วยความจำระหว่างลูกค้าห้องสมุด COM และส่วนประกอบ (การจัดสรรและการเปิดตัวไม่ได้อยู่ในโมดูลเดียวกัน) ในแอปพลิเคชัน COM จะต้องใช้ตัวจัดการหน่วยความจำที่สอดคล้องกัน มาตรฐานการจัดการหน่วยความจำที่จัดทำโดย COM เป็นอินเทอร์เฟซ IMALLOC: // IID_IMALLOC: {00000002-0000-0000-CROPLE-000000000046} คลาส Imalloc: สาธารณะ iunknown - เป็นโมฆะ * alloc (ulong cb) = 0; เป็นโมฆะ * realloc (เป็นโมฆะ * pv, ulong cb) = 0; เป็นโมฆะฟรี (เป็นโมฆะ *pv) = 0; Ulong Getsize (เป็นโมฆะ *PV) = 0; // ส่งคืนขนาดหน่วยความจำที่จัดสรร int didalloc (void *pv) = 0; เป็นโมฆะ HeapMinimize () = 0; // ระบบปฏิบัติการสำหรับการเพิ่มประสิทธิภาพประสิทธิภาพ - รับตัวชี้อินเทอร์เฟซ IMALLOC: HRESULT COGETMALLOC (DWORD DWMEMCONTEXT, IMALLOC ** PPMALLOC); พารามิเตอร์แรกของฟังก์ชัน cogetMalloc dwmemcontext ใช้เพื่อระบุประเภทของตัวจัดการหน่วยความจำ Library COM มีผู้จัดการหน่วยความจำสองตัวคือตัวจัดการหน่วยความจำที่ระบุในระหว่างการเริ่มต้นหรือตัวจัดการเริ่มต้นภายในหรือที่รู้จักกันในชื่อตัวจัดการงาน (การจัดสรรงาน) memctx_task ในพารามิเตอร์ dwmemcontext; กระบวนการและส่งผ่านไปยังกระบวนการที่สองโดยใช้หน่วยความจำนี้ในกระบวนการที่สองหรือแม้แต่ปล่อย ตราบใดที่ค่าส่งคืนของฟังก์ชั่นคือ S_OK, PPMALLOC ชี้ไปที่ตัวชี้อินเทอร์เฟซ Memory Manager ของไลบรารี COM และคุณสามารถใช้มันเพื่อดำเนินการหน่วยความจำหลังการใช้งาน ไลบรารี COM ห่อหุ้มฟังก์ชั่น API สามฟังก์ชั่นที่สามารถใช้สำหรับการจัดสรรหน่วยความจำและการเปิดตัว: เป็นโมฆะ * CotaskMemalloc (Ulong CB); เป็นโมฆะ CotaskFree (Void *PV); เป็นโมฆะ CotaskMemrealLoc (Void *PV, Ulong CB); ฟังก์ชั่นทั้งสามนี้ถูกกำหนดให้กับฟังก์ชั่นสมาชิกสามรายการที่สอดคล้องกับ IMALLOC: alloc, realloc และฟรี ตัวอย่าง: วิธีการที่โปรแกรม COM ค้นหาค่า progid ที่เกี่ยวข้องจากค่า CLSID: wchar *pwprogid; ถ่าน pszprogid [128]; HRESULT = :: PROGIDFROMCLSID (CLSID_DICTIONARY, & PWPROGID); ถ้า (hresult! = s_ok) { - - WCSTOMBS (PSZPROGID, PWPROGID, 128); CotaskMemFree (PWProgid); หลังจากเรียกใช้ฟังก์ชัน com progidFromClsid เพื่อส่งคืนเนื่องจากไลบรารี COM จัดสรรพื้นที่หน่วยความจำสำหรับตัวแปรเอาต์พุต pwProgid แอปพลิเคชันจะต้องเรียกฟังก์ชัน cotaskmemfree เพื่อเพิ่มหน่วยความจำหลังจากใช้ตัวแปร PWProgid ตัวอย่างนี้แสดงให้เห็นถึงสถานการณ์ที่มีการจัดสรรหน่วยความจำในไลบรารี COM และหน่วยความจำเป็นอิสระในโปรแกรมการโทร ฟังก์ชั่นอื่น ๆ ในไลบรารี COM มีลักษณะคล้ายกันโดยเฉพาะอย่างยิ่งฟังก์ชั่นบางอย่างที่มีพารามิเตอร์เอาต์พุตความยาวไม่ จำกัด ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ 组件程序的装载和卸载 ------------------------------------------------------ ------------------------------------------------------ ------------------------------------------------------ ------------------------ 进程内组件的装载: 客户程序调用COM 库的CoCreateInstance 或CoGetClassObject 函数创建COM 对象,在CoGetClassObject 函数中,COM 库根据系统注册表中的信息,找到类标识符CLSID 对应的组件程序(DLL 文件)的全路径,然后调用LoadLibrary(实际上是CoLoadLibrary)函数,并调用组件程序的DllGetClassObject 引出函数。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 ====================================================== ==================== ================================== ========= ⊙ 结束 ====================================================== ==================== ================================== ========= |