Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die Netzwerkprogrammierschnittstelle (NPI) des Winsock-Kernels (WSK) verwendet IRPs zum asynchronen Abschluss von Netzwerk-E/A-Vorgängen. Jede WSK-Funktion verwendet einen Zeiger auf einen IRP als Parameter. Das WSK-Subsystem schließt das IRP ab, nachdem der von der WSK-Funktion ausgeführte Vorgang abgeschlossen ist.
Ein IRP, das von einer WSK-Anwendung zum Übergeben an eine WSK-Funktion verwendet wird, kann auf eine der folgenden Arten stammen.
Die WSK-Anwendung ordnet das IRP zu, indem die IoAllocateIrp-Funktion aufgerufen wird . In diesem Fall muss die WSK-Anwendung den IRP mit mindestens einem E/A-Stapelspeicherort zuordnen.
Die WSK-Anwendung verwendet einen abgeschlossenen IRP wieder, den sie zuvor zugewiesen hat. In diesem Fall muss der WSK die IoReuseIrp-Funktion aufrufen, um das IRP erneut zu initialisieren.
Die WSK-Anwendung verwendet einen IRP, der entweder von einem Treiber auf höherer Ebene oder vom E/A-Manager an sie übergeben wurde. In diesem Fall muss das IRP über mindestens einen verbleibenden E/A-Stapelspeicherort verfügen, der vom WSK-Subsystem verwendet werden kann.
Nachdem eine WSK-Anwendung über ein IRP verfügt, das zum Aufrufen einer WSK-Funktion verwendet werden soll, kann sie eine IoCompletion-Routine für die IRP festlegen, die aufgerufen wird, wenn das IRP vom WSK-Subsystem abgeschlossen wird. Eine WSK-Anwendung legt eine IoCompletion-Routine für ein IRP fest, indem die IoSetCompletionRoutine-Funktion aufgerufen wird. Je nachdem, wie das IRP entstanden ist, ist eine IoCompletion-Routine entweder erforderlich oder optional.
Wenn die WSK-Anwendung den IRP zugewiesen hat oder eine zuvor zugewiesene IRP wiederverwendet, muss sie vor dem Aufrufen einer WSK-Funktion eine IoCompletion-Routine für das IRP festlegen. In diesem Fall muss die WSK-Anwendung TRUE für die Parameter InvokeOnSuccess, InvokeOnError und InvokeOnCancel angeben, die an die IoSetCompletionRoutine-Funktion übergeben werden, um sicherzustellen, dass die IoCompletion-Routine immer aufgerufen wird. Darüber hinaus muss die für das IRP festgelegte IoCompletion-Routine immer STATUS_MORE_PROCESSING_REQUIRED zurückgeben, um die Abschlussverarbeitung des IRP zu beenden. Wenn die WSK-Anwendung das IRP verwendet, nachdem die IoCompletion-Routine aufgerufen wurde, sollte sie die IoFreeIrp-Funktion aufrufen, um die IRP freizugeben, bevor sie von der IoCompletion-Routine zurückkehrt. Wenn die WSK-Anwendung den IRP nicht freigibt, kann sie das IRP für einen Aufruf einer anderen WSK-Funktion wiederverwenden.
Wenn die WSK-Anwendung einen IRP verwendet, der von einem Treiber auf höherer Ebene oder vom E/A-Manager an sie übergeben wurde, sollte sie vor dem Aufrufen der WSK-Funktion nur dann eine IoCompletion-Routine für das IRP festlegen, wenn sie benachrichtigt werden muss, wenn der von der WSK-Funktion ausgeführte Vorgang abgeschlossen ist. Wenn die WSK-Anwendung keine IoCompletion-Routine für das IRP festsetzt, wird die IRP nach Abschluss des IRP wieder an den Treiber der höheren Ebene oder an den E/A-Manager gemäß der normalen IRP-Abschlussverarbeitung übergeben. Wenn die WSK-Anwendung eine IoCompletion-Routine für das IRP festlegt, kann die IoCompletion-Routine entweder STATUS_SUCCESS oder STATUS_MORE_PROCESSING_REQUIRED zurückgeben. Wenn die IoCompletion-Routine STATUS_SUCCESS zurückgibt, wird die IRP-Abschlussverarbeitung normal fortgesetzt. Wenn die IoCompletion-Routine STATUS_MORE_PROCESSING_REQUIRED zurückgibt, muss die WSK-Anwendung das IRP abschließen, indem sie IoCompleteRequest aufruft , nachdem sie die Verarbeitung der Ergebnisse des Vorgangs abgeschlossen hat, der von der WSK-Funktion ausgeführt wurde. Eine WSK-Anwendung sollte niemals einen IRP freigeben, der von einem Treiber höherer Ebene oder vom E/A-Manager an sie übergeben wurde.
Hinweis Wenn die WSK-Anwendung eine IoCompletion-Routine für ein IRP festlegt, das von einem Treiber auf höherer Ebene oder vom E/A-Manager an sie übergeben wurde, muss die IoCompletion-Routine den PendingReturned-Member des IRP überprüfen und die IoMarkIrpPending-Funktion aufrufen, wenn der PendingReturned-MemberTRUE ist. Weitere Informationen finden Sie unter Implementieren einer IoCompletion-Routine.
Hinweis Eine WSK-Anwendung sollte keine neuen WSK-Funktionen im Kontext der IoCompletion-Routine aufrufen. Dies kann zu rekursiven Aufrufen führen und den Kernelmodusstapel erschöpfen. Bei der Ausführung unter IRQL = DISPATCH_LEVEL kann dies auch zum Verhungern anderer Threads führen.
Eine WSK-Anwendung initialisiert nicht die IRPs, die sie an die WSK-Funktionen übergibt, außer dem Festlegen einer IoCompletion-Routine . Wenn eine WSK-Anwendung ein IRP an eine WSK-Funktion übergibt, richtet das WSK-Subsystem den nächsten E/A-Stapelspeicherort im Namen der Anwendung ein.
Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung ein IRP zuordnen und verwenden kann, wenn ein Empfangsvorgang für einen Socket ausgeführt wird.
// 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;
}
Das im vorherigen Beispiel gezeigte Modell, bei dem die WSK-Anwendung einen IRP zuordnet und ihn dann in der Vervollständigungsroutine freigibt, ist das Modell, das in den Beispielen im rest der WSK-Dokumentation verwendet wird.
Das folgende Codebeispiel zeigt, wie eine WSK-Anwendung ein IRP verwenden kann, das von einem Treiber auf höherer Ebene oder vom E/A-Manager an sie übergeben wurde, wenn ein Empfangsvorgang für einen Socket ausgeführt wird.
// 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;
}
Weitere Informationen zur Verwendung von IRPs finden Sie unter Behandeln von IRPs.