Dela via


Använda IRP:er med Winsock-kärnfunktioner

Winsock Kernel (WSK) Network Programming Interface (NPI) använder IRP:er för asynkron slutförande av nätverks-I/O-operationer. Varje WSK-funktion tar en pekare till en IRP som parameter. WSK-undersystemet slutför IRP när åtgärden som utförs av WSK-funktionen har slutförts.

En IRP som ett WSK-program använder för att skicka till en WSK-funktion kan komma från något av följande sätt.

  • WSK-programmet allokerar IRP genom att anropa funktionen IoAllocateIrp. I det här fallet måste WSK-programmet allokera IRP med minst en I/O-stackplats.

  • WSK-programmet återanvänder en slutförd IRP som tidigare har tilldelats. I det här fallet måste WSK anropa funktionen IoReuseIrp för att initiera IRP igen.

  • WSK-programmet använder en IRP som skickades ned till den antingen av en drivrutin på högre nivå eller av I/O-chefen. I det här fallet måste IRP ha minst en återstående I/O-stackplats tillgänglig för användning av WSK-undersystemet.

När ett WSK-program har en IRP som ska användas för att anropa en WSK-funktion kan den ange en IoCompletion- rutin för att IRP ska anropas när IRP har slutförts av WSK-undersystemet. Ett WSK-program anger en IoCompletion- rutin för en IRP genom att anropa funktionen IoSetCompletionRoutine. Beroende på hur IRP kommer ifrån, krävs en IoCompletion- rutin, eller så är den frivillig.

  • Om WSK-programmet allokerade IRP eller återanvänder en IRP som det tidigare allokerade måste det ange en IoCompletion- rutin för IRP innan en WSK-funktion anropas. I den här situationen WSK-programmet måste ange TRUE- för InvokeOnSuccess, InvokeOnErroroch InvokeOnCancel parametrar som skickas till funktionen IoSetCompletionRoutine för att säkerställa att IoCompletion-rutinen alltid anropas. Dessutom måste den IoCompletion rutin som har angetts för IRP alltid returnera STATUS_MORE_PROCESSING_REQUIRED för att avsluta slutförandet av bearbetningen av IRP. Om WSK-programmet görs med hjälp av IRP efter att IoCompletion-rutinen har anropats, bör programmet anropa funktionen IoFreeIrp för att frigöra IRP innan man återvänder från IoCompletion-rutinen. Om WSK-programmet inte frigör IRP kan det återanvända IRP för ett anrop till en annan WSK-funktion.

  • Om WSK-programmet använder en IRP som överfördes till det av en drivrutin på högre nivå eller av I/O-hanteraren, bör det ange en IoCompletion- rutin för IRP innan WSK-funktionen anropas, endast om det behöver meddelas när åtgärden som utförs av WSK-funktionen har slutförts. Om WSK-programmet inte anger en IoCompletion- rutin för IRP, så skickas, när IRP har avslutats, IRP tillbaka till drivrutinen på högre nivå eller till I/O-chefen enligt normal IRP-slutförandebearbetning. Om WSK-programmet anger en IoCompletion- rutin för IRP kan rutinen IoCompletion antingen returnera STATUS_SUCCESS eller STATUS_MORE_PROCESSING_REQUIRED. Om IoCompletion- rutin returnerar STATUS_SUCCESS fortsätter IRP-slutförandebearbetningen normalt. Om IoCompletion- rutin returnerar STATUS_MORE_PROCESSING_REQUIRED måste WSK-programmet slutföra IRP:n genom att anropa IoCompleteRequest när den har slutfört bearbetningen av resultatet av åtgärden som utfördes av WSK-funktionen. Ett WSK-program bör aldrig frigöra en IRP som skickades till den av en drivrutin på högre nivå eller av I/O-hanteraren.

Obs Om WSK-programmet anger en IoCompletion- rutin för en IRP som skickades ned till den av en drivrutin på högre nivå eller av I/O-chefen, då IoCompletion rutin måste kontrollera PendingReturned medlem i IRP och anropa funktionen IoMarkIrpPending om PendingReturned medlem är TRUE. Mer information finns i Implementera en IoCompletion-rutin.

Note Ett WSK-program bör inte anropa nya WSK-funktioner i IoCompletion-rutinen. Detta kan leda till rekursiva anrop och uttömning av kernellägesstacken. När du kör på IRQL = DISPATCH_LEVEL kan detta också leda till svält av andra trådar.

En WSK-applikation initierar inte de IRP:er som den skickar till WSK-funktionerna, annat än att ställa in en IoCompletion-rutin. När ett WSK-program skickar en IRP till en WSK-funktion konfigurerar WSK-undersystemet nästa I/O-stackplats för programmets räkning.

Följande kodexempel visar hur ett WSK-program kan allokera och använda en IRP när du utför en mottagningsåtgärd på en socket.

// Prototype for the receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    );

// Function to receive data
NTSTATUS
  ReceiveData(
    PWSK_SOCKET Socket,
    PWSK_BUF DataBuffer
    )
{
  PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
  PIRP Irp;
  NTSTATUS Status;

  // Get pointer to the provider dispatch structure
  Dispatch =
    (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);

  // Allocate an IRP
  Irp =
    IoAllocateIrp(
      1,
      FALSE
      );

  // Check result
  if (!Irp)
  {
    // Return error
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Set the completion routine for the IRP
  IoSetCompletionRoutine(
    Irp,
    ReceiveComplete,
    DataBuffer,  // Use the data buffer for the context
    TRUE,
    TRUE,
    TRUE
    );

  // Initiate the receive operation on the socket
  Status =
    Dispatch->WskReceive(
      Socket,
      DataBuffer,
      0,  // No flags are specified
      Irp
      );

  // Return the status of the call to WskReceive()
  return Status;
}

// Receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    )
{
  UNREFERENCED_PARAMETER(DeviceObject);

  PWSK_BUF DataBuffer;
  ULONG ByteCount;

  // Check the result of the receive operation
  if (Irp->IoStatus.Status == STATUS_SUCCESS)
  {
    // Get the pointer to the data buffer
    DataBuffer = (PWSK_BUF)Context;
 
    // Get the number of bytes received
    ByteCount = (ULONG)(Irp->IoStatus.Information);

    // Process the received data
    ...
  }

  // Error status
  else
  {
    // Handle error
    ...
  }

  // Free the IRP
  IoFreeIrp(Irp);

  // Always return STATUS_MORE_PROCESSING_REQUIRED to
  // terminate the completion processing of the IRP.
  return STATUS_MORE_PROCESSING_REQUIRED;
}

Modellen som visas i föregående exempel, där WSK-programmet allokerar en IRP och sedan frigör den i slutföranderutinen, är den modell som används i exemplen i resten av WSK-dokumentationen.

Följande kodexempel visar hur ett WSK-program kan använda en IRP som har skickats till den av en drivrutin på högre nivå eller av I/O-chefen när en mottagningsåtgärd utförs på en socket.

// Prototype for the receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    );

// Function to receive data
NTSTATUS
  ReceiveData(
    PWSK_SOCKET Socket,
    PWSK_BUF DataBuffer,
    PIRP Irp;  // IRP from a higher level driver or the I/O manager
    )
{
  PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
  NTSTATUS Status;

  // Get pointer to the provider dispatch structure
  Dispatch =
    (PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);

  // Set the completion routine for the IRP such that it is
  // only called if the receive operation succeeds.
  IoSetCompletionRoutine(
    Irp,
    ReceiveComplete,
    DataBuffer,  // Use the data buffer for the context
    TRUE,
    FALSE,
    FALSE
    );

  // Initiate the receive operation on the socket
  Status =
    Dispatch->WskReceive(
      Socket,
      DataBuffer,
      0,  // No flags are specified
      Irp
      );

  // Return the status of the call to WskReceive()
  return Status;
}

// Receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    )
{
  UNREFERENCED_PARAMETER(DeviceObject);

  PWSK_BUF DataBuffer;
  ULONG ByteCount;

  // Since the completion routine was only specified to
  // be called if the operation succeeds, this should
  // always be true.
  ASSERT(Irp->IoStatus.Status == STATUS_SUCCESS);

  // Check the pending status of the IRP
  if (Irp->PendingReturned == TRUE)
  {
    // Mark the IRP as pending
    IoMarkIrpPending(Irp);
  }

  // Get the pointer to the data buffer
  DataBuffer = (PWSK_BUF)Context;
 
  // Get the number of bytes received
  ByteCount = (ULONG)(Irp->IoStatus.Information);

  // Process the received data
  ...

  // Return STATUS_SUCCESS to continue the
  // completion processing of the IRP.
  return STATUS_SUCCESS;
}

Mer information om hur du använder IRP:er finns i Hantera IRP:er.