Condividi tramite


Registrazione di un'applicazione kernel Winsock

Registrazione dell'oggetto client WSK

Un'applicazione Winsock Kernel (WSK) deve registrarsi come client WSK chiamando la funzione WskRegister . WskRegister richiede all'applicazione WSK di inizializzare e passare un puntatore all'interfaccia di programmazione di rete del client WSK ( NPI)(una struttura di WSK_CLIENT_NPI ) e un oggetto di registrazione WSK (una struttura WSK_REGISTRATION ) inizializzato da WskRegister al termine della restituzione.

Nell'esempio di codice seguente viene illustrato come un'applicazione WSK può registrarsi come client 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;
  }

  .
  . 
  .
}

Un'applicazione WSK non è necessaria per chiamare WskRegister dall'interno della funzione DriverEntry . Ad esempio, se un'applicazione WSK è un sottocomponente di un driver complesso, la registrazione dell'applicazione potrebbe verificarsi solo quando viene attivato il sottocomponente dell'applicazione WSK.

Un'applicazione WSK deve mantenere la struttura WSK_CLIENT_DISPATCH passata a WskRegister valida e residente in memoria fino a quando WskDeregister non viene chiamato e la registrazione non è più valida. La struttura WSK_REGISTRATION deve anche essere mantenuta valida e residente in memoria fino a quando l'applicazione WSK smette di effettuare chiamate alle altre funzioni di registrazione WSK. L'esempio di codice precedente mantiene queste due strutture nella sezione dati globali del driver, mantenendo quindi i dati della struttura residenti in memoria fino a quando il driver non viene scaricato.

Acquisizione npI del provider WSK

Dopo che un'applicazione WSK è stata registrata come client WSK con WskRegister, deve usare la funzione WskCaptureProviderNPI per acquisire l'NPI del provider WSK dal sottosistema WSK per iniziare a usare l'interfaccia WSK.

Poiché il sottosistema WSK potrebbe non essere ancora pronto quando un'applicazione WSK tenta di acquisire il provider WSK NPI, la funzione WskCaptureProviderNPI consente all'applicazione WSK di eseguire il polling o attendere che il sottosistema WSK diventi pronto come indicato di seguito:

  • Se il parametro WaitTimeout è WSK_NO_WAIT, la funzione restituirà sempre immediatamente senza attendere.

  • Se WaitTimeout è WSK_INFINITE_WAIT, la funzione attenderà finché il sottosistema WSK non sarà pronto.

  • Se WaitTimeout è qualsiasi altro valore, la funzione restituirà quando il sottosistema WSK diventa pronto o quando il tempo di attesa, in millisecondi, raggiunge il valore di WaitTimeout, che si verifica per primo.

Importante Per evitare effetti negativi sull'inizio di altri driver e servizi, un'applicazione WSK che chiama WskCaptureProviderNPI dalla funzione DriverEntry non deve impostare il parametro WaitTimeout su WSK_INFINITE_WAIT o un tempo di attesa eccessivo. Inoltre, se un'applicazione WSK inizia molto presto nella fase di avvio del sistema, dovrebbe attendere che il sottosistema WSK diventi pronto in un thread di lavoro diverso rispetto a quello in cui viene eseguito DriverEntry .

Se la chiamata a WskCaptureProviderNPI ha esito negativo con STATUS_NOINTERFACE, l'applicazione WSK può usare la funzione WskQueryProviderCharacteristics per individuare l'intervallo di versioni di WSK NPI supportate dal sottosistema WSK. L'applicazione WSK può chiamare WskDeregister per annullare la registrazione dell'istanza di registrazione corrente e quindi registrarla di nuovo usando un'istanza di WSK_CLIENT_DISPATCH diversa che usa una versione WSK NPI supportata.

Quando WskCaptureProviderNPI restituisce correttamente, il parametro WskProviderNpi punta a un provider WSK NPI ( WSK_PROVIDER_NPI) pronto per l'uso dall'applicazione WSK. La struttura WSK_PROVIDER_NPI contiene puntatori all'oggetto client WSK ( WSK_CLIENT) e WSK_PROVIDER_DISPATCH alla tabella di invio di funzioni WSK che l'applicazione WSK può usare per creare socket WSK ed eseguire altre operazioni sull'oggetto client WSK. Al termine dell'applicazione WSK usando le funzioni di WSK_PROVIDER_DISPATCH, deve rilasciare il provider WSK NPI chiamando WskReleaseProviderNPI.

Nell'esempio di codice seguente viene illustrato come un'applicazione WSK può acquisire il provider WSK NPI, usarlo per creare un socket e quindi rilasciarlo.

// 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;

}

Un'applicazione WSK può chiamare WskCaptureProviderNPI più di una volta. Per ogni chiamata a WskCaptureProviderNPI che restituisce correttamente, deve essere presente una chiamata corrispondente a WskReleaseProviderNPI. Un'applicazione WSK non deve effettuare ulteriori chiamate alle funzioni in WSK_PROVIDER_DISPATCH dopo aver chiamato WskReleaseProviderNPI.