註冊 Winsock 核心應用程式
WSK 用戶端物件註冊
Winsock Kernel (WSK) 應用程式必須藉由呼叫 WskRegister 函式來註冊為 WSK 用戶端。 WskRegister 需要 WSK應用程式初始化 WSK 用戶端的網路程式設計介面 (NPI) (WSK_CLIENT_NPI () 和 WSK 註冊物件 (WSK 註冊物件, (WskRegister在成功傳回時初始化WSK_REGISTRATION結構) 。
下列程式碼範例示範 WSK 應用程式如何註冊為 WSK 用戶端。
// Include the WSK header file
#include "wsk.h"
// WSK Client Dispatch table that denotes the WSK version
// that the WSK application wants to use and optionally a pointer
// to the WskClientEvent callback function
const WSK_CLIENT_DISPATCH WskAppDispatch = {
MAKE_WSK_VERSION(1,0), // Use WSK version 1.0
0, // Reserved
NULL // WskClientEvent callback not required for WSK version 1.0
};
// WSK Registration object
WSK_REGISTRATION WskRegistration;
// DriverEntry function
NTSTATUS
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status;
WSK_CLIENT_NPI wskClientNpi;
.
.
.
// Register the WSK application
wskClientNpi.ClientContext = NULL;
wskClientNpi.Dispatch = &WskAppDispatch;
Status = WskRegister(&wskClientNpi, &WskRegistration);
if(!NT_SUCCESS(Status)) {
.
.
.
return Status;
}
.
.
.
}
從其DriverEntry函式內呼叫WskRegister 不需要 WSK應用程式。 例如,如果 WSK 應用程式是複雜驅動程式的子元件,則只有在啟用 WSK 應用程式子元件時,才會發生應用程式的註冊。
WSK 應用程式必須保留傳遞至WskRegister有效且位於記憶體中的WSK_CLIENT_DISPATCH結構,直到呼叫WskDeregister且註冊不再有效為止。 WSK_REGISTRATION結構也必須保持有效且保留在記憶體中,直到 WSK 應用程式停止呼叫其他WSK 註冊函式為止。 上述程式碼範例會將這兩個結構保留在驅動程式的全域資料區段中,藉此將結構資料保留在記憶體中,直到卸載驅動程式為止。
WSK 提供者 NPI 擷取
在 WSK 應用程式向 WskRegister註冊為 WSK 用戶端之後,它必須使用 WskCaptureProviderNPI 函式,從 WSK 子系統擷取 WSK 提供者 NPI,才能開始使用 WSK 介面。
由於 WSK 子系統在 WSK 應用程式嘗試擷取 WSK 提供者 NPI 時可能尚未就緒,因此 WskCaptureProviderNPI 函式可讓 WSK 應用程式輪詢或等候 WSK 子系統準備就緒,如下所示:
如果 WaitTimeout 參數WSK_NO_WAIT,函式一律會立即傳回,而不需等候。
如果 WaitTimeout WSK_INFINITE_WAIT,函式會等到 WSK 子系統準備就緒為止。
如果 WaitTimeout 是任何其他值,則當 WSK 子系統準備就緒或等候時間以毫秒為單位時,函式會傳回 WaitTimeout的值,不論第一個情況。
重要為了避免對其他驅動程式和服務啟動造成負面影響,從其DriverEntry函式呼叫WskCaptureProviderNPI 的 WSK應用程式不應將WaitTimeout參數設定為WSK_INFINITE_WAIT或過度等候時間。 此外,如果 WSK 應用程式在系統啟動階段初期啟動,它應該等候 WSK 子系統準備好在與 DriverEntry 執行所在的背景工作執行緒不同的背景工作執行緒中。
如果 呼叫 WskCaptureProviderNPI 失敗並STATUS_NOINTERFACE,WSK 應用程式可以使用 WskQueryProviderCharacteristics 函式來探索 WSK NPI 子系統所支援的 WSK NPI 版本範圍。 WSK 應用程式可以呼叫 WskDeregister 來取消註冊其目前的註冊實例,然後使用使用支援 WSK NPI 版本的不同 WSK_CLIENT_DISPATCH 實例重新註冊。
當 WskCaptureProviderNPI 成功傳回時,其 WskProviderNpi 參數會指向 WSK 提供者 NPI ( WSK_PROVIDER_NPI) 可供 WSK 應用程式使用。 WSK_PROVIDER_NPI 結構包含 WSK 用戶端物件的指標, ( WSK_CLIENT) ,以及 WSK 應用程式可用來建立 WSK 通訊端並在 WSK 用戶端物件上執行其他作業的 WSK 函 式WSK_PROVIDER_DISPATCH分 派資料表。 使用WSK_PROVIDER_DISPATCH函式完成 WSK 應用程式之後,它必須藉由呼叫 WskReleaseProviderNPI 來釋放 WSK 提供者 NPI。
下列程式碼範例示範 WSK 應用程式如何擷取 WSK 提供者 NPI、使用它來建立通訊端,然後釋放它。
// WSK application routine that waits for WSK subsystem
// to become ready and captures the WSK Provider NPI
NTSTATUS
WskAppWorkerRoutine(
)
{
NTSTATUS Status;
WSK_PROVIDER_NPI wskProviderNpi;
// Capture the WSK Provider NPI. If WSK subsystem is not ready yet,
// wait until it becomes ready.
Status = WskCaptureProviderNPI(
&WskRegistration, // must have been initialized with WskRegister
WSK_INFINITE_WAIT,
&wskProviderNpi
);
if(!NT_SUCCESS(Status))
{
// The WSK Provider NPI could not be captured.
if( Status == STATUS_NOINTERFACE ) {
// WSK application's requested version is not supported
}
else if( status == STATUS_DEVICE_NOT_READY ) {
// WskDeregister was invoked in another thread thereby causing
// WskCaptureProviderNPI to be canceled.
}
else {
// Some other unexpected failure has occurred
}
return Status;
}
// The WSK Provider NPI has been captured.
// Create and set up a listening socket that accepts
// incoming connections.
Status = CreateListeningSocket(&wskProviderNpi, ...);
// The WSK Provider NPI will not be used any more.
// So, release it here immediately.
WskReleaseProviderNPI(&WskRegistration);
// Return result of socket creation routine
return Status;
}
WSK 應用程式可以多次呼叫 WskCaptureProviderNPI 。 對於成功傳回 的每個 WskCaptureProviderNPI 呼叫,都必須有對 WskReleaseProviderNPI的對應呼叫。 在呼叫WskReleaseProviderNPI之後,WSK 應用程式不得對WSK_PROVIDER_DISPATCH中的函式進行任何進一步呼叫。