Winsock カーネル アプリケーションの登録
WSK クライアント オブジェクトの登録
Winsock カーネル (WSK) アプリケーションは、WskRegister 関数を呼び出して WSK クライアントとして登録する必要があります。 WskRegister では、その WSK クライアントのネットワーク プログラミング インターフェイス (NPI)(WSK_CLIENT_NPI 構造) と WSK 登録オブジェクト (WSK_REGISTRATION 構造) (正常に戻ったときに WskRegister によって初期化されます) へのポインターを WSK アプリケーションが初期化して渡す必要があります。
次のコード例は、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;
}
.
.
.
}
WSK アプリケーションは、DriverEntry 関数内から WskRegister を呼び出す必要はありません。 たとえば、WSK アプリケーションが複雑なドライバーのサブコンポーネントである場合、WSK アプリケーション サブコンポーネントがアクティブ化される際にのみ、アプリケーションの登録が発生する可能性があります。
wskDeregister が呼び出され、登録が無効になるまで、WSK アプリケーションは、WskRegister に渡された WSK_CLIENT_DISPATCH 構造を有効な状態に保ち、メモリ内に常駐させる必要があります。 さらに、WSK アプリケーションが他の WSK 登録関数の呼び出しを停止するまで、WSK_REGISTRATION 構造は有効であり、メモリ内に常駐している必要があります。 前のコード例では、ドライバーのグローバル データ セクションにこれら 2 つの構造を保持しており、ドライバーがアンロードされるまで構造データをメモリに保持しています。
WSK プロバイダー NPI キャプチャ
WSK アプリケーションは、WskRegister に WSK クライアントとして登録されると、WSK インターフェイスの使用を開始するため、WskCaptureProviderNPI 関数を使用して WSK サブシステムから WSK プロバイダー NPI をキャプチャする必要があります。
WSK アプリケーションが WSK プロバイダー NPI のキャプチャを試みたとき、WSK サブシステムの準備がまだできていない可能性があるため、WskCaptureProviderNPI 関数を使用することで、WSK アプリケーションが WSK サブシステムをポーリングしたり、WSK サブシステムの準備が整うのを待機したりできるようになります。
WaitTimeout パラメーターが WSK_NO_WAIT の場合は必ず、関数は待機せずにすぐに戻ります。
WaitTimeout が WSK_INFINITE_WAIT の場合、関数は WSK サブシステムの準備ができるまで待機します。
WaitTimeout が他の値である場合、関数は WSK サブシステムの準備が整ったとき、または待機時間 (ミリ秒単位) が WaitTimeout の値に達したとき (どちらか早い方) に値を返します。
重要 他のドライバーやサービスの開始に悪影響を与えないようにするため、その DriverEntry 関数から WskCaptureProviderNPI を呼び出す WSK アプリケーションで、WaitTimeout パラメーターを WSK_INFINITE_WAIT または過剰な待機時間に設定しないでください。 さらに、WSK アプリケーションがシステム起動フェーズの非常に早い段階で開始される場合、DriverEntry が実行されるワーカー スレッドとは異なるワーカー スレッドで WSK サブシステムが準備できるようになるのを待つ必要があります。
wskCaptureProviderNPI の呼び出しが STATUS_NOINTERFACE で失敗した場合、WSK アプリケーションは WskQueryProviderCharacteristics 関数を使用して、WSK サブシステムによってサポートされている WSK NPI バージョンの範囲を検出できます。 WSK アプリケーションは、WskDeregister を呼び出して現在の登録インスタンスの登録を解除してから、サポートされている WSK NPI バージョンを使用する別の WSK_CLIENT_DISPATCH インスタンスを使用して再登録できます。
WskCaptureProviderNPI が値を正常に返すと、その WskProviderNpi パラメーターは、WSK アプリケーションによって使用できる WSK プロバイダー NPI (WSK_PROVIDER_NPI) をポイントします。 WSK_PROVIDER_NPI 構造には、WSK クライアント オブジェクト (WSK_CLIENT) へのポインターと、WSK アプリケーションが WSK ソケットの作成やその他の操作を WSK クライアント オブジェクトで実行するために使用できる WSK 関数の WSK_PROVIDER_DISPATCH ディスパッチ テーブルが含まれています。 WSK アプリケーションは、WSK_PROVIDER_DISPATCH 関数の使用が完了したら、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 への対応する呼び出しが必要です。 WSK アプリケーションは、WskReleaseProviderNPI を呼び出した後、WSK_PROVIDER_DISPATCH 内の関数をそれ以上呼び出してはなりません。