Registrieren einer Winsock-Kernelanwendung

WSK-Clientobjektregistrierung

Eine Winsock Kernel-Anwendung (WSK) muss sich als WSK-Client registrieren, indem die WskRegister-Funktion aufgerufen wird. WskRegister erfordert, dass die WSK-Anwendung einen Zeiger auf die Netzwerkprogrammierschnittstelle (Network Programming Interface, NPI) ihres WSK-Clients (eine WSK_CLIENT_NPI-Struktur ) und ein WSK-Registrierungsobjekt (eine WSK_REGISTRATION-Struktur ) ihres WSK-Clients initialisiert, das nach erfolgreicher Rückgabe von WskRegister initialisiert wird.

Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung sich als WSK-Client registrieren kann.

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

  .
  . 
  .
}

Eine WSK-Anwendung ist nicht erforderlich, um WskRegister innerhalb der DriverEntry-Funktion aufzurufen. Wenn eine WSK-Anwendung beispielsweise ein Teilkomponenten eines komplexen Treibers ist, kann die Registrierung der Anwendung nur erfolgen, wenn der Unterkomponenten der WSK-Anwendung aktiviert ist.

Eine WSK-Anwendung muss die anWskRegister übergebene WSK_CLIENT_DISPATCH Struktur gültig und im Arbeitsspeicher bleiben, bis WskDeregister aufgerufen wird und die Registrierung nicht mehr gültig ist. Die WSK_REGISTRATION-Struktur muss auch gültig und im Arbeitsspeicher gespeichert sein, bis die WSK-Anwendung keine Aufrufe der anderen WSK-Registrierungsfunktionen mehr durchführt. Im vorherigen Codebeispiel werden diese beiden Strukturen im globalen Datenabschnitt des Treibers beibehalten, wodurch die Strukturdaten im Arbeitsspeicher gespeichert bleiben, bis der Treiber entladen wird.

NPI-Erfassung des WSK-Anbieters

Nachdem eine WSK-Anwendung als WSK-Client bei WskRegister registriert wurde, muss sie die WskCaptureProviderNPI-Funktion verwenden, um die NPI des WSK-Anbieters aus dem WSK-Subsystem zu erfassen, um mit der Verwendung der WSK-Schnittstelle zu beginnen.

Da das WSK-Subsystem möglicherweise noch nicht bereit ist, wenn eine WSK-Anwendung versucht, die NPI des WSK-Anbieters zu erfassen, ermöglicht die WskCaptureProviderNPI-Funktion der WSK-Anwendung, wie folgt abzufragen oder zu warten, bis das WSK-Subsystem bereit ist:

  • Wenn der WaitTimeout-Parameter WSK_NO_WAIT ist, wird die Funktion immer sofort ohne Wartezeit zurückgegeben.

  • Wenn WaitTimeout WSK_INFINITE_WAIT ist, wartet die Funktion, bis das WSK-Subsystem bereit ist.

  • Wenn WaitTimeout ein anderer Wert ist, gibt die Funktion entweder zurück, wenn das WSK-Subsystem bereit wird oder wenn die Wartezeit in Millisekunden den Wert von WaitTimeout erreicht, je nachdem, was zuerst auftritt.

Wichtig Um den Start anderer Treiber und Dienste zu vermeiden, sollte eine WSK-Anwendung, die WskCaptureProviderNPI über die DriverEntry-Funktion aufruft, den WaitTimeout-Parameter nicht auf WSK_INFINITE_WAIT oder eine übermäßige Wartezeit festlegen. Wenn eine WSK-Anwendung sehr früh in der Systemstartphase gestartet wird, sollte sie auch warten, bis das WSK-Subsystem in einem anderen Workerthread als dem, in dem DriverEntry ausgeführt wird, bereit ist.

Wenn der Aufruf von WskCaptureProviderNPI mit STATUS_NOINTERFACE fehlschlägt, kann die WSK-Anwendung die WskQueryProviderCharacteristics-Funktion verwenden, um den Bereich der vom WSK-Subsystem unterstützten WSK-NPI-Versionen zu ermitteln. Die WSK-Anwendung kann WskDeregister aufrufen, um die Registrierung ihrer aktuellen instance aufzuheben, und dann mithilfe einer anderen WSK_CLIENT_DISPATCH instance, die eine unterstützte WSK-NPI-Version verwendet, erneut registrieren.

Wenn WskCaptureProviderNPI erfolgreich zurückgegeben wird, verweist der WskProviderNpi-Parameter auf eine WSK-Anbieter-NPI ( WSK_PROVIDER_NPI), die von der WSK-Anwendung verwendet werden kann. Die WSK_PROVIDER_NPI-Struktur enthält Zeiger auf das WSK-Clientobjekt ( WSK_CLIENT) und die WSK_PROVIDER_DISPATCH Verteilungstabelle der WSK-Funktionen, mit denen die WSK-Anwendung WSK-Sockets erstellen und andere Vorgänge für das WSK-Clientobjekt ausführen kann. Nachdem die WSK-Anwendung die WSK_PROVIDER_DISPATCH-Funktionen verwendet hat, muss sie die WSK-Anbieter-NPI freigeben, indem WskReleaseProviderNPI aufgerufen wird.

Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung den NPI des WSK-Anbieters erfassen, zum Erstellen eines Sockets verwenden und ihn dann freigeben kann.

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

}

Eine WSK-Anwendung kann WskCaptureProviderNPI mehrmals aufrufen. Für jeden erfolgreich zurückgegebenen Aufruf von WskCaptureProviderNPI muss ein entsprechender Aufruf von WskReleaseProviderNPI vorhanden sein. Eine WSK-Anwendung darf nach dem Aufruf von WskReleaseProviderNPI keine weiteren Aufrufe der Funktionen in WSK_PROVIDER_DISPATCH ausführen.