註冊介面
本節詳細討論註冊 RPC 介面的過程。
本節中的資訊會顯示在下列主題中:
- 介面註冊函式
- Entry-Point 向量
- Manager EPVs
- 註冊介面 的單一實作
- 註冊多個介面實作
- 叫用管理員例程 規則
- 將遠端程序呼叫指派至 Server-Manager 例程
- 提供您自己的 Object-Inquiry 函數
介面註冊函式
伺服器會藉由調用 RpcServerRegisterIf 函數來註冊其介面。 複雜的伺服器程式通常支援一個以上的介面。 伺服器應用程式必須針對支援的每個介面呼叫此函式一次。
此外,伺服器也可以支援相同介面的多個版本,每個版本都有自己的介面函式實作。 如果您的伺服器程式這樣做,它必須提供一組進入點。 進入點是一個管理員例程,會分派對接口版本的呼叫。 每個介面版本都必須有一個進入點。 進入點群組稱為進入點向量。 如需詳細資訊,請參閱 Entry-Point 向量。
除了標準函式 RpcServerRegisterIf之外,RPC 也支援其他介面註冊函式。 RpcServerRegisterIf2 函式可讓您指定一組註冊旗標,藉此擴充 RpcServerRegisterIf 的功能(請參閱 介面註冊旗標)、伺服器可接受的並行遠端過程調用要求數目上限,以及傳入數據區塊的大小上限。
RPC 連結庫也包含名為 RpcServerRegisterIfEx的函式。 如同 rpcServerRegisterIf函式,此函式會註冊介面。 您的伺服器程式也可以使用此函式來指定一組註冊旗標(請參閱 介面註冊旗標)、伺服器可接受的並行遠程過程調用要求數目上限,以及安全性回呼函式。
RpcServerRegisterIf、RpcServerRegisterIfEx和 RpcServerRegisterIf2 函式會在內部介面登錄數據表中設定值。 下表用來將介面 UUID 和物件 UUID 對應至管理員 EPV。 管理程式 EPV 是函式指標的陣列,其中包括 IDL 檔案中指定介面的每個函式原型的一個函式指標。
如需了解提供多個 EPV 以實現多個介面的資訊,請參閱 多個介面實作。
運行時庫會使用介面註冊表(透過呼叫函式 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2)和物件註冊表(透過呼叫函式 RpcObjectSetType)將介面和物件 UUID 對應至函式指標。
當您想要讓伺服器程式從 RPC 執行時間連結庫登錄中移除介面時,請呼叫 RpcServerUnregisterIf 函式。 從登錄中移除介面之後,RPC 運行時間連結庫將不再接受該介面的新呼叫。
進入點向量
管理員進入點向量 (EPV) 是函式指標的陣列,指向IDL檔案中指定的函式實作。 陣列中的元素數目會對應至IDL檔案中指定的函式數目。 RPC 支援多個進入點向量,代表介面中所指定函式的多個實作。
MIDL 編譯程式會自動產生管理員 EPV 數據類型,以用於建構管理員 EPV。 數據類型會命名 if-name**_SERVER_EPV**,其中 if-name 指定 IDL 檔案中的介面識別符。
MIDL 編譯程式會自動建立並初始化預設管理員 EPV,假設介面中每個程式都有相同名稱的管理員例程,並在 IDL 檔案中指定。
當伺服器提供相同介面的多個實作時,伺服器必須為每個實作建立一個額外的管理員 EPV。 針對IDL檔案中定義的每個程式,每個EPV必須只包含一個進入點(函式的位址)。 伺服器應用程式會針對介面的每個額外實作,宣告並初始化類型為 if-name**_SERVER_EPV** 的一個管理員 EPV 變數。 若要註冊 EPV,請針對支援的每個物件類型分別呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2。
當客戶端對伺服器進行遠端過程調用時,會根據介面 UUID 和物件類型來選取包含函式指標的 EPV。 物件類型是由 object-inquiry 函式根據物件 UUID 衍生出的,或者由由RpcObjectSetType所控制的表格驅動對應所衍生的。
經理 EPVs
根據預設,MIDL 編譯程式會使用介面 IDL 檔案中的程式名稱來產生管理員 EPV,編譯程式會將它直接放入伺服器存根。 這個預設 EPV 會使用介面定義中宣告的程式名稱,以靜態方式初始化。
若要使用預設 EPV 註冊管理員,請在呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2 函式時,將 MgrEpv 參數的值指定為NULL。 如果管理員所使用的例程名稱對應至介面定義的例程名稱,您可以使用 MIDL 編譯程式所產生的介面預設 EPV 來註冊此管理員。 您也可以使用伺服器應用程式提供的 EPV 來註冊管理員。
伺服器可以(有時也必須)為介面建立並註冊非null 管理員 EPV。 若要選取由伺服器應用程式提供的 EPV,請傳遞已被伺服器宣告為參數 MgrEpv 值的 EPV 位址。 非null 的 MgrEpv 參數值始終會覆寫伺服器存根中的預設 EPV。
MIDL 編譯程式會自動產生管理員 EPV 資料類型 (RPC_MGR_EPV),讓伺服器應用程式用於建構管理員 EPV。 管理器 EPV 必須針對 IDL 檔案中定義的每個程序,恰好包含一個進入點(函數位址)。
在下列情況下,伺服器必須提供非null EPV:
- 當管理員例程的名稱與介面定義中所宣告的程式名稱不同時
- 當伺服器使用預設 EPV 來註冊該介面的另一個實作時
伺服器會針對介面的每個實作,初始化類型為 if-name**_SERVER_EPV** 的變數,以宣告管理員 EPV。
註冊單一介面實作
當伺服器只提供一個介面的實作時,伺服器只會 呼叫一次 rpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2 一次。 在標準案例中,伺服器會使用預設管理員 EPV。 (例外狀況是管理員使用與介面中所宣告名稱不同的例程名稱。
針對標準案例,您可以提供下列值 來呼叫 rpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2:
經理 EPV
若要使用預設 EPV,請為參數 MgrEpv 指定 null 值。
管理員類型 UUID
使用預設 EPV 時,提供 null 值或 nil UUID 作為 MgrTypeUuid 參數,以註冊介面與 nil 管理器類型 UUID。 在這種情況下,不論繫結句柄中的物件 UUID 為何,所有遠端程序呼叫都會被分派到預設 EPV,假設尚未進行 RpcObjectSetType 呼叫。
您也可以提供非空的管理員類型 UUID。 在此情況下,您也必須呼叫 RpcObjectSetType 例程。
註冊介面的多個實作
您可以提供 IDL 檔案中指定的多個遠端程式實作。 伺服器應用程式會呼叫 RpcObjectSetType,將物件 UUID 對應至類型 UUID,並呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2 將管理員 EPV 與類型 UUID 產生關聯。 當遠端過程調用以其物件 UUID 抵達時,RPC 伺服器執行時函式庫會將物件 UUID 映射至類型 UUID。 然後,伺服器應用程式會使用 UUID 類型和介面 UUID 來選取管理員 EPV。
您也可以指定自己的函式,將物件 UUID 的對應解析為管理員類型 UUID。 當您呼叫 rpcObjectSetInqFn 時,您可以指定對應函式。
若要提供介面的多個實作,伺服器必須分別呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx 或 RpcServerRegisterIf2 來註冊每個實作。 針對每一個實作,伺服器緩存器都會提供相同的 IfSpec 參數,但不同組的 MgrTypeUuid 和 MgrEpv 參數。
在多個管理員的情況下,請使用 RpcServerRegisterIf、RpcServerRegisterIfEx 或 RpcServerRegisterIf2,如下所示:
經理 EPV
若要提供介面的多個實作,伺服器必須:
- 為每個額外的實作建立非null 管理物件 EPV。
- 在 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2中,為 MgrEpv 參數指定非NULL 值。
請注意,伺服器也可以向預設管理員 EPV 註冊。
管理員類型 UUID
為介面的每個EPV提供管理員類型 UUID。 MgrTypeUuid 的 nil 類型 UUID (或 null 值), 參數可以指定給其中一個管理員 EPV。 每個類型 UUID 都必須不同。
叫用管理員例程的規則
RPC 執行時庫會將傳入的遠端程序呼叫分派給提供該 RPC 介面的管理員。 當為介面註冊多個管理員時,RPC 執行時期函式庫必須選取其中一個。 若要選取管理員,RPC 運行時間連結庫會使用呼叫之系結句柄所指定的物件 UUID。
當解譯遠端過程調用的物件 UUID 時,運行時間連結庫會套用下列規則:
Nil 物件 UUID
nil 物件 UUID 會自動指派 nil 類型 UUID(在 RpcObjectSetType 例程中指定 nil 物件 UUID 是非法的)。 因此,若系結句柄包含 nil 物件 UUID,則該遠端程序呼叫會自動轉送至已向 nil 類型 UUID 註冊的管理員(如果有的話)。
非空物件的 UUIDs
原則上,繫結控制代碼包含非空物件 UUID 的遠端程序呼叫,應該由類型 UUID 與物件 UUID 類型相符的管理者處理。 不過,識別正確的管理員需要伺服器藉由呼叫 rpcObjectSetType 例程來指定該物件 UUID 的類型。
如果伺服器無法為非 nil 物件 UUID 呼叫 RpcObjectSetType 例程,該物件的遠端程序呼叫將轉至用於 nil 物件 UUID 的管理員 EPV(即,nil 類型 UUID)。
如果伺服器透過呼叫 RpcObjectSetType 例程,將一個非 nil 的物件 UUID 指派了類型 UUID,但沒有透過呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx 或 RpcServerRegisterIf2註冊該類型的管理員 EPV,則具有該非 nil 物件 UUID 的綁定句柄中的遠端過程呼叫將無法執行。
下表摘要說明執行期程式庫用來選擇管理程序的動作。
呼叫的物件 UUID | 伺服器將類型設為物件 UUID? | 伺服器是否已註冊 EPV 類型? | 分派動作 |
---|---|---|---|
零 | 不適用 | 是的 | 使用具有空類型 UUID 的管理者。 |
零 | 不適用 | 不 | 錯誤 (RPC_S_UNSUPPORTED_TYPE):拒絕遠端程序呼叫。 |
非 nil | 是的 | 是的 | 使用具有相同類型 UUID 的管理員。 |
非空值 | 不 | 忽視 | 使用具有 nil 類型 UUID 的管理員。 如果沒有 UUID 類型為 nil 的管理員,則會產生錯誤(RPC_S_UNSUPPORTEDTYPE);拒絕遠端程序呼叫。 |
非空值 | 是的 | 不 | 錯誤(RPC_S_UNSUPPORTEDTYPE):拒絕了遠程過程調用。 |
呼叫的物件 UUID 是在遠端程序呼叫的系結句柄中找到的物件 UUID。
伺服器會呼叫 rpcObjectSetType 來設定物件 UUID 的類型,以指定物件的 UUID 類型。
伺服器透過呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx 或 RpcServerRegisterIf2 來以相同的類型 UUID 註冊管理員 EPV 的類型。
將遠端程序呼叫分派至伺服器管理程序例程
下表顯示 RPC 執行階段函式庫將遠端過程調用分派到伺服器管理員常式的步驟。
下表說明伺服器註冊預設管理員 EPV 的簡單案例。
介面登錄數據表
介面 UUID | 管理員類型 UUID | 進入點向量 |
---|---|---|
uuid1 | 零 | 預設 EPV |
物件登錄數據表
物件 UUID | 物件類型 |
---|---|
零 | 零 |
(任何其他物件 UUID) | 零 |
將系結句柄對應至進入點向量 (EPV)
介面 UUID (來自用戶端系結句柄) | 物件 UUID (來自用戶端系結句柄) | 物件類型(來自物件登入表) | 管理員 EPV (來自介面登入表 ) |
---|---|---|---|
uuid1 | 零 | 零 | 預設 EPV |
與上述相同 | uuidA | 零 | 預設 EPV |
下列步驟描述當具有介面 UUID uuid1 的用戶端呼叫 RPC 伺服器時,伺服器的運行時程式庫採取的動作,如上述表格所示。
伺服器會呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2,將它所提供的介面與 nil 管理員類型 UUID 和 MIDL 產生的預設管理員 EPV 產生關聯。 此呼叫會在介面登錄數據表中新增條目。 介面 UUID 包含在參數 IfSpec 中。
根據預設,對象登錄表會將所有物件 UUID 與 nil 類型 UUID 產生關聯。 在這裡範例中,伺服器不會呼叫 rpcObjectSetType。
伺服器執行時庫會收到遠端程序代碼,其中包含呼叫所屬介面的 UUID,以及來自呼叫綁定句柄的物件 UUID。
如需關於如何將物件 UUID 設定到綁定控制代碼的討論,請參閱下列函式參考項目:
使用遠端過程調用中的介面 UUID,伺服器的執行時期庫會在介面註冊表中找出該介面 UUID。
如果伺服器未使用 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2註冊介面,則遠端過程調用會傳回具有RPC_S_UNKNOWN_IF狀態代碼的呼叫端。
使用系結句柄中的物件 UUID,伺服器的運行時間連結庫會在物件登錄表中找出該物件 UUID。 在此範例中,所有物件 UUID 都會對應至 nil 物件類型。
伺服器的執行時期庫會在介面登錄數據表中定位 nil 管理類型。
將介面註冊表中的介面 UUID 與 nil 類型結合後會解析為預設的 EPV,其中包含要為遠端程序調用中找到的介面 UUID 執行的伺服器管理例程。
假設伺服器提供多個介面和每個介面的多個實作,如下表所述。
介面登錄數據表
介面 UUID | 管理員類型 UUID | 進入點向量 |
---|---|---|
uuid1 | 零 | epv1 |
uuid1 | uuid3 | epv4 |
uuid2 | uuid4 | epv2 |
uuid2 | uuid7 | epv3 |
物件登錄數據表
物件 UUID | 物件類型 |
---|---|
uuidA | uuid3 |
uuidB | uuid7 |
uuidC | uuid7 |
uuidD | uuid3 |
uuidE | uuid3 |
uuidF | uuid8 |
零 | 零 |
(任何其他 UUID) | 零 |
將系結句柄對應至進入點向量
介面 UUID (來自用戶端系結句柄) | 物件 UUID (來自用戶端系結句柄) | 物件類型(來自物件登入表) | 管理 EPV(來自介面註冊表) |
---|---|---|---|
uuid1 | 零 | 零 | epv1 |
uuid1 | uuidA | uuid3 | epv4 |
uuid1 | uuidD | uuid3 | epv4 |
uuid1 | uuidE | uuid3 | epv4 |
uuid2 | uuidB | uuid7 | epv3 |
uuid2 | uuidC | uuid7 | epv3 |
下列步驟描述伺服器執行時程式庫採取的動作,當具有介面 UUID uuid2 和物件 UUID uuidC 的用戶端呼叫它時,如前述表格所示。
伺服器會呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2,將它所提供的介面與不同的管理員 EPV 產生關聯。 介面登錄表中的專案反映出四次呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2,用來提供兩個介面,每個介面都有兩個實作(EPV)。
伺服器會呼叫 RpcObjectSetType,以建立它提供的每個物件類型。 除了 nil 物件與 nil 類型的預設關聯之外,在物件登錄數據表中未明確找到的所有其他物件 UUID 也會對應至 nil 類型 UUID。
在此範例中,伺服器會呼叫 RpcObjectSetType 例程六次。
伺服器執行時期庫會收到遠端程序呼叫,其中包含呼叫所屬的介面 UUID,以及來自呼叫綁定控制代碼的物件 UUID。
在遠端過程調用中使用的介面 UUID,伺服器的執行階段庫會在介面登錄表中定位該介面 UUID。
利用來自系結句柄的 uuidC 物件 UUID,伺服器的執行期庫可以在物件登錄表中定位此物件的 UUID,並找到它對應的類型為 uuid7。
若要找出管理員類型,伺服器的運行時間連結庫會結合介面 UUID、uuid2,以及在介面登錄數據表中輸入 uuid7。 這會解析為 epv3,其中包含要針對遠端過程調用執行的伺服器管理員例程。
epv2 中的例程永遠不會執行,因為伺服器尚未呼叫 RpcObjectSetType 例程,將具有 uuid 4 uuid4 類型的任何物件新增至對象登錄數據表。
包含介面 UUID uuid2 和物件 UUID uuidF 的遠端程序呼叫 會向呼叫方返回一個RPC_S_UNKNOWN_MGR_TYPE狀態代碼,因為伺服器未呼叫 RpcServerRegisterIf、RpcServerRegisterIfEx或 RpcServerRegisterIf2 以管理員類型 uuid8註冊這個介面。
傳回值
此函式會傳回下列其中一個值。
價值 | 意義 |
---|---|
RPC_S_OK | 成功 |
RPC_S_TYPE_ALREADY_REGISTERED | 已註冊 UUID 類型 |
提供您自己的物件查詢函式
請考慮管理數千個不同類型物件的伺服器。 每當伺服器啟動時,伺服器應用程式都必須針對每一個物件呼叫 rpcObjectSetType函式,即使用戶端可能只參考其中一些物件(或需要很長的時間才能參考它們)。 這些數千個物件可能位於磁碟上,因此擷取其類型相當耗時。 此外,將物件 UUID 對應至管理員類型 UUID 的內部資料表,實際上會重複物件本身所維護的對應。
為了方便起見,RPC 函式集包含 rpcObjectSetInqFn函式。 使用此函式時,您會提供自己的物件查詢函式。
例如,當您將物件 100–199 對應至類型編號 1、200–299 對應至類型編號 2,依此類推時,您可以提供自己的物件查詢函式。 物件查詢功能也可以擴展至分散式檔案系統,其中伺服器應用程式並不擁有所有可用檔案(物件 UUID)的清單,或者當檔案系統使用物件 UUID 作為檔案識別時,但您不希望預先載入所有物件 UUID 與類型 UUID 之間的映射時。
相關主題