Поделиться через


Регистрация приложения ядра Winsock

Регистрация клиентского объекта WSK

Приложение winsock Kernel (WSK) должно быть зарегистрировано в качестве клиента WSK путем вызова функции WskRegister . WskRegister требует, чтобы приложение WSK инициализировало и передало указатель на сетевой программный интерфейс (NPI) клиента WSK (структура WSK_CLIENT_NPI ) и объект регистрации WSK ( структура WSK_REGISTRATION ), который будет инициализирован WskRegister после успешного возврата.

В следующем примере кода показано, как приложение 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 не требуется вызывать WskRegister из функции DriverEntry . Например, если приложение WSK является подкомпонентом сложного драйвера, регистрация приложения может происходить только при активации подкомпонента приложения WSK.

Приложение WSK должно поддерживать структуру WSK_CLIENT_DISPATCH , переданную в WskRegister , действительную и резидентную в памяти, пока не будет вызван метод WskDeregister и регистрация не будет действительна. Структура WSK_REGISTRATION также должна оставаться действительной и находиться в памяти до тех пор, пока приложение WSK не перестанет выполнять вызовы других функций регистрации WSK. В предыдущем примере кода эти две структуры сохраняются в разделе глобальных данных драйвера, тем самым сохраняя данные структуры в памяти до тех пор, пока драйвер не выгрузится.

Сбор NPI поставщика WSK

После регистрации приложения WSK в качестве клиента WSK в WskRegister оно должно использовать функцию WskCaptureProviderNPI для записи NPI поставщика WSK из подсистемы WSK, чтобы начать использовать интерфейс WSK.

Так как подсистема WSK может быть еще не готова, когда приложение WSK пытается записать NPI поставщика WSK, функция WskCaptureProviderNPI позволяет приложению WSK опрашивать подсистему WSK или ожидать готовности подсистемы WSK следующим образом:

  • Если параметр WaitTimeout WSK_NO_WAIT, функция всегда будет возвращать немедленно, не ожидая.

  • Если значение WaitTimeout WSK_INFINITE_WAIT, функция будет ожидать готовности подсистемы WSK.

  • Если WaitTimeout имеет любое другое значение, функция возвращает либо когда подсистема WSK будет готова, либо когда время ожидания в миллисекундах достигает значения WaitTimeout в зависимости от того, что произойдет раньше.

Важно Чтобы избежать негативного влияния на запуск других драйверов и служб, приложение WSK, которое вызывает WskCaptureProviderNPI из функции DriverEntry , не должно задавать для параметра WaitTimeout значение WSK_INFINITE_WAIT или чрезмерное время ожидания. Кроме того, если приложение WSK запускается очень рано на этапе запуска системы, ему следует дождаться готовности подсистемы WSK в другом рабочем потоке, отличном от того, в котором выполняется DriverEntry .

Если вызов WskCaptureProviderNPI завершается сбоем с STATUS_NOINTERFACE, приложение WSK может использовать функцию WskQueryProviderCharacteristics для обнаружения диапазона версий NPI WSK, поддерживаемых подсистемой WSK. Приложение WSK может вызвать WskDeregister , чтобы отменить регистрацию текущего экземпляра регистрации, а затем снова зарегистрировать с помощью другого экземпляра WSK_CLIENT_DISPATCH , использующего поддерживаемую версию NPI WSK.

При успешном возврате WskCaptureProviderNPI его параметр WskProviderNpi указывает на NPI поставщика WSK ( WSK_PROVIDER_NPI), готовый к использованию приложением WSK. Структура WSK_PROVIDER_NPI содержит указатели на клиентский объект WSK ( WSK_CLIENT) и таблицу диспетчеризации WSK_PROVIDER_DISPATCH функций WSK, которую приложение WSK может использовать для создания сокетов WSK и выполнения других операций с клиентским объектом WSK. После завершения работы приложения WSK с функциями WSK_PROVIDER_DISPATCH оно должно освободить NPI поставщика WSK, вызвав WskReleaseProviderNPI.

В следующем примере кода показано, как приложение WSK может записать NPI поставщика WSK, использовать его для создания сокета, а затем освободить его.

// 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 не должно выполнять дальнейшие вызовы функций в WSK_PROVIDER_DISPATCH после вызова WskReleaseProviderNPI.