註冊介面

本節將詳細說明註冊 RPC 介面的程式。

本節中的資訊會顯示在下列主題中:

介面註冊函式

伺服器藉由呼叫 RpcServerRegisterIf 函式來註冊其介面。 複雜的伺服器程式通常支援多個介面。 伺服器應用程式必須針對其支援的每個介面呼叫此函式一次。

此外,伺服器也可以支援相同介面的多個版本,每個版本都有自己的介面函式實作。 如果您的伺服器程式這樣做,它必須提供一組進入點。 進入點是一個管理員常式,會分派介面版本的呼叫。 每個版本的介面都必須有一個進入點。 進入點群組稱為進入點向量。 如需詳細資訊,請參閱 進入點向量

除了標準函式 RpcServerRegisterIf之外,RPC 也支援其他介面註冊函式。 RpcServerRegisterIf2函式可讓您指定一組註冊旗標, (請參閱介面註冊旗標) 、伺服器可接受的並行遠端程序呼叫要求數目上限,以及傳入資料區塊位元組的最大大小,來擴充RpcServerRegisterIf的功能。

RPC 程式庫也包含稱為 RpcServerRegisterIfEx的函式。 如同 RpcServerRegisterIf 函式,此函式會註冊介面。 您的伺服器程式也可以使用此函式來指定一組註冊旗標, (請參閱 介面註冊 旗標) 、伺服器可接受的並行遠端程序呼叫要求數目上限,以及安全性回呼函式。

RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2函式會在內部介面登錄資料表中設定值。 下表用來將介面 UUID 和物件 UUID 對應至管理員 EPV。 管理員 EPV 是函式指標的陣列,其中包含 IDL 檔案中所指定介面中每個函式原型的一個函式指標。

如需提供多個 EPV 以提供介面多個實作的資訊,請參閱 多個介面實作

執行時間程式庫會使用介面登錄資料表 (透過呼叫RpcServerRegisterIf、RpcServerRegisterIfExRpcServerRegisterIf2) ,以及呼叫RpcObjectSetType) 將介面和物件 UUID 對應至函式指標所設定的物件登錄資料表 (。

當您希望伺服器程式從 RPC 執行時間程式庫登錄中移除介面時,請呼叫 RpcServerUnregisterIf 函式。 從登錄中移除介面之後,RPC 執行時間程式庫將不再接受該介面的新呼叫。

進入點向量

管理員進入點向量 (EPV) 是函式指標陣列,指向 IDL 檔案中指定的函式實作。 陣列中的元素數目會對應至 IDL 檔案中指定的函式數目。 RPC 支援多個進入點向量,代表介面中所指定函式的多個實作。

MIDL 編譯器會自動產生管理員 EPV 資料類型,以用於建構管理員 EPV。 資料類型命名 為 if-name**_SERVER_EPV**,其中 if-name 指定 IDL 檔案中的介面識別碼。

MIDL 編譯器會自動建立並初始化預設管理者 EPV,假設介面中的每個程式都有相同名稱的管理員常式,並在 IDL 檔案中指定。

當伺服器提供相同介面的多個實作時,伺服器必須為每個實作建立一個額外的管理員 EPV。 每個 EPV 都必須針對 IDL 檔案中定義的每個程式,只包含函式) 的一個進入點 (位址。 伺服器應用程式會針對介面的每個額外實作,宣告並初始化 類型為 if-name**_SERVER_EPV** 的一個管理員 EPV 變數。 若要註冊 EPV,它會針對它支援的每個物件類型呼叫RpcServerRegisterIf、RpcServerRegisterIfExRpcServerRegisterIf2一次。

當用戶端對伺服器進行遠端程序呼叫時,會根據介面 UUID 和物件類型來選取包含函式指標的 EPV。 物件類型衍生自 object-in查詢函式的物件 UUID 或 RpcObjectSetType所控制的資料表驅動對應。

經理 EPV

根據預設,MIDL 編譯器會使用介面 IDL 檔案中的程式名稱來產生管理員 EPV,編譯器會將它直接放入伺服器存根。 這個預設 EPV 會使用介面定義中所宣告的程式名稱,以靜態方式初始化。

若要使用預設 EPV 註冊管理員,請在呼叫RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2函式時,將Null指定為MgrEpv參數的值。 如果管理員所使用的常式名稱對應至介面定義的常式名稱,您可以使用 MIDL 編譯器所產生的介面預設 EPV 來註冊此管理員。 您也可以使用伺服器應用程式所提供的 EPV 註冊管理員。

伺服器可以 (,有時必須) 建立並註冊介面的非Null 管理員 EPV。 若要選取伺服器應用程式提供的 EPV,請傳遞伺服器已宣告其值為 MgrEpv 參數值的 EPV 位址。 MgrEpv的非Null值,參數一律會覆寫伺服器存根中的預設 EPV。

MIDL 編譯器會自動產生管理員 EPV 資料類型 (RPC_MGR_EPV) ,讓伺服器應用程式用於建構管理員 EPV。 管理員 EPV 必須針對 IDL 檔案中定義的每個程式,只包含一個進入點 (函式位址) 。

在下列情況下,伺服器必須提供非Null EPV:

  • 當管理員常式的名稱與介面定義中所宣告的程式名稱不同時
  • 當伺服器使用預設 EPV 來註冊介面的另一個實作時

伺服器會針對介面的每個實作,初始化 if-name**_SERVER_EPV** 類型的變數來宣告管理員 EPV。

註冊介面的單一實作

當伺服器只提供一個介面的實作時,伺服器只會呼叫 RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2 一次。 在標準案例中,伺服器會使用預設管理者 EPV。 (例外狀況是管理員使用與 interface.) 中所宣告的常式名稱不同時

針對標準案例,您會提供下列值來呼叫RpcServerRegisterIfRpcServerRegisterIfEx 或 RpcServerRegisterIf2

  • 經理 EPV

    若要使用預設 EPV,請為MgrEpv指定參數的 Null值。

  • 管理員類型 UUID

    使用預設 EPV 時,請為MgrTypeUuid參數提供Null值或 nil UUID,以向 nil 管理員類型 UUID 註冊介面。 在此情況下,不論系結控制碼中的物件 UUID 為何,所有遠端程序呼叫都會分派至預設 EPV,假設尚未進行 RpcObjectSetType 呼叫。

    您也可以提供非 nil 管理員類型 UUID。 在此情況下,您也必須呼叫 RpcObjectSetType 常式。

註冊介面的多個實作

您可以提供一個以上的遠端程式實作, (在 IDL 檔案中指定的) 。 伺服器應用程式會呼叫RpcObjectSetType將物件 UUID 對應至類型 UUID,並呼叫RpcServerRegisterIf、RpcServerRegisterIfExRpcServerRegisterIf2,以將管理員 EPV 與類型 UUID 產生關聯。 當遠端程序呼叫與其物件 UUID 一起送達時,RPC 伺服器執行時間程式庫會將物件 UUID 對應至 UUID 類型。 然後,伺服器應用程式會使用 UUID 類型和介面 UUID 來選取管理員 EPV。

您也可以指定自己的函式,以解析從物件 UUID 到管理員類型 UUID 的對應。 當您呼叫 RpcObjectSetInqFn時,您可以指定對應函式。

若要提供介面的多個實作,伺服器必須分別呼叫RpcServerRegisterIfRpcServerRegisterIfEx 或 RpcServerRegisterIf2來註冊每個實作。 針對伺服器暫存器的每個實作,它會提供相同的 IfSpec 參數,但一組不同的 MgrTypeUuidMgrEpv 參數。

在多個管理員的情況下,請使用 RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2 ,如下所示:

  • 經理 EPV

    若要提供介面的多個實作,伺服器必須:

    請注意,伺服器也可以向預設管理者 EPV 註冊。

  • 管理員類型 UUID

    為每個介面的 EPV 提供管理員類型 UUID。 可為其中一個管理員 EPV 指定參數的 nil 類型 UUID (或null值) 。 每個類型 UUID 都必須不同。

叫用管理員常式的規則

RPC 執行時間程式庫會將傳入遠端程序呼叫分派給提供所要求 RPC 介面的管理員。 當多個管理員註冊介面時,RPC 執行時間程式庫必須選取其中一個。 若要選取管理員,RPC 執行時間程式庫會使用呼叫系結控制碼所指定的物件 UUID。

執行時間程式庫在解譯遠端程序呼叫的物件 UUID 時,會套用下列規則:

  • Nil 物件 UUID

    nil 物件 UUID 會自動指派 nil 類型 UUID (在 RpcObjectSetType 常式中指定 nil 物件 UUID) 不合法。 因此,系結控制碼包含 nil 物件 UUID 的遠端程序呼叫會自動分派至向 nil 類型 UUID 註冊的管理員,如果有的話。

  • 非 nil 物件 UUID

    基本上,系結控制碼包含非 nil 物件 UUID 的遠端程序呼叫應該由類型 UUID 符合物件 UUID 類型的管理員處理。 不過,識別正確的管理員需要伺服器已藉由呼叫 RpcObjectSetType 常式來指定該物件的 UUID 類型。

    如果伺服器無法呼叫非 nil 物件 UUID 的 RpcObjectSetType 常式,該物件 UUID 的遠端程序呼叫會移至服務遠端過程呼叫的管理員 EPV,其中 nil 物件 UUID (亦即 nil 類型 UUID) 。

    如果伺服器藉由呼叫RpcObjectSetType常式來指派非 nil 物件 UUID 類型 UUID,則無法執行系結控制碼中具有非 nil 物件 UUID 的遠端過程呼叫,但不會呼叫RpcServerRegisterIf、RpcServerRegisterIfExRpcServerRegisterIf2,為該類型 UUID 註冊管理員 EPV。

下表摘要說明執行時間程式庫用來選取管理員常式的動作。

呼叫的物件 UUID 物件 UUID 的伺服器集類型? 伺服器已註冊的 EPV 類型? 分派動作
不適用 使用具有 nil 類型 UUID 的管理員。
不適用 錯誤 (RPC_S_UNSUPPORTED_TYPE) ;會拒絕遠端程序呼叫。
非 nil Yes Yes 使用具有相同類型 UUID 的管理員。
非 nil 忽略 使用具有 nil 類型 UUID 的管理員。 如果沒有具有 nil 類型 UUID 的管理員,則錯誤 (RPC_S_UNSUPPORTEDTYPE) ;會拒絕遠端程序呼叫。
非 nil No 錯誤 (RPC_S_UNSUPPORTEDTYPE) ;會拒絕遠端程序呼叫。

 

呼叫的物件 UUID 是遠端程序呼叫之系結控制碼中找到的物件 UUID。

伺服器會呼叫 RpcObjectSetType 來指定物件的 UUID 類型,以設定物件的類型 UUID。

伺服器會使用相同類型 UUID 呼叫 RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2 來註冊管理員 EPV 的類型。

注意

nil 物件 UUID 一律會自動指派 nil 類型 UUID。 在 RpcObjectSetType 常式中指定 nil 物件 UUID 不合法。

 

將遠端程序呼叫分派給伺服器管理員常式

下表顯示 RPC 執行時間程式庫將遠端程序呼叫分派給伺服器管理員常式所需的步驟。

下表說明伺服器註冊預設管理者 EPV 的簡單案例。

介面登錄資料表

介面 UUID 管理員類型 UUID 進入點向量
uuid1 預設 EPV

 

物件登錄資料表

物件 UUID 物件型別
(任何其他物件 UUID)

 

將系結控制碼對應至進入點向量 (EPV)

來自用戶端系結控制碼的介面 UUID () 來自用戶端系結控制碼) 的物件 UUID ( 從物件登錄資料表 (物件類型) 從介面登錄資料表) 管理員 EPV (
uuid1 預設 EPV
同上 uuidA 預設 EPV

 

下列步驟描述當具有介面 UUID uuid1 的用戶端呼叫它時,RPC 伺服器執行時間程式庫所採取的動作,如上述表格所示。

  1. 伺服器會呼叫RpcServerRegisterIfRpcServerRegisterIfEx 或 RpcServerRegisterIf2,將它所提供的介面與 nil 管理員類型 UUID 和 MIDL 產生的預設管理者 EPV 產生關聯。 此呼叫會在介面登錄資料表中新增專案。 介面 UUID 包含在 IfSpec 參數中。

  2. 根據預設,物件登錄資料表會將所有物件 UUID 與 nil 類型 UUID 產生關聯。 在此範例中,伺服器不會呼叫 RpcObjectSetType

  3. 伺服器執行時間程式庫會收到遠端程式碼,其中包含呼叫所屬的介面 UUID,以及呼叫系結控制碼中的物件 UUID。

    如需如何將物件 UUID 設定為系結控制碼的討論,請參閱下列函式參考專案:

  4. 從遠端程序呼叫使用介面 UUID,伺服器的執行時間程式庫會在介面登錄資料表中找出該介面 UUID。

    如果伺服器未使用RpcServerRegisterIf、RpcServerRegisterIfExRpcServerRegisterIf2註冊介面,則遠端程序呼叫會傳回具有RPC_S_UNKNOWN_IF狀態碼的呼叫端。

  5. 從系結控制碼使用物件 UUID,伺服器執行時間程式庫會在物件登錄資料表中找出該物件 UUID。 在此範例中,所有物件 UUID 都會對應至 nil 物件類型。

  6. 伺服器的執行時間程式庫會在介面登錄資料表中找出 nil 管理員類型。

  7. 結合介面登錄資料表中的介面 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 的用戶端呼叫它時,

  1. 伺服器會呼叫 RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2 ,以將它所提供的介面與不同的管理員 EPV 產生關聯。 介面登錄資料表中的專案反映 RpcServerRegisterIfRpcServerRegisterIfExRpcServerRegisterIf2 的四個呼叫,以提供兩個介面,其中兩個實作 (每個介面的 EPV) 。

  2. 伺服器會呼叫 RpcObjectSetType ,以建立它提供的每個物件類型。 除了 nil 物件與 nil 類型的預設關聯之外,物件登錄表中未明確找到的所有其他物件 UUID 也會對應至 nil 類型 UUID。

    在此範例中,伺服器會呼叫 RpcObjectSetType 常式六次。

  3. 伺服器執行時間程式庫會收到遠端程序呼叫,其中包含呼叫所屬的介面 UUID,以及呼叫系結控制碼中的物件 UUID。

  4. 使用遠端程序呼叫中的介面 UUID,伺服器的執行時間程式庫會在介面登錄表中找出介面 UUID。

  5. 使用系結控制碼中的 uuidC 物件 UUID ,伺服器的執行時間程式庫會找出物件登錄資料表中的物件 UUID,併發現它對應至 uuid7類型。

  6. 若要找出管理員類型,伺服器的執行時間程式庫會在介面登錄資料表中結合介面 UUID、 uuid2和類型 uuid7 。 這會解析為 epv3,其中包含要針對遠端程序呼叫執行的伺服器管理員常式。

epv2中的常式永遠不會執行,因為伺服器尚未呼叫RpcObjectSetType常式,將類型UUID 為 uuid4的任何物件新增至物件登錄資料表。

具有介面 UUID uuid2和物件 UUID uuidF的遠端程序呼叫會傳回具有RPC_S_UNKNOWN_MGR_TYPE狀態碼的呼叫端,因為伺服器未呼叫RpcServerRegisterIf、RpcServerRegisterIfEx 或 RpcServerRegisterIf2,以使用 uuid8的管理員類型註冊介面。

傳回值

此函式會傳回下列其中一個值。

意義
RPC_S_OK Success
RPC_S_TYPE_ALREADY_REGISTERED 已註冊類型 UUID

 

提供您自己的物件查詢函式

請考慮管理許多不同類型數千個物件的伺服器。 每當伺服器啟動時,伺服器應用程式都必須針對每個物件呼叫 RpcObjectSetType 函式,即使用戶端可能只參考其中幾個物件 (或花很長的時間參考它們) 。 這些數千個物件可能位於磁片上,因此擷取其類型相當耗時。 此外,將物件 UUID 對應至管理員類型 UUID 的內部資料表基本上會複製與物件本身維護的對應。

為了方便起見,RPC 函式集包含 RpcObjectSetInqFn函數。 透過此函式,您可以提供自己的物件查詢函式。

例如,當您將物件 100–199 對應至類型數位 1、200–299 到類型數位 2 時,您可以提供自己的物件查詢函式,依此類歸。 物件查詢函式也可以延伸至分散式檔案系統,其中伺服器應用程式沒有可用的所有檔案清單 (物件 UUID) ,或當檔案系統中的物件 UUID 名稱檔,而且您不想預先載入物件 UUID 與類型 UUID 之間的所有對應。

RpcBindingFromStringBinding

RpcBindingSetObject

RpcNsBindingExport

RpcNsBindingImportBegin

RpcNsBindingLookupBegin

RpcObjectSetType

RpcServerRegisterIf

RpcServerRegisterIf2

RpcServerRegisterIfEx

RpcServerUnregisterIf

RpcServerUnregisterIfEx