Win32 API 日本語リファレンス
ホームNetworking.WinSock › WSAAsyncSelect

WSAAsyncSelect

関数
ソケットのネットワークイベント通知をウィンドウメッセージで要求する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 2000 以降

シグネチャ

// WS2_32.dll
#include <windows.h>

INT WSAAsyncSelect(
    SOCKET s,
    HWND hWnd,
    DWORD wMsg,
    INT lEvent
);

パラメーター

名前方向説明
sSOCKETinイベント通知を必要とするソケットを識別する記述子。
hWndHWNDinネットワークイベントが発生したときにメッセージを受信するウィンドウを識別するハンドル。
wMsgDWORDinネットワークイベントが発生したときに受信するメッセージ。
lEventINTinアプリケーションが関心を持つネットワークイベントの組み合わせを指定するビットマスク。

戻り値の型: INT

公式ドキュメント

WSAAsyncSelect 関数 (winsock.h) は、ソケットに対するネットワークイベントを Windows メッセージベースで通知するよう要求します。

戻り値

WSAAsyncSelect 関数が成功し、ネットワークイベントセットへの関心の宣言が成功した場合、戻り値は 0 です。それ以外の場合は SOCKET_ERROR が返され、 WSAGetLastError を呼び出すことで特定のエラー番号を取得できます。

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSAENETDOWN
ネットワークサブシステムが失敗しました。
WSAEINVAL
指定されたパラメーターのいずれかが無効でした。たとえば、ウィンドウハンドルが既存のウィンドウを参照していない、または指定されたソケットが無効な状態にある場合などです。
WSAEINPROGRESS
ブロッキング動作の Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数を処理中です。
WSAENOTSOCK
記述子がソケットではありません。

アプリケーションウィンドウがメッセージを受信したときに、追加のエラーコードが設定される場合があります。このエラーコードは、WSAGETSELECTERROR マクロを使用して応答メッセージの lParam から抽出されます。各ネットワークイベントで発生しうるエラーコードを次の表に示します。

イベント: FD_CONNECT

エラーコード 意味
WSAEAFNOSUPPORT 指定されたファミリのアドレスは、このソケットでは使用できません。
WSAECONNREFUSED 接続の試行が拒否されました。
WSAENETUNREACH 現時点で、このホストからネットワークに到達できません。
WSAEFAULT namelen パラメーターが無効です。
WSAEINVAL ソケットは既にアドレスにバインドされています。
WSAEISCONN ソケットは既に接続されています。
WSAEMFILE 使用可能なファイル記述子がこれ以上ありません。
WSAENOBUFS 使用可能なバッファー領域がありません。ソケットを接続できません。
WSAENOTCONN ソケットが接続されていません。
WSAETIMEDOUT 接続を確立できずに接続の試行がタイムアウトしました。

イベント: FD_CLOSE

エラーコード 意味
WSAENETDOWN ネットワークサブシステムが失敗しました。
WSAECONNRESET 接続がリモート側によってリセットされました。
WSAECONNABORTED タイムアウトまたはその他の障害により接続が終了しました。
エラーコード 意味
WSAENETDOWN ネットワークサブシステムが失敗しました。

イベント: FD_ROUTING_INTERFACE_CHANGE

エラーコード 意味
WSAENETUNREACH 指定された宛先に到達できなくなりました。
WSAENETDOWN ネットワークサブシステムが失敗しました。

解説(Remarks)

WSAAsyncSelect 関数は、lEvent パラメーターで指定されたネットワークイベントを WS2_32.DLL が検出したときに、ウィンドウ hWnd にメッセージを送信するよう要求するために使用されます。送信すべきメッセージは wMsg パラメーターで指定します。通知が必要なソケットは s パラメーターで識別します。

WSAAsyncSelect 関数は、lEvent の値にかかわらず、ソケット s を自動的に非ブロッキングモードに設定します。ソケット s をブロッキングモードに戻すには、まず lEvent を 0 に設定して WSAAsyncSelect を呼び出し、ソケット s に関連付けられたイベントレコードをクリアする必要があります。その後、ioctlsocket または WSAIoctl を呼び出して、ソケットをブロッキングモードに戻すことができます。非ブロッキングソケットをブロッキングモードに戻す方法の詳細については、ioctlsocket 関数と WSAIoctl 関数を参照してください。

lEvent パラメーターは、次の表に示す値のいずれかをビットごとの OR 演算子で組み合わせて構成します。

意味
FD_READ 読み取り準備完了の通知を受信するために設定します。
FD_WRITE 書き込み準備完了の通知を受信します。
FD_OOB OOB データの到着の通知を受信します。
FD_ACCEPT 着信接続の通知を受信します。
FD_CONNECT 接続またはマルチポイント結合操作の完了の通知を受信します。
FD_CLOSE ソケットのクローズの通知を受信します。
FD_QOS ソケットの Quality of Service (QoS) の変更の通知を受信します。
FD_GROUP_QOS ソケットグループの Quality of Service (QoS) の変更の通知を受信します (ソケットグループでの将来の使用のために予約)。予約済み。
FD_ROUTING_INTERFACE_CHANGE 指定された宛先に対するルーティングインターフェイスの変更の通知を受信します。
FD_ADDRESS_LIST_CHANGE ソケットのプロトコルファミリのローカルアドレスリストの変更の通知を受信します。

ソケットに対して WSAAsyncSelect を発行すると、同じソケットに対する以前の WSAAsyncSelect または WSAEventSelect がキャンセルされます。たとえば、読み取りと書き込みの両方の通知を受け取るには、アプリケーションは次のように FD_READFD_WRITE の両方を指定して WSAAsyncSelect を呼び出す必要があります。

rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);

イベントごとに異なるメッセージを指定することはできません。次のコードは機能しません。2 番目の呼び出しが 1 番目の呼び出しの効果をキャンセルし、メッセージ wMsg2 で報告されるのは FD_WRITE イベントのみとなります。

rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);

すべての通知をキャンセルし、ソケット上のネットワークイベントに関連するメッセージを Windows Sockets がこれ以上送信しないようにするには、lEvent を 0 に設定します。

rc = WSAAsyncSelect(s, hWnd, 0, 0);

この場合、WSAAsyncSelect はソケットに対するイベントメッセージの投稿を即座に無効にしますが、メッセージがアプリケーションのメッセージキュー内で待機している可能性があります。したがって、アプリケーションはキャンセル後であってもネットワークイベントメッセージを受信できるよう準備しておく必要があります。 closesocket でソケットをクローズすると、 WSAAsyncSelect によるメッセージ送信もキャンセルされますが、キュー内のメッセージに関する同じ注意事項が引き続き当てはまります。

accept 関数によって作成されたソケットは、それを受け入れるために使用されたリスニングソケットと同じプロパティを持ちます。その結果、リスニングソケットに設定された WSAAsyncSelect イベントは、受け入れられたソケットにも適用されます。たとえば、リスニングソケットに WSAAsyncSelect イベント FD_ACCEPTFD_READFD_WRITE が設定されている場合、そのリスニングソケットで受け入れられたソケットも、メッセージに使用される同じ wMsg 値で FD_ACCEPTFD_READFD_WRITE イベントを持ちます。異なる wMsg やイベントが必要な場合、アプリケーションは受け入れられたソケットと希望する新しいデータを渡して WSAAsyncSelect を呼び出す必要があります。

指定されたソケット s 上で、指定されたネットワークイベントのいずれかが発生すると、アプリケーションウィンドウ hWnd はメッセージ wMsg を受信します。wParam パラメーターは、ネットワークイベントが発生したソケットを識別します。lParam の下位ワードは発生したネットワークイベントを指定します。lParam の上位ワードにはエラーコードが含まれます。エラーコードは Winsock2.h で定義された任意のエラーになりえます。

注意 イベント通知メッセージを受信した際、 WSAGetLastError 関数を使用してエラー値を確認することはできません。返されるエラー値が lParam の上位ワードの値と異なる場合があるためです。
エラーコードとイベントコードは、Winsock2.h で次のように定義されているマクロ WSAGETSELECTERRORWSAGETSELECTEVENT を使用して lParam から抽出できます。
#include <windows.h>

#define WSAGETSELECTEVENT(lParam)       LOWORD(lParam)
#define WSAGETSELECTERROR(lParam)       HIWORD(lParam)

これらのマクロを使用することで、アプリケーションのソースコードの移植性が最大限に高まります。

返される可能性のあるネットワークイベントコードを次の表に示します。

意味
FD_READ ソケット s が読み取り準備完了です。
FD_WRITE ソケット s が書き込み準備完了です。
FD_OOB ソケット s で OOB データの読み取り準備が完了しました。
FD_ACCEPT ソケット s が新しい着信接続を受け入れる準備が完了しました。
FD_CONNECT ソケット s 上で開始された接続またはマルチポイント join 操作が完了しました。
FD_CLOSE ソケット s で識別される接続がクローズされました。
FD_QOS ソケット s に関連付けられた Quality of Service が変更されました。
FD_GROUP_QOS 予約済み。s が属するソケットグループに関連付けられた Quality of Service が変更されました (ソケットグループでの将来の使用のために予約)。
FD_ROUTING_INTERFACE_CHANGE 指定された宛先への送信に使用すべきローカルインターフェイスが変更されました。
FD_ADDRESS_LIST_CHANGE アプリケーションクライアントがバインドできるソケットプロトコルファミリのアドレスリストが変更されました。

WSAAsyncSelect は複数のイベントへの関心を指定して呼び出すことができますが、アプリケーションウィンドウはネットワークイベントごとに 1 つのメッセージを受信します。

select 関数の場合と同様に、 WSAAsyncSelect は、データ転送操作 (send または recv) を即座に成功する見込みで発行できるタイミングを判断するために頻繁に使用されます。とはいえ、堅牢なアプリケーションは、メッセージを受信して Windows Sockets 2 の呼び出しを発行したときに、即座に WSAEWOULDBLOCK が返される可能性に備える必要があります。たとえば、次の一連のイベントが起こりえます。

  1. ソケット s にデータが到着し、Windows Sockets 2 が WSAAsyncSelect メッセージを投稿します。
  2. アプリケーションが別のメッセージを処理します。
  3. 処理中に、アプリケーションが ioctlsocket(s, FIONREAD...) を発行し、読み取り可能なデータがあることを認識します。
  4. アプリケーションが recv(s,...) を発行してデータを読み取ります。
  5. アプリケーションがループして次のメッセージを処理し、最終的にデータの読み取り準備が完了したことを示す WSAAsyncSelect メッセージに到達します。
  6. アプリケーションが recv(s,...) を発行しますが、エラー WSAEWOULDBLOCK で失敗します。
その他の順序も起こりえます。

WS2_32.DLL は、特定のネットワークイベントに対するメッセージでアプリケーションを継続的に氾濫させることはありません。特定のイベントの通知をアプリケーションウィンドウに正常に投稿した後は、アプリケーションがそのネットワークイベントの通知を暗黙的に再有効化する関数呼び出しを行うまで、そのネットワークイベントに対するそれ以上のメッセージはアプリケーションウィンドウに投稿されません。

イベント 再有効化する関数
FD_READ recvrecvfromWSARecv、または WSARecvFrom
FD_WRITE sendsendtoWSASend、または WSASendTo
FD_OOB recvrecvfromWSARecv、または WSARecvFrom
FD_ACCEPT accept または WSAAccept。ただし、エラーコードが WSATRY_AGAIN であり、条件関数が CF_DEFER を返したことを示している場合を除きます。
FD_CONNECT なし。
FD_CLOSE なし。
FD_QOS コマンド SIO_GET_QOS を指定した WSAIoctl
FD_GROUP_QOS 予約済み。 コマンド SIO_GET_GROUP_QOS を指定した WSAIoctl (ソケットグループでの将来の使用のために予約)。
FD_ROUTING_INTERFACE_CHANGE コマンド SIO_ROUTING_INTERFACE_CHANGE を指定した WSAIoctl
FD_ADDRESS_LIST_CHANGE コマンド SIO_ADDRESS_LIST_CHANGE を指定した WSAIoctl

再有効化ルーチンへの呼び出しは、たとえ失敗した呼び出しであっても、該当するイベントに対するメッセージ投稿の再有効化につながります。

FD_READFD_OOBFD_ACCEPT イベントの場合、メッセージ投稿はレベルトリガーです。これは、再有効化ルーチンが呼び出され、その呼び出し後も該当する条件が依然として満たされている場合に、 WSAAsyncSelect メッセージがアプリケーションに投稿されることを意味します。これにより、アプリケーションはイベント駆動型となり、一度に到着するデータ量を気にする必要がなくなります。次の順序を考えてみます。

  1. ネットワークトランスポートスタックがソケット s 上で 100 バイトのデータを受信し、Windows Sockets 2 に FD_READ メッセージを投稿させます。
  2. アプリケーションが recv( s, buffptr, 50, 0) を発行して 50 バイトを読み取ります。
  3. 読み取るべきデータがまだ残っているため、別の FD_READ メッセージが投稿されます。
このセマンティクスにより、アプリケーションは FD_READ メッセージに応答して利用可能なすべてのデータを読み取る必要はなく、各 FD_READ メッセージに応答して 1 回の recv を行うのが適切です。アプリケーションが 1 つの FD_READ に応答して複数の recv 呼び出しを発行すると、複数の FD_READ メッセージを受信する可能性があります。そのようなアプリケーションでは、recv 呼び出しを開始する前に、FD_READ イベントを設定せずに WSAAsyncSelect を呼び出して FD_READ メッセージを無効にすることが必要になる場合があります。

FD_QOS および FD_GROUP_QOS イベントはエッジトリガーと見なされます。Quality of Service の変更が発生したとき、メッセージは正確に 1 回だけ投稿されます。プロバイダーが Quality of Service のさらなる変更を検出するか、アプリケーションがソケットの Quality of Service を再交渉するまで、それ以上のメッセージは送信されません。

FD_ROUTING_INTERFACE_CHANGE メッセージは、SIO_ROUTING_INTERFACE_CHANGE を指定した WSAIoctl で指定された宛先に到達するために使用すべきローカルインターフェイスが、その IOCTL の発行後に変更されたときに投稿されます。

FD_ADDRESS_LIST_CHANGE メッセージは、SIO_ADDRESS_LIST_CHANGE を指定した WSAIoctl の発行後に、アプリケーションがバインドできるアドレスのリストが変更されたときに投稿されます。

アプリケーションが WSAAsyncSelect を呼び出したとき、または再有効化関数が呼び出されたときに何らかのイベントが発生していた場合、必要に応じてメッセージが投稿されます。たとえば、次の順序を考えてみます。

  1. アプリケーションが listen を呼び出します。
  2. 接続要求を受信しますが、まだ受け入れられていません。
  3. アプリケーションが、そのソケットに対して FD_ACCEPT メッセージの受信を必要とすることを指定して WSAAsyncSelect を呼び出します。イベントの永続性により、Windows Sockets 2 は即座に FD_ACCEPT メッセージを投稿します。

FD_WRITE イベントの扱いは少し異なります。FD_WRITE メッセージは、ソケットが connect または WSAConnect で最初に接続されたとき (FD_CONNECT も登録されている場合はその後)、あるいは accept または WSAAccept で受け入れられたとき、そしてその後、送信操作が WSAEWOULDBLOCK で失敗してからバッファー領域が利用可能になったときに投稿されます。したがって、アプリケーションは、最初の FD_WRITE メッセージから、送信が WSAEWOULDBLOCK を返すまでの間、送信が可能であると想定できます。そのような失敗の後、アプリケーションは FD_WRITE メッセージによって再び送信が可能になったことを通知されます。

FD_OOB イベントは、ソケットが OOB データを個別に受信するよう構成されている場合にのみ使用されます。ソケットが OOB データをインラインで受信するよう構成されている場合、OOB (緊急) データは通常のデータとして扱われ、アプリケーションは FD_OOB イベントではなく FD_READ イベントに関心を登録し、それを受信します。アプリケーションは、SO_OOBINLINE オプションに対して setsockopt または getsockopt を使用することで、OOB データの処理方法を設定または検査できます。

FD_CLOSE メッセージのエラーコードは、ソケットのクローズが正常 (graceful) であったか異常 (abortive) であったかを示します。エラーコードが 0 の場合、クローズは正常でした。エラーコードが WSAECONNRESET の場合、ソケットの仮想回線がリセットされました。これは、SOCK_STREAM などのコネクション指向ソケットにのみ適用されます。

FD_CLOSE メッセージは、ソケットに対応する仮想回線のクローズ通知を受信したときに投稿されます。TCP の用語では、これは接続が TIME WAIT 状態または CLOSE WAIT 状態に移行したときに FD_CLOSE が投稿されることを意味します。これは、リモート側が送信側で shutdown を実行したか、 closesocket を実行した結果として発生します。FD_CLOSE は、ソケットからすべてのデータが読み取られた後にのみ投稿されるべきですが、データ損失の可能性を回避するため、アプリケーションは FD_CLOSE を受信した際に残りのデータがないかを確認する必要があります。

アプリケーションが仮想回線のクローズを示す FD_CLOSE メッセージを受信するのは、正常なクローズの場合は受信したすべてのデータが読み取られたときのみであることに注意してください。この状態を示す FD_READ メッセージは受信されません。

FD_QOS または FD_GROUP_QOS メッセージは、それぞれソケット s に関連付けられたフロー仕様、または s が属するソケットグループのフロー仕様内のいずれかのパラメーターが変更されたときに投稿されます。アプリケーションは、ソケット s または s が属するソケットグループの現在の Quality of Service を取得するために、それぞれコマンド SIO_GET_QOS または SIO_GET_GROUP_QOS を指定した WSAIoctl を使用する必要があります。

FD_ROUTING_INTERFACE_CHANGE および FD_ADDRESS_LIST_CHANGE イベントもエッジトリガーと見なされます。アプリケーションが SIO_ROUTING_INTERFACE_CHANGE または SIO_ADDRESS_LIST_CHANGE を指定した WSAIoctl を発行して通知を要求した後、変更が発生したとき、メッセージは正確に 1 回だけ投稿されます。アプリケーションが IOCTL を再発行し、その IOCTL が発行されたために別の変更が検出されるまで、それ以上のメッセージは送信されません。

各非同期通知メッセージのイベントと条件の概要を次に示します。

出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// WS2_32.dll
#include <windows.h>

INT WSAAsyncSelect(
    SOCKET s,
    HWND hWnd,
    DWORD wMsg,
    INT lEvent
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern int WSAAsyncSelect(
    UIntPtr s,   // SOCKET
    IntPtr hWnd,   // HWND
    uint wMsg,   // DWORD
    int lEvent   // INT
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function WSAAsyncSelect(
    s As UIntPtr,   ' SOCKET
    hWnd As IntPtr,   ' HWND
    wMsg As UInteger,   ' DWORD
    lEvent As Integer   ' INT
) As Integer
End Function
' s : SOCKET
' hWnd : HWND
' wMsg : DWORD
' lEvent : INT
Declare PtrSafe Function WSAAsyncSelect Lib "ws2_32" ( _
    ByVal s As LongPtr, _
    ByVal hWnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal lEvent As Long) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

WSAAsyncSelect = ctypes.windll.ws2_32.WSAAsyncSelect
WSAAsyncSelect.restype = ctypes.c_int
WSAAsyncSelect.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
    wintypes.HANDLE,  # hWnd : HWND
    wintypes.DWORD,  # wMsg : DWORD
    ctypes.c_int,  # lEvent : INT
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('WS2_32.dll')
WSAAsyncSelect = Fiddle::Function.new(
  lib['WSAAsyncSelect'],
  [
    Fiddle::TYPE_UINTPTR_T,  # s : SOCKET
    Fiddle::TYPE_VOIDP,  # hWnd : HWND
    -Fiddle::TYPE_INT,  # wMsg : DWORD
    Fiddle::TYPE_INT,  # lEvent : INT
  ],
  Fiddle::TYPE_INT)
#[link(name = "ws2_32")]
extern "system" {
    fn WSAAsyncSelect(
        s: usize,  // SOCKET
        hWnd: *mut core::ffi::c_void,  // HWND
        wMsg: u32,  // DWORD
        lEvent: i32  // INT
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("WS2_32.dll", SetLastError = true)]
public static extern int WSAAsyncSelect(UIntPtr s, IntPtr hWnd, uint wMsg, int lEvent);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_WSAAsyncSelect' -Namespace Win32 -PassThru
# $api::WSAAsyncSelect(s, hWnd, wMsg, lEvent)
#uselib "WS2_32.dll"
#func global WSAAsyncSelect "WSAAsyncSelect" sptr, sptr, sptr, sptr
; WSAAsyncSelect s, hWnd, wMsg, lEvent   ; 戻り値は stat
; s : SOCKET -> "sptr"
; hWnd : HWND -> "sptr"
; wMsg : DWORD -> "sptr"
; lEvent : INT -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
#uselib "WS2_32.dll"
#cfunc global WSAAsyncSelect "WSAAsyncSelect" sptr, sptr, int, int
; res = WSAAsyncSelect(s, hWnd, wMsg, lEvent)
; s : SOCKET -> "sptr"
; hWnd : HWND -> "sptr"
; wMsg : DWORD -> "int"
; lEvent : INT -> "int"
; INT WSAAsyncSelect(SOCKET s, HWND hWnd, DWORD wMsg, INT lEvent)
#uselib "WS2_32.dll"
#cfunc global WSAAsyncSelect "WSAAsyncSelect" intptr, intptr, int, int
; res = WSAAsyncSelect(s, hWnd, wMsg, lEvent)
; s : SOCKET -> "intptr"
; hWnd : HWND -> "intptr"
; wMsg : DWORD -> "int"
; lEvent : INT -> "int"
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procWSAAsyncSelect = ws2_32.NewProc("WSAAsyncSelect")
)

// s (SOCKET), hWnd (HWND), wMsg (DWORD), lEvent (INT)
r1, _, err := procWSAAsyncSelect.Call(
	uintptr(s),
	uintptr(hWnd),
	uintptr(wMsg),
	uintptr(lEvent),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function WSAAsyncSelect(
  s: NativeUInt;   // SOCKET
  hWnd: THandle;   // HWND
  wMsg: DWORD;   // DWORD
  lEvent: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSAAsyncSelect';
result := DllCall("WS2_32\WSAAsyncSelect"
    , "UPtr", s   ; SOCKET
    , "Ptr", hWnd   ; HWND
    , "UInt", wMsg   ; DWORD
    , "Int", lEvent   ; INT
    , "Int")   ; return: INT
●WSAAsyncSelect(s, hWnd, wMsg, lEvent) = DLL("WS2_32.dll", "int WSAAsyncSelect(int, void*, dword, int)")
# 呼び出し: WSAAsyncSelect(s, hWnd, wMsg, lEvent)
# s : SOCKET -> "int"
# hWnd : HWND -> "void*"
# wMsg : DWORD -> "dword"
# lEvent : INT -> "int"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "ws2_32" fn WSAAsyncSelect(
    s: usize, // SOCKET
    hWnd: ?*anyopaque, // HWND
    wMsg: u32, // DWORD
    lEvent: i32 // INT
) callconv(std.os.windows.WINAPI) i32;
proc WSAAsyncSelect(
    s: uint,  # SOCKET
    hWnd: pointer,  # HWND
    wMsg: uint32,  # DWORD
    lEvent: int32  # INT
): int32 {.importc: "WSAAsyncSelect", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int WSAAsyncSelect(
    size_t s,   // SOCKET
    void* hWnd,   // HWND
    uint wMsg,   // DWORD
    int lEvent   // INT
);
ccall((:WSAAsyncSelect, "WS2_32.dll"), stdcall, Int32,
      (Csize_t, Ptr{Cvoid}, UInt32, Int32),
      s, hWnd, wMsg, lEvent)
# s : SOCKET -> Csize_t
# hWnd : HWND -> Ptr{Cvoid}
# wMsg : DWORD -> UInt32
# lEvent : INT -> Int32
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
int32_t WSAAsyncSelect(
    uintptr_t s,
    void* hWnd,
    uint32_t wMsg,
    int32_t lEvent);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.WSAAsyncSelect(s, hWnd, wMsg, lEvent)
-- s : SOCKET
-- hWnd : HWND
-- wMsg : DWORD
-- lEvent : INT
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('WS2_32.dll');
const WSAAsyncSelect = lib.func('__stdcall', 'WSAAsyncSelect', 'int32_t', ['uintptr_t', 'void *', 'uint32_t', 'int32_t']);
// WSAAsyncSelect(s, hWnd, wMsg, lEvent)
// s : SOCKET -> 'uintptr_t'
// hWnd : HWND -> 'void *'
// wMsg : DWORD -> 'uint32_t'
// lEvent : INT -> 'int32_t'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("WS2_32.dll", {
  WSAAsyncSelect: { parameters: ["usize", "pointer", "u32", "i32"], result: "i32" },
});
// lib.symbols.WSAAsyncSelect(s, hWnd, wMsg, lEvent)
// s : SOCKET -> "usize"
// hWnd : HWND -> "pointer"
// wMsg : DWORD -> "u32"
// lEvent : INT -> "i32"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
int32_t WSAAsyncSelect(
    size_t s,
    void* hWnd,
    uint32_t wMsg,
    int32_t lEvent);
C, "WS2_32.dll");
// $ffi->WSAAsyncSelect(s, hWnd, wMsg, lEvent);
// s : SOCKET
// hWnd : HWND
// wMsg : DWORD
// lEvent : INT
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Ws2_32 extends StdCallLibrary {
    Ws2_32 INSTANCE = Native.load("ws2_32", Ws2_32.class);
    int WSAAsyncSelect(
        long s,   // SOCKET
        Pointer hWnd,   // HWND
        int wMsg,   // DWORD
        int lEvent   // INT
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun WSAAsyncSelect = WSAAsyncSelect(
    s : LibC::SizeT,   # SOCKET
    hWnd : Void*,   # HWND
    wMsg : UInt32,   # DWORD
    lEvent : Int32   # INT
  ) : Int32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef WSAAsyncSelectNative = Int32 Function(UintPtr, Pointer<Void>, Uint32, Int32);
typedef WSAAsyncSelectDart = int Function(int, Pointer<Void>, int, int);
final WSAAsyncSelect = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<WSAAsyncSelectNative, WSAAsyncSelectDart>('WSAAsyncSelect');
// s : SOCKET -> UintPtr
// hWnd : HWND -> Pointer<Void>
// wMsg : DWORD -> Uint32
// lEvent : INT -> Int32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function WSAAsyncSelect(
  s: NativeUInt;   // SOCKET
  hWnd: THandle;   // HWND
  wMsg: DWORD;   // DWORD
  lEvent: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSAAsyncSelect';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "WSAAsyncSelect"
  c_WSAAsyncSelect :: CUIntPtr -> Ptr () -> Word32 -> Int32 -> IO Int32
-- s : SOCKET -> CUIntPtr
-- hWnd : HWND -> Ptr ()
-- wMsg : DWORD -> Word32
-- lEvent : INT -> Int32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let wsaasyncselect =
  foreign "WSAAsyncSelect"
    (size_t @-> (ptr void) @-> uint32_t @-> int32_t @-> returning int32_t)
(* s : SOCKET -> size_t *)
(* hWnd : HWND -> (ptr void) *)
(* wMsg : DWORD -> uint32_t *)
(* lEvent : INT -> int32_t *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library ws2_32 (t "WS2_32.dll"))
(cffi:use-foreign-library ws2_32)

(cffi:defcfun ("WSAAsyncSelect" wsaasync-select :convention :stdcall) :int32
  (s :uint64)   ; SOCKET
  (h-wnd :pointer)   ; HWND
  (w-msg :uint32)   ; DWORD
  (l-event :int32))   ; INT
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $WSAAsyncSelect = Win32::API::More->new('WS2_32',
    'int WSAAsyncSelect(WPARAM s, HANDLE hWnd, DWORD wMsg, int lEvent)');
# my $ret = $WSAAsyncSelect->Call($s, $hWnd, $wMsg, $lEvent);
# s : SOCKET -> WPARAM
# hWnd : HWND -> HANDLE
# wMsg : DWORD -> DWORD
# lEvent : INT -> int
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

公式の関連項目