IMarshal 介面 (objidlbase.h)
可讓 COM 物件定義和管理其介面指標的封送處理。
繼承
IMarshal 介面繼承自 IUnknown 介面。 IMarshal 也有下列類型的成員:
方法
IMarshal 介面具有這些方法。
IMarshal::D isconnectObject IMarshal::D isconnectObject (objidlbase.h) 方法會釋放其伺服器呼叫此方法實作的物件的所有連線。 |
IMarshal::MarshalInterface IMarshal::MarshalInterface (objidlbase.h) 方法會封送處理介面指標。 |
IMarshal::ReleaseMarshalData IMarshal::ReleaseMarshalData (objidlbase.h) 方法會終結封送處理的數據封包。 |
IMarshal::UnmarshalInterface IMarshal::UnmarshalInterface (objidlbase.h) 方法 unmarshals 介面指標。 |
備註
封送處理 是將數據封裝成封包的程式,以傳輸至不同的進程或計算機。 Unmarshaling 是在接收端復原該數據的程式。 在任何指定的呼叫中,方法自變數會以一個方向封送處理和取消封送處理,而傳回值則會封送處理,並在另一個方向取消封送處理。
雖然封送處理適用於所有數據類型,但介面指標需要特殊處理。 基本問題是用戶端程式代碼在一個位址空間中執行的方式,可以正確地取值位於不同位址空間之物件上介面的指標。 COM 解決方案是讓用戶端應用程式透過代理物件或 Proxy 與原始物件通訊,而該對象位於用戶端的程式中。 Proxy 會保存原始物件上介面的參考,並將指標交給用戶端本身的介面。 當用戶端在原始物件上呼叫介面方法時,其呼叫實際上會移至 Proxy。 因此,從客戶端的觀點來看,所有呼叫都會進行中。
在接收呼叫時,Proxy 會封送處理方法自變數,並透過一些進程間通訊的方式傳遞,例如 RPC,將它們沿著伺服器進程中的程式碼傳遞,以取消封送自變數,並將其傳遞至原始物件。 這個相同的程式代碼封送處理會傳回傳回至 Proxy 的值,這會取消封送值,並將其傳遞至用戶端應用程式。
IMarshal 提供在用戶端程式中建立、初始化和管理 Proxy 的方法;它不會指出 Proxy 應該如何與原始物件通訊。 IMarshal 的 COM 預設實作會使用 RPC。 當您自行實作此介面時,您可以自由選擇您認為適合您應用程式的任何進程間通訊方法,也就是共用記憶體、命名管道、視窗句柄、RPC,簡短來說,任何都可以運作。
IMarshal 預設實作
COM 會使用自己的 IMarshal 介面內部實作,封送處理未提供其本身實作的任何物件。 COM 藉由查詢 IMarshal 的對象來判斷此判斷。 如果缺少介面,COM 預設為其內部實作。IMarshal 的 COM 預設實作會針對每個物件使用泛型 Proxy,並視需要在對象上實作的每個介面建立個別存根和 Proxy。 這是必要的機制,因為 COM 無法事先知道特定物件可以實作哪些特定介面。 未使用 COM 預設封送處理、改為撰寫自己的 Proxy 和封送處理例程的開發人員,在編譯時期知道要在物件上找到的所有介面,因此確切瞭解需要哪些封送處理程式代碼。 在提供所有物件的封送處理支援中,COM 必須在運行時間執行。
介面 Proxy 位於客戶端進程中;介面存根位於伺服器中。 每個配對都會處理介面的所有封送處理。 每個介面 Proxy 的作業是封送處理自變數和 unmarshal 傳回值和輸出參數,這些參數會在後續呼叫介面時來回傳遞。 每個介面存根的作業都是取消marshal 函式自變數,並將它們傳遞至原始物件,然後封送處理傳回值和傳回物件傳回的參數。
Proxy 和存根會透過 RPC (遠端過程調用) 通道進行通訊,其會利用系統的 RPC 基礎結構來進行進程間通訊。 RPC 通道會實作單一介面 IRpcChannelBuffer,而介面 Proxy 和存根都會保存指標。 Proxy 和存根會呼叫 介面以取得封送處理封包、將數據傳送至其對應專案,並在完成封包時終結封包。 介面存根也會保存原始物件的指標。
對於任何指定的介面,Proxy 和 Stub 都會實作為相同類別的實例,這兩者都會列在 ProxyStubClsid32 卷標下的系統登錄中的每個介面。 此專案會將介面的 IID 對應至其 Proxy 和存根物件的 CLSID 。 當 COM 需要封送處理介面時,它會在系統登錄中尋找以取得適當的 CLSID。 此 CLSID 所識別的伺服器會實作介面 Proxy 和介面存根。
通常,這個 CLSID 所參考的類別是由工具自動產生,其輸入是指定介面之函式簽章和語意的描述,以某些介面描述語言撰寫。 雖然強烈建議使用這類語言,但為了正確性而鼓勵這麼做,則不需要這麼做。 Proxy 和存根只是 RPC 基礎結構所使用的 COM 元件,因此只要支持正確的外部合約,就可以以任何所需的方式寫入。 設計新介面的程式設計人員負責確保所有介面 Proxy 和存根都同意其封送處理數據的表示法。
建立時,介面 Proxy 一律會匯總成較大的 Proxy,以整體表示物件。 此物件 Proxy 也會匯總 COM 泛型 Proxy 物件,稱為 Proxy 管理員。 Proxy 管理員會實作兩個介面: IUnknown 和 IMarshal。 在物件上可能實作的其他所有介面,都會透過個別介面 Proxy 的匯總,在其物件 Proxy 中公開。 擁有物件 Proxy 指標的用戶端會「認為」它持有實際物件的指標。
在用戶端程式中需要代表整個物件的 Proxy,讓用戶端可以辨別對完全不同對象上實作之相同介面的呼叫。 不過,這類需求不存在於伺服器進程中,物件本身所在的位置,因為所有介面存根只會與其建立的物件通訊。 無法進行其他連線。
介面存根與介面 Proxy 相較之下,不會匯總,因為某些外部用戶端不需要將它們顯示為較大整體的一部分。 連線時,介面存根會提供伺服器物件的指標,而伺服器對象應該將其接收的方法調用轉送至該物件。 雖然在概念上參考存根管理員相當實用,這表示伺服器端 RPC 基礎結構中任何程式碼和狀態片段都為指定物件的遠端服務,但不需要直接要求程式代碼和狀態採用任何特定且指定的格式。
第一次用戶端要求特定物件上介面的指標時,COM 會在伺服器進程中載入 IClassFactory 存根,並使用它將第一個指標封送處理回用戶端。 在用戶端程式中,COM 會載入類別處理站物件的泛型 Proxy,並呼叫其 IMarshal 實作來取消復原該第一個指標。 COM 接著會建立第一個介面 Proxy,並將指標交給 RPC 通道。 最後,COM 會傳回用戶端的 IClassFactory 指標,此指標會使用它來呼叫 IClassFactory::CreateInstance,並將它傳遞至介面的參考。
回到伺服器進程,COM 現在會建立 物件的新實例,以及所要求介面的存根。 這個存根會將介面指標封送處理回客戶端進程,此時會針對物件本身建立另一個物件 Proxy。 此外,建立的是所要求介面的 Proxy,這是傳回給用戶端的指標。 隨著物件上其他介面的後續呼叫,COM 會視需要載入適當的介面存根和 Proxy。
建立新的介面 Proxy 時,COM 會將其指標交給 Proxy 管理員的 IUnknown 實作,它會委派所有 QueryInterface 呼叫。 每個介面 Proxy 都會實作自己的兩個介面:它所代表的介面和 IRpcProxyBuffer。 介面 Proxy 會直接向客戶端公開自己的介面,而用戶端可以藉由在 Proxy 管理員上呼叫 QueryInterface 來取得其指標。 不過,只有 COM 可以呼叫 IRpcProxyBuffer,用來連接 Proxy 並中斷與 RPC 通道的連線。 客戶端無法查詢介面 Proxy,以取得 IRpcProxyBuffer 介面的指標。
在伺服器端,每個介面存根都會實作 IRpcStubBuffer。 做為存根管理員的伺服器程式代碼會呼叫 IRpcStubBuffer::Connect ,並傳遞其 物件的 IUnknown 指標介面存根。
當介面 Proxy 收到方法調用時,它會透過呼叫 IRpcChannelBuffer::GetBuffer,從其 RPC 通道取得封送處理封包。 封送處理自變數的程式會將數據複製到緩衝區。 封送處理完成時,介面 Proxy 會叫用 IRpcChannelBuffer::SendReceive 將封送處理封包傳送至對應的介面存根。 當 IRpcChannelBuffer::SendReceive 傳回時,自變數封送處理的緩衝區將會由包含從介面存根封送處理之傳回值的新緩衝區取代。 介面 Proxy 會取消封存傳回值、叫用 IRpcChannelBuffer::FreeBuffer 以釋放緩衝區,然後將傳回值傳回給方法的原始呼叫端。
它是 IRpcChannelBuffer::SendReceive 的實作,實際將要求傳送至伺服器進程,並知道如何識別伺服器進程,以及在該進程中,應該傳送要求的物件。 通道實作也知道如何將要求轉送至該程式中適當的存根管理員。 介面存根會從提供的緩衝區取消封存自變數、叫用伺服器物件上的指示方法,並將傳回值封送處理回 IRpcChannelBuffer::GetBuffer 所配置的新緩衝區。 接著,通道會將傳回的數據封包傳送回介面 Proxy,該 Proxy 仍在 IRpcChannelBuffer::SendReceive 中間,其會傳回至介面 Proxy。
只要符合下列條件,即可使用介面 Proxy 的特定實例來服務多個介面:
- 受影響的介面 IID 必須對應至系統登錄中適當的 ProxyStubClsid 。
- 介面 Proxy 必須支援從一個支援的介面呼叫 QueryInterface 到另一個介面,如往常一樣,以及從 IUnknown 和 IRpcProxyBuffer 呼叫。
在各種時間,Proxy 和存根必須配置或釋放記憶體。 例如,介面 Proxy 必須配置記憶體,以便將參數傳回給其呼叫端。 在此方面,介面 Proxy 和介面存根只是一般 COM 元件,因為它們應該使用標準工作配置器。 (請參閱 CoGetMalloc.)
規格需求
需求 | 值 |
---|---|
最低支援的用戶端 | Windows 2000 專業版 [傳統型應用程式 |UWP 應用程式] |
最低支援的伺服器 | Windows 2000 Server [傳統型應用程式 |UWP 應用程式] |
目標平台 | Windows |
標頭 | objidlbase.h (包含 ObjIdl.h) |