イベント コールバック関数の有効化と無効化

Winsock カーネル (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;
}

リッスン ソケットの場合、WskInspectEvent イベントコールバック関数と WskAbortEvent イベント コールバック関数は、WSK アプリケーションがソケットで条件付き受け入れモードを有効にする場合にのみ有効です。 WSK アプリケーションでは、ソケットをローカル トランスポート アドレスにバインドする前にソケットの SO_CONDITIONAL_ACCEPT ソケット オプションを設定することで、リスニング ソケットで条件付き受け入れモードを有効にします。 ソケット オプションを設定する方法の詳細については、「ソケットでの制御操作の実行」を参照してください。

リッスン しているソケットで条件付き受け入れモードを有効にした後、ソケットの WskInspectEvent および WskAbortEvent イベント コールバック関数を無効にすることはできません。 リッスンしているソケットで受信接続を条件付きで受け入れる方法の詳細は、「受信接続のリッスンと受け入れ」を参照してください。

リッスン ソケットは、リッスン ソケットの WskAcceptEvent イベント コールバック関数によって受け入れるコネクション指向ソケットでイベント コールバック関数を自動的に有効にすることができます。 WSK アプリケーションは、リッスン しているソケットでコネクション指向ソケット イベント コールバック関数を有効にすることで、これらのコールバック関数を自動的に有効にします。 このプロセスの詳細は、SO_WSK_EVENT_CALLBACKを参照してください。

WSK アプリケーションが作成するすべてのソケットで特定のイベント コールバック関数を常時有効にする場合、アプリケーションは、WSK_Standard Edition T_STATIC_EVENT_CALLBACKS クライアント制御操作を使用して、WSKサブシステムを構成し、それらのイベント コールバック関数を自動的に有効にすることができます。。 この方法で有効にされているイベント コールバック関数は常に有効であり、後で WSK アプリケーションによって無効にしたり再度有効にしたりすることはできません。 WSK アプリケーションが、作成するすべてのソケットで特定のイベント コールバック関数を常に有効にする場合、アプリケーションはこの方法を使用してこれらのイベント コールバック関数を自動的に有効にする必要があります。それによりパフォーマンスが大幅に向上するためです。

次のコード例は、WSK アプリケーションが WSK_Standard Edition T_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_Standard Edition T_STATIC_EVENT_CALLBACKS クライアント制御操作を使用して特定のイベント コールバック関数を自動的に有効にする場合は、ソケットを作成する前に、これを行ってください。