啟用和停用事件回呼函式
Winsock Kernel (WSK) 應用程式可以實作 WSK 子系統非同步呼叫的事件回呼函式,以在通訊端發生特定 事件 時通知應用程式。 每當 WSK 應用程式建立通訊端或接受接聽通訊端上的通訊端時,就可以將用戶端 分派資料表 結構提供給 WSK 子系統。 此分派資料表包含新通訊端之 WSK 應用程式事件回呼函式的指標。 如果 WSK 應用程式未針對特定通訊端實作任何事件回呼函式,則不需要為該通訊端的 WSK 子系統提供用戶端分派資料表結構。
除了接聽通訊端的 WskInspectEvent 和 WskAbortEvent 事件回呼函式之外,所有通訊端的事件回呼函式都可以使用 SO_WSK_EVENT_CALLBACK 通訊端選項來啟用或停用。 WSK 應用程式可以同時在通訊端上啟用多個事件回呼函式。 不過,WSK 應用程式必須個別停用每個事件回呼函式。
下列程式碼範例示範 WSK 應用程式如何使用 SO_WSK_EVENT_CALLBACK 通訊端選項,在連線導向通訊端上啟用 WskDisconnectEvent 和 WskReceiveEvent 事件回呼函式。
// Function to enable the WskDisconnectEvent and WskReceiveEvent
// event callback functions on a connection-oriented socket
NTSTATUS
EnableDisconnectAndRecieveCallbacks(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be enabled on the socket
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_RECEIVE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return the status of the call to WskControlSocket()
return Status;
}
下列程式碼範例示範 WSK 應用程式如何使用 SO_WSK_EVENT_CALLBACK 通訊端選項來停用連線導向通訊端上的 WskReceiveEvent 事件回呼函式。
// Prototype for the disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// Function to disable the WskDisconnectEvent event
// callback functions on a connection-oriented socket
NTSTATUS
DisableDisconnectCallback(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
PIRP Irp;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's 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,
DisableDisconnectComplete,
Socket, // Use the socket object for the context
TRUE,
TRUE,
TRUE
);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flag for the event callback function that
// is to be disabled on the socket along with the disable flag
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_DISABLE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
Irp
);
// Return the status of the call to WskControlSocket()
return Status;
}
// Disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_SOCKET Socket;
// Check the result of the control operation
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// The WskDisconnectEvent event callback
// function is now disabled
// Get the socket object from the context
Socket = (PWSK_SOCKET)Context;
// Perform the next operation on the socket
...
}
// 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;
}
針對接聽通訊端,只有在 WSK 應用程式在通訊端上啟用條件式接受模式時,才會啟用 WskInspectEvent 和 WskAbortEvent 事件回呼函式。 WSK 應用程式可在接聽通訊端上啟用條件式接受模式,方法是在將通訊端系結至本機傳輸位址之前,先設定通訊端 的 SO_CONDITIONAL_ACCEPT 通訊端選項。 如需如何設定通訊端選項的詳細資訊,請參閱 在通訊端上執行控制作業。
在接聽通訊端上啟用條件式接受模式之後,就無法停用通訊端的 WskInspectEvent 和 WskAbortEvent 事件回呼函式。 如需在接聽通訊端上有條件地接受連入連線的詳細資訊,請參閱 接聽和接受連入連線。
接聽通訊端可以在接聽通訊端的 WskAcceptEvent 事件回呼函式所接受的連接導向通訊端上自動啟用事件回呼函式。 WSK 應用程式會在接聽通訊端上啟用連線導向通訊端事件回呼函式,自動啟用這些回呼函式。 如需此程式的詳細資訊,請參閱 SO_WSK_EVENT_CALLBACK。
如果 WSK 應用程式一律會在它建立的每個通訊端上啟用特定事件回呼函式,應用程式可以使用用戶端控制作業,將 WSK 子系統設定為使用 WSK_SET_STATIC_EVENT_CALLBACKS 用戶端控制作業自動啟用這些事件回呼函式。 以這種方式啟用的事件回呼函式一律會啟用,且稍後 WSK 應用程式無法停用或重新啟用。 如果 WSK 應用程式一律會在所建立的每個通訊端上啟用特定事件回呼函式,應用程式應該使用此方法自動啟用這些事件回呼函式,因為它會產生更好的效能。
下列程式碼範例示範 WSK 應用程式如何使用WSK_SET_STATIC_EVENT_CALLBACKS用戶端控制作業,在資料包通訊端上自動啟用 WskReceiveFromEvent 事件回呼函式,以及連接導向通訊端上的 WskReceiveEvent 事件回呼函式。
// Function to set static event callbacks
NTSTATUS
SetStaticEventCallbacks(
PWSK_APP_BINDING_CONTEXT BindingContext,
)
{
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be automatically enabled on every new socket
EventCallbackControl.EventMask =
WSK_EVENT_RECEIVE_FROM | WSK_EVENT_RECEIVE;
// Perform client control operation
Status =
BindingContext->
WskProviderDispatch->
WskControlClient(
BindingContext->WskClient,
WSK_SET_STATIC_EVENT_CALLBACKS,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return status of client control operation
return Status;
}
如果 WSK 應用程式使用WSK_SET_STATIC_EVENT_CALLBACKS用戶端控制作業來自動啟用特定事件回呼函式,它必須先執行此動作,才能建立任何通訊端。