IMarshal 介面 (objidl.h)
可讓 COM 物件定義及管理其介面指標的封送處理。
繼承
IMarshal 介面繼承自 IUnknown 介面。 IMarshal 也有下列類型的成員:
方法
IMarshal 介面具有這些方法。
IMarshal::D isconnectObject IMarshal::D isconnectObject 方法 (objidl.h) 會在關閉之前釋放物件的所有連線。 |
IMarshal::GetMarshalSizeMax 擷取封送處理期間所需的緩衝區大小上限。 |
IMarshal::GetUnmarshalClass 擷取 unmarshaling 程式代碼的 CLSID。 |
IMarshal::MarshalInterface IMarshal::MarshalInterface 方法 (objidl.h) 封送處理介面指標。 |
IMarshal::ReleaseMarshalData IMarshal::ReleaseMarshalData 方法 (objidl.h) 終結封送處理的數據封包。 |
IMarshal::UnmarshalInterface IMarshal::UnmarshalInterface 方法 (objidl.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 傳回值,以及後續呼叫介面時傳回的參數。 每個介面存根的作業是取消封送函式自變數,並將它們傳遞至原始物件,然後封送處理傳回值和輸出物件傳回的參數。
Proxy 和存根會透過 RPC (遠端過程調用) 通道進行通訊,利用系統的 RPC 基礎結構進行進程間通訊。 RPC 通道會實作單一介面 IRpcChannelBuffer,而介面 Proxy 和存根都會保存指標。 Proxy 和存根會呼叫 介面以取得封送處理封包、將數據傳送至其對應專案,並在完成時終結封包。 介面存根也會保存原始物件的指標。
針對任何給定的介面,Proxy 和存根都會實作為相同類別的實例,這會列在系統登錄的 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 會載入 Class Factory 物件的泛型 Proxy,並呼叫其 IMarshal 實作,以取消第一個指標的 unmarshal。 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 |
標頭 | objidl.h (包含 ObjIdl.h) |