註冊 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中的函式進行任何進一步呼叫。