com組件接口


int  main(  int  argc,  char  *argv[] )
{
    cout <<  "Initializing COM"  << endl;
 
    if  ( FAILED( CoInitialize( NULL )))
    {
       cout <<  "Unable to initialize COM"  << endl;
       return  -1;
    }
 
    ISampleMath* pSampleMath;
    HRESULT  hr;
    // This time use CoCreateInstance
    hr = CoCreateInstance( CLSID_SampleMath,
                           NULL,
                           CLSCTX_LOCAL_SERVER,
                           IID_ISampleMath,
                           ( void **) &pSampleMath );
 
    if  ( FAILED( hr ))
    {
       cout <<  "Failed to create server instance. HR = "  << hr << endl;
       CoUninitialize();
       return  -1;
    }
 
    // Access the IMath interface
    long  lResult;
    pSampleMath->Add( 134, 353, &lResult );
    cout <<  "134 + 353 = "  << lResult << endl;
 
 
 
    // Release all of our interfaces
    if  ( pSampleMath )
 
    CoUninitialize();
 
    return  0;
}
 
 

COM組件可以是一個Dll(進程內組件),也可以是一個EXE(進程外組件)。進程內組件就是組件和客戶程序在同一進程內,進程外組件即組件和客戶程序分別有自己的進程空間。

    一個COM組件可以包含多個COM對象,一個COM對象又可以有多個接口。

 

第2章 COM對象和接口

2.1 CLSID和IID

    對於COM對象來說,接口是它與外界進行交互的唯一途徑。

    每個COM對象,可以用CLSID來標識,COM對象的每個接口可以用IID來標識。CLSID和IID都是128位的標識符GUID,是一個隨機數,可以由兩方面特性來保證:空間(如網絡適配器地址)和時間。

    GUID可以通過COM庫的API函數生成:

HRESULT CoCreateGuid( GUID * pguid );
2.1.2 COM對象和C++對象的不同
COM對象的數據成員封裝以組建模塊為最終邊界,對於對象用戶是完全透明的、不可見的,用戶必須通過接口方法來訪問數據成員;C++對象的封裝特性只是語義上的,用戶可以直接看到數據成員。
2.2 COM接口結構
COM組件開發知識重點——COM原理與應用篇(一)
接口是包含了一組函數的數據結構。客戶程序利用這些函數獲得組件對象的服務。接口成員函數中的字符串變量必須使用Unicode字符指針。
客戶程序用一個指向接口數據結構的指針來調用接口成員函數,接口指針又指向pVtable(指向vtable的指針),pVtable指向一組函數,稱為接口函數表(虛函數表vtable),表中每一項為4個字節長的函數指針,每個函數指針再指向函數的具體實現。
2.2.2 接口描述語言IDL
2.3 IUnknown接口
COM定義的每個接口都必須從IUnknown接口繼承過來,因為IUnknown接口提供了兩個重要特性:生存期控制和接口查詢。
COM組件開發知識重點——COM原理與應用篇(一)
QueryInterface用於查詢COM對象的其他接口指針,AddRef和Release用於對引用計數進行操作。
在COM對象級實現引用計數,精細度比較合適。

 

2.3.1 使用引用計數規則

(1)函數的參數中使用接口指針變量。

輸入參數:在被調用函數中,不必調用AddRef和Release函數。

輸出函數:在被調用函數返回之前,對輸出參數調用AddRef,增加引用計數。

輸入-輸出參數:在參數被修改之前,對原來傳進來的接口指針調用Release,引用計數減1,在參數被修改之后,對新的接口指針變量指針調用AddRef,若在函數執行過程中,參數沒有被修改,則不必調用AddRef和Release函數。

(2)局部接口指針變量。

在局部函數塊中,一個局部接口指針變量被賦了值並調用了接口成員函數,則對該局部接口指針變量 不必調用AddRef和Release函數。
(3)全局接口指針變量。
在把全局接口指針變量作為輸入參數傳給某個函數之前,調用AddRef,在函數返回之后調用Release。
(4)C++中類成員變量為接口指針變量:適用於(3)。
(5)在順序執行過程中,如果對一個接口指針變量賦值,則對賦值后的接口指針變量調用AddRef,如果賦值前的接口指針變量還沒有結束,則賦值前必須對它調用Release以便先結束它的使用。

COM的實現

3.1 進程內組件(DLL)的實現,可以參考DLL技術,主要參數為:

1)LoadLibrary:裝載DLL模塊

2)GetProcAddress:取引出函數的地址

3)FreeLibrary:釋放DLL模塊

    COM采用LPC(本地過程調用)和RPC(遠程過程調用)的方法進行進程之間的通信,LPC用於在同一機器上的不同進程之間進行通信,而RPC用於在不同機器上的進程之間進行通信。

COM組件開發知識重點——COM原理與應用篇(二)3.2 組件程序的兩個用於注冊的入口函數為DllRegisterServer和DllUnregisterServer,注冊組件使用命令:RegSvr32 *.dll;反注冊組件使用命令:RegSvr32 /u *.dll,進程內組件注冊使用此命令。進程外組件注冊必須支持兩個命令行參數/RegServer 和/UnregServer。
3.3 類廠

    COM庫通過類廠創建COM對象,對應每一個COM類,都有一個類廠專門用於該COM類的對象創建工作。類廠本身也是一個COM對象,它支持接口IClassFactory。

COM組件開發知識重點——COM原理與應用篇(二)CreateInstance創建對應的COM對象,LockServer控制組件的生存周期。

類廠由函數DllGetClassObject創建。

COM組件開發知識重點——COM原理與應用篇(二)DllGetClassObject返回類廠對象的接口指針,再通過CreateInstance創建對應的COM對象。
3.3.2 COM庫與類廠的交互

    創建對象函數:

1)若創建遠程對象或希望一次獲取對象的多個接口指針,選用CoCreateInstanceEx。

COM組件開發知識重點——COM原理與應用篇(二)

2)若希望獲取類廠對象或要調用類廠的某些成員函數,選用CoGetClassObject,通常IID=IID_IclassFactory,進程內組件直接調用DLL的CoGetClassObject,若CoGetClassObject創建的類廠對象位於進程外組件,函數啟動組件進程,然后等待,直到組件進程把它支持的COM類對象的類廠注冊到COM中,返回類廠信息。

COM組件開發知識重點——COM原理與應用篇(二)

3)其他情況下,選用CoCreateInstance創建對象,CoCreateInstance封裝類廠創建對象的過程,返回COM對象的接口指針,不能創建遠程機器上的對象。

COM組件開發知識重點——COM原理與應用篇(二)COM組件開發知識重點——COM原理與應用篇(二)
3.4 COM庫

    COM庫初始化函數:CoInitialize

    COM庫終止函數:CoUninitialize

3.4.2 COM庫的內存管理

    COM提供的內存管理器標准,是一個COM接口IMalloc。當組件內存的分配和釋放不在同一模塊,需要用到內存管理器,COM庫封裝了三個API函數,用於內存分配和釋放

CoTaskMemAlloc

CoTaskMemFree
CoTaskMemRealloc

3.4.3 組件程序的裝載和卸載

1)進程內組件的裝載、卸載

2)進程外組件的裝載、卸載

    組件程序滿足兩個條件才可以被卸載:組件中對象數為0;類廠的鎖計數器為0。此時,DllCanUnloadNow返回TRUE。

    在判斷返回類型HRESULT時,需用宏SUCCEEDED和FAILED。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM