在 Winsock Kernel (WSK) 應用程式向 網路模組註冊器 (NMR) 註冊為 WSK NPI 的客戶端之後,如果 WSK 子系統已載入且已向 NMR 註冊本身,NMR 會立即呼叫應用程式的 ClientAttachProvider 回呼函式。 如果 WSK 子系統未向 NMR 註冊,則 NMR 不會呼叫應用程式的 ClientAttachProvider 回呼函式,直到 WSK 子系統向 NMR 註冊為止。
WSK 應用程式應該進行下列一連串的呼叫,以完成附件程式。
當 NMR 呼叫 WSK 應用程式的 ClientAttachProvider 回呼函式時,它會將指標傳遞至與 WSK 子系統相關聯的 NPI_REGISTRATION_INSTANCE 結構。 WSK 應用程式的 ClientAttachProvider 回呼函式可以使用 NMR 傳遞給它的數據來判斷它是否可以附加至 WSK 子系統。 一般而言,WSK 應用程式只需要 WSK 子系統NPI_REGISTRATION_INSTANCE結構之 NpiSpecificCharacteristics 成員所指向之WSK_PROVIDER_CHARACTERISTICS結構中包含的版本資訊。
如果 WSK 應用程式判斷它可以附加至 WSK 子系統,則 WSK 應用程式的 ClientAttachProvider 回呼函式會配置並初始化 WSK 子系統附件的系結內容結構。 然後應用程式會呼叫 NmrClientAttachProvider 函式,以繼續附件程式。
如果 NmrClientAttachProvider 傳回STATUS_SUCCESS,則 WSK 應用程式已成功連結至 WSK 子系統。 在此情況下,WSK 應用程式的 ClientAttachProvider 回呼函式必須在 NMR 呼叫應用程式的 ClientAttachProvider 回呼函式時,儲存 NMR 傳入 NmrBindingHandle 參數的系結句柄。 WSK 應用程式的 ClientAttachProvider 回呼函式還必須將客戶端物件(WSK_CLIENT)與提供者分派表(WSK_PROVIDER_DISPATCH)的指標儲存在應用程式傳遞給 NmrClientAttachProvider 函式的 ProviderBindingContext 和 ProviderDispatch 參數中所使用的變數中。 WSK 應用程式通常會將此資料儲存在其系結內容中,以便附加到 WSK 子系統。 在 WSK 應用程式成功附加至 WSK 子系統之後,WSK 應用程式的 ClientAttachProvider 回呼函式必須傳回STATUS_SUCCESS。
如果 NmrClientAttachProvider 傳回 STATUS_NOINTERFACE,WSK 應用程式可以再次嘗試呼叫 NmrClientAttachProvider 函式,將 ClientDispatch 指標傳遞至另一個 WSK_CLIENT_DISPATCH 結構,以指定應用程式支援的 WSK NPI 替代版本。
如果 對 NmrClientAttachProvider 函式的呼叫未傳回STATUS_SUCCESS,而且 WSK 應用程式不會再嘗試附加至 WSK 子系統,則 WSK 應用程式的 ClientAttachProvider 回呼函式應該清除並解除分配在 呼叫 NmrClientAttachProvider 之前配置的任何資源。 在此情況下,WSK 應用程式的 ClientAttachProvider 回呼函式必須傳回最後一次呼叫 NmrClientAttachProvider 函式所傳回的狀態代碼。
如果 WSK 應用程式判斷它無法附加至提供者模組,則應用程式的 ClientAttachProvider 回呼函式必須傳回STATUS_NOINTERFACE。
下列程式代碼範例示範 WSK 應用程式如何自行附加至 WSK 子系統。
// Context structure type for the WSK application's
// binding to the WSK subsystem
typedef struct WSK_APP_BINDING_CONTEXT_ {
HANDLE NmrBindingHandle;
PWSK_CLIENT WskClient;
PWSK_PROVIDER_DISPATCH WskProviderDispatch;
.
. // Other application-specific members
.
} WSK_APP_BINDING_CONTEXT, *PWSK_APP_BINDING_CONTEXT;
// Pool tag used for allocating the binding context
#define BINDING_CONTEXT_POOL_TAG 'tpcb'
// The WSK application uses version 1.0 of WSK
#define WSK_APP_WSK_VERSION MAKE_WSK_VERSION(1,0)
// Structure for the WSK application's dispatch table
const WSK_CLIENT_DISPATCH WskAppDispatch = {
WSK_APP_WSK_VERSION,
0,
NULL // No WskClientEvent callback
};
// ClientAttachProvider NMR API callback function
NTSTATUS
ClientAttachProvider(
IN HANDLE NmrBindingHandle,
IN PVOID ClientContext,
IN PNPI_REGISTRATION_INSTANCE ProviderRegistrationInstance
)
{
PNPI_MODULEID WskProviderModuleId;
PWSK_PROVIDER_CHARACTERISTICS WskProviderCharacteristics;
PWSK_APP_BINDING_CONTEXT BindingContext;
PWSK_CLIENT WskClient;
PWSK_PROVIDER_DISPATCH WskProviderDispatch;
NTSTATUS Status;
// Get pointers to the WSK subsystem's identification and
// characteristics structures
WskProviderModuleId = ProviderRegistrationInstance->ModuleId;
WskProviderCharacteristics =
(PWSK_PROVIDER_CHARACTERISTICS)
ProviderRegistrationInstance->NpiSpecificCharacteristics;
//
// The WSK application can use the data in the structures pointed
// to by ProviderRegistrationInstance, WskProviderModuleId, and
// WskProviderCharacteristics to determine if the WSK application
// can attach to the WSK subsystem.
//
// In this example, the WSK application does not perform any
// checks to determine if it can attach to the WSK subsystem.
//
// Allocate memory for the WSK application's binding
// context structure
BindingContext =
(PWSK_APP_BINDING_CONTEXT)
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(WSK_APP_BINDING_CONTEXT),
BINDING_CONTEXT_POOL_TAG
);
// Check result of allocation
if (BindingContext == NULL)
{
// Return error status code
return STATUS_INSUFFICIENT_RESOURCES;
}
// Initialize the binding context structure
...
// Continue with the attachment to the WSK subsystem
Status = NmrClientAttachProvider(
NmrBindingHandle,
BindingContext,
&WskAppDispatch,
&WskClient,
&WskProviderDispatch
);
// Check result of attachment
if (Status == STATUS_SUCCESS)
{
// Save NmrBindingHandle, WskClient, and
// WskProviderDispatch for future reference
BindingContext->NmrBindingHandle = NmrBindingHandle;
BindingContext->WskClient = WskClient;
BindingContext->WskProviderDispatch = WskProviderDispatch;
}
// Attachment did not succeed
else
{
// Free memory for application's binding context structure
ExFreePoolWithTag(
BindingContext,
BINDING_CONTEXT_POOL_TAG
);
}
// Return result of attachment
return Status;
}