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.