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

WSASendMsg

関数
メッセージ構造体を用いてデータを送信する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

INT WSASendMsg(
    SOCKET Handle,
    WSAMSG* lpMsg,
    DWORD dwFlags,
    DWORD* lpNumberOfBytesSent,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine   // optional
);

パラメーター

名前方向説明
HandleSOCKETinsocket を識別するディスクリプタです。
lpMsgWSAMSG*inPosix.1g の msghdr 構造体を格納する WSAMSG 構造体です。
dwFlagsDWORDinWSASendMsg 関数呼び出しの動作を変更するために使用するフラグです。詳細については、「解説」セクションの「dwFlags の使用」を参照してください。
lpNumberOfBytesSentDWORD*outoptional

I/O 操作が即座に完了した場合に、この呼び出しで送信されたバイト数へのポインタです。

lpOverlapped パラメータが NULL でない場合は、誤った結果を避けるためこのパラメータに NULL を使用してください。このパラメータを NULL にできるのは、lpOverlapped パラメータが NULL でない場合のみです。

lpOverlappedOVERLAPPED*inoutoptionalWSAOVERLAPPED 構造体へのポインタです。非オーバーラップソケットでは無視されます。
lpCompletionRoutineLPWSAOVERLAPPED_COMPLETION_ROUTINEinoptional送信操作が完了したときに呼び出される完了ルーチンへのポインタです。非オーバーラップソケットでは無視されます。

戻り値の型: INT

公式ドキュメント

接続済みおよび未接続の socket からデータと任意の制御情報を送信します。メモ この関数は Windows ソケット仕様に対する Microsoft 固有の拡張です。

戻り値

成功して即座に完了した場合はゼロを返します。ゼロが返された場合、呼び出しスレッドがアラータブル状態にあるときに、指定された完了ルーチンが呼び出されます。

戻り値が SOCKET_ERROR で、その後の WSAGetLastError の呼び出しが WSA_IO_PENDING を返す場合は、オーバーラップ操作が正常に開始されたことを示します。完了はイベントや完了ポートなどの他の手段によって通知されます。

失敗した場合は SOCKET_ERROR を返し、その後の WSAGetLastError の呼び出しは WSA_IO_PENDING 以外の値を返します。次の表にエラーコードを示します。

エラーコード 意味
WSAEACCES
要求されたアドレスがブロードキャストアドレスですが、適切なフラグが設定されていませんでした。
WSAECONNRESET
UDP データグラムソケットの場合、このエラーは以前の送信操作が ICMP の "Port Unreachable" メッセージを引き起こしたことを示します。
WSAEFAULT
lpMsglpNumberOfBytesSentlpOverlapped、または lpCompletionRoutine パラメータが、ユーザーアドレス空間の有効な部分に完全には含まれていません。このエラーは、lpMsg パラメータが指す WSAMSG 構造体の name メンバーが NULL ポインタであり、WSAMSG 構造体の namelen メンバーがゼロに設定されていなかった場合にも返されます。また、lpMsg パラメータが指す WSAMSG 構造体の Control.buf メンバーが NULL ポインタであり、WSAMSG 構造体の Control.len メンバーがゼロに設定されていなかった場合にも返されます。
WSAEINPROGRESS
ブロッキングする Windows ソケット 1.1 の呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理中です。
WSAEINTR
ブロッキングする Windows ソケット 1.1 の呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEINVAL
socket が bind でバインドされていないか、socket がオーバーラップフラグ付きで作成されていません。
WSAEMSGSIZE
socket はメッセージ指向であり、メッセージが基盤となるトランスポートがサポートする最大値より大きくなっています。
WSAENETDOWN
ネットワークサブシステムに障害が発生しました。
WSAENETRESET
データグラムソケットの場合、このエラーは生存時間(TTL)が期限切れになったことを示します。
WSAENETUNREACH
ネットワークに到達できません。
WSAENOBUFS
Windows ソケットプロバイダーがバッファのデッドロックを報告しました。
WSAENOTCONN
socket が接続されていません。
WSAENOTSOCK
ディスクリプタが socket ではありません。
WSAEOPNOTSUPP
socket 操作がサポートされていません。このエラーは、lpMsg パラメータが指す WSAMSG 構造体の dwFlags メンバーに、WSASendMsg に対して無効な制御フラグが含まれている場合に返されます。
WSAESHUTDOWN
socket がシャットダウンされています。howSD_SEND または SD_BOTH に設定して shutdown を呼び出した後の socket に対して、WSASendMsg 関数を呼び出すことはできません。
WSAETIMEDOUT
socket がタイムアウトしました。このエラーは、socket に SO_SNDTIMEO ソケットオプションを使用して待機タイムアウトが指定されており、そのタイムアウトを超過した場合に返されます。
WSAEWOULDBLOCK
オーバーラップソケット: 未処理のオーバーラップ I/O 要求が多すぎます。非オーバーラップソケット: socket が非ブロッキングとしてマークされており、送信操作を即座に完了できません。
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSA_IO_PENDING
オーバーラップ操作が正常に開始され、完了は後で通知されます。
WSA_OPERATION_ABORTED
socket のクローズ、または WSAIoctl での SIO_FLUSH コマンドの実行により、オーバーラップ操作がキャンセルされました。

解説(Remarks)

WSASendMsg 関数は、WSASend 関数および WSASendTo 関数の代わりに使用できます。WSASendMsg 関数は、データグラムソケットおよび raw ソケットでのみ使用できます。s パラメータの socket ディスクリプタは、ソケットタイプを SOCK_DGRAM または SOCK_RAW に設定して開く必要があります。

dwFlags パラメータには、次の制御フラグの組み合わせのみを含めることができます: MSG_DONTROUTEMSG_PARTIALMSG_OOBlpMsg パラメータが指す WSAMSG 構造体の dwFlags メンバーは、入力時には無視され、出力時には使用されません。

メモ WSASendMsg 関数の関数ポインタは、SIO_GET_EXTENSION_FUNCTION_POINTER オペコードを指定して WSAIoctl 関数を呼び出すことにより、実行時に取得する必要があります。WSAIoctl 関数に渡す入力バッファには、WSASendMsg 拡張関数を識別する値を持つグローバル一意識別子(GUID)である WSAID_WSASENDMSG を含める必要があります。成功すると、WSAIoctl 関数が返す出力に WSASendMsg 関数へのポインタが含まれます。WSAID_WSASENDMSG GUID は Mswsock.h ヘッダーファイルで定義されています。

オーバーラップソケットは、WSA_FLAG_OVERLAPPED フラグを設定した WSASocket 関数の呼び出しで作成されます。オーバーラップソケットでは、lpOverlappedlpCompletionRoutine の両方が NULL でない限り、情報の送信にオーバーラップ I/O が使用されます。lpOverlappedlpCompletionRoutine がともに NULL の場合、socket は非オーバーラップソケットとして扱われます。オーバーラップソケットでは完了通知が行われ、バッファがトランスポートによって消費されると、完了ルーチンがトリガーされるか、イベントオブジェクトが設定されます。操作が即座に完了しない場合、最終的な完了ステータスは完了ルーチンを通じて、または WSAGetOverlappedResult 関数を呼び出すことで取得されます。

非オーバーラップソケットでは、lpOverlapped パラメータと lpCompletionRoutine パラメータは無視され、WSASendMsgsend 関数と同じブロッキングセマンティクスを採用します。つまり、データがバッファからトランスポートのバッファへコピーされます。socket が非ブロッキングかつストリーム指向で、トランスポートのバッファに十分な空きがない場合、WSASendMsg はアプリケーションのバッファの一部のみが消費された状態で戻ります。これに対し、ブロッキングソケットでこのバッファ状況が発生した場合、WSASendMsg はアプリケーションのバッファ内容がすべて消費されるまでブロックします。

この関数がオーバーラップ方式で完了する場合、この呼び出しから戻る前にこの WSABUF 構造体をキャプチャするのは Winsock サービスプロバイダーの責任です。これにより、アプリケーションは lpMsg パラメータが指す WSAMSG 構造体の lpBuffers メンバーが指す、スタックベースの WSABUF 配列を構築できます。

メッセージ指向のソケットでは、基盤となるプロバイダーの最大メッセージサイズを超えないように注意する必要があります。この値は、ソケットオプション SO_MAX_MSG_SIZE の値を取得することで得られます。データが長すぎて基盤となるプロトコルを通じてアトミックに渡せない場合、エラー WSAEMSGSIZE が返され、データは送信されません。

SOCK_DGRAM 型または SOCK_RAW 型の IPv4 ソケットでは、アプリケーションは WSASendMsg 関数で送信に使用するローカル IP 送信元アドレスを指定できます。WSASendMsg 関数の WSAMSG 構造体で渡される制御データオブジェクトの 1 つに、送信に使用するローカル IPv4 送信元アドレスを指定する in_pktinfo 構造体を含めることができます。

SOCK_DGRAM 型または SOCK_RAW 型の IPv6 ソケットでは、アプリケーションは WSASendMsg 関数で送信に使用するローカル IP 送信元アドレスを指定できます。WSASendMsg 関数の WSAMSG 構造体で渡される制御データオブジェクトの 1 つに、送信に使用するローカル IPv6 送信元アドレスを指定する in6_pktinfo 構造体を含めることができます。

デュアルスタックソケットで WSASendMsg 関数を使用してデータグラムを送信する際、アプリケーションが使用する特定のローカル IP 送信元アドレスを指定したい場合、その処理方法は宛先 IP アドレスによって異なります。IPv4 宛先アドレスまたは IPv4 マップ IPv6 宛先アドレスへ送信する場合、lpMsg パラメータが指す WSAMSG 構造体で渡される制御データオブジェクトの 1 つに、送信に使用するローカル IPv4 送信元アドレスを含む in_pktinfo 構造体を含める必要があります。IPv4 マップ IPv6 アドレスではない IPv6 宛先アドレスへ送信する場合、lpMsg パラメータが指す WSAMSG 構造体で渡される制御データオブジェクトの 1 つに、送信に使用するローカル IPv6 送信元アドレスを含む in6_pktinfo 構造体を含める必要があります。

メモ SO_SNDTIMEO ソケットオプションは、ブロッキングソケットにのみ適用されます。
メモ WSASendMsg が正常に完了しても、データが正常に配信されたことを示すわけではありません。
メモ lpOverlapped パラメータを NULL に設定して WSASendMsg のようなブロッキングする Winsock 呼び出しを発行する場合、Winsock は呼び出しが完了する前にネットワークイベントを待つ必要が生じることがあります。この状況では Winsock はアラータブルな待機を実行し、同じスレッドでスケジュールされた非同期プロシージャ呼び出し(APC)によって中断される可能性があります。同じスレッドで進行中のブロッキングする Winsock 呼び出しを中断した APC 内で、別のブロッキングする Winsock 呼び出しを発行すると、未定義の動作を引き起こすため、Winsock クライアントは決してこれを試みてはなりません。

dwFlags

dwFlags 入力パラメータを使用すると、関連する socket に指定されたオプションを超えて、関数呼び出しの動作に影響を与えることができます。つまり、この関数のセマンティクスは、ソケットオプションと dwFlags パラメータによって決まります。後者は、次の値のいずれかとビット単位の OR 演算子を使用して構築します。
意味
MSG_DONTROUTE データをルーティングの対象にしないことを指定します。Windows ソケットサービスプロバイダーは、このフラグを無視することを選択できます。
MSG_PARTIAL lpMsg->lpBuffers がメッセージの一部のみを含むことを指定します。部分的なメッセージ送信をサポートしないトランスポートでは、エラーコード WSAEOPNOTSUPP が返されることに注意してください。

dwFlags パラメータに指定可能な値は、Winsock2.h ヘッダーファイルで定義されています。

出力時には、lpMsg パラメータが指す WSAMSG 構造体の dwFlags メンバーは使用されません。

オーバーラップソケット I/O

オーバーラップ操作が即座に完了する場合、 WSASendMsg はゼロを返し、lpNumberOfBytesSent パラメータが送信されたバイト数で更新されます。オーバーラップ操作が正常に開始され、後で完了する場合、 WSASendMsgSOCKET_ERROR を返し、エラーコード WSA_IO_PENDING を示します。この場合、lpNumberOfBytesSent は更新されません。オーバーラップ操作が完了すると、転送されたデータ量は、(指定されている場合は)完了ルーチンの cbTransferred パラメータを通じて、または WSAGetOverlappedResultlpcbTransfer パラメータを通じて通知されます。
メモ 特定のスレッドによって開始されたすべての I/O は、そのスレッドが終了するとキャンセルされます。オーバーラップソケットの場合、操作が完了する前にスレッドが終了すると、保留中の非同期操作が失敗する可能性があります。詳細については ExitThread を参照してください。

オーバーラップ I/O を使用する WSASendMsg 関数は、以前の WSARecvWSARecvFromLPFN_WSARECVMSG (WSARecvMsg)WSASendWSASendMsg、または WSASendTo 関数の完了ルーチン内から呼び出すことができます。これにより、時間に敏感なデータ送信を、完全にプリエンプティブなコンテキスト内で行うことができます。

lpOverlapped パラメータは、オーバーラップ操作が継続している間、有効でなければなりません。複数の I/O 操作が同時に未処理の場合、それぞれが別個の WSAOVERLAPPED 構造体を参照する必要があります。

lpCompletionRoutine パラメータが NULL の場合、lpOverlappedhEvent パラメータが有効なイベントオブジェクトハンドルを含んでいれば、オーバーラップ操作が完了したときにシグナル状態になります。アプリケーションは WSAWaitForMultipleEvents または WSAGetOverlappedResult を使用して、イベントオブジェクトを待機またはポーリングできます。

lpCompletionRoutineNULL でない場合、hEvent パラメータは無視され、アプリケーションが完了ルーチンにコンテキスト情報を渡すために使用できます。NULL でない lpCompletionRoutine を渡し、後で同じオーバーラップ I/O 要求に対して WSAGetOverlappedResult を呼び出す呼び出し元は、その WSAGetOverlappedResult の呼び出しに対して fWait パラメータを TRUE に設定してはなりません。この場合、hEvent パラメータの用途は未定義であり、hEvent パラメータでの待機を試みると予測できない結果を生じます。

完了ルーチンは、Windows ファイル I/O 完了ルーチンに規定されているのと同じ規則に従います。完了ルーチンは、たとえば fAlertable パラメータを TRUE に設定して呼び出した WSAWaitForMultipleEvents などにより、スレッドがアラータブルな待機状態になるまで呼び出されません。

トランスポートプロバイダーは、アプリケーションが socket I/O 完了ルーチンのコンテキスト内から送信および受信操作を呼び出すことを許可し、特定の socket について I/O 完了ルーチンがネストされないことを保証します。これにより、時間に敏感なデータ送信を、完全にプリエンプティブなコンテキスト内で行うことができます。

完了ルーチンのプロトタイプは次のとおりです。


void CALLBACK CompletionRoutine(
  IN DWORD dwError,
  IN DWORD cbTransferred,
  IN LPWSAOVERLAPPED lpOverlapped,
  IN DWORD dwFlags
);

CompletionRoutine 関数は、アプリケーション定義またはライブラリ定義の関数名のプレースホルダーです。dwError パラメータは、lpOverlapped パラメータで示されるオーバーラップ操作の完了ステータスを指定します。cbTransferred パラメータは送信されたバイト数を示します。現在のところ定義されているフラグ値はなく、dwFlags パラメータはゼロになります。CompletionRoutine 関数は値を返しません。

この関数から戻ると、socket に対する別の保留中の完了ルーチンの呼び出しが許可されます。待機中のすべての完了ルーチンは、アラータブルなスレッドの待機が戻りコード WSA_IO_COMPLETION で満たされる前に呼び出されます。完了ルーチンは任意の順序で呼び出される可能性があり、必ずしもオーバーラップ操作が完了したのと同じ順序とは限りません。ただし、ポストされたバッファは、指定されたのと同じ順序で送信されることが保証されます。

Windows 8.1 および Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2、およびそれ以降の Windows ストアアプリでサポートされています。

出典・ライセンス: 上記「公式ドキュメント」の内容は 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 WSASendMsg(
    SOCKET Handle,
    WSAMSG* lpMsg,
    DWORD dwFlags,
    DWORD* lpNumberOfBytesSent,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine   // optional
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern int WSASendMsg(
    UIntPtr Handle,   // SOCKET
    IntPtr lpMsg,   // WSAMSG*
    uint dwFlags,   // DWORD
    IntPtr lpNumberOfBytesSent,   // DWORD* optional, out
    IntPtr lpOverlapped,   // OVERLAPPED* optional, in/out
    IntPtr lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function WSASendMsg(
    Handle As UIntPtr,   ' SOCKET
    lpMsg As IntPtr,   ' WSAMSG*
    dwFlags As UInteger,   ' DWORD
    lpNumberOfBytesSent As IntPtr,   ' DWORD* optional, out
    lpOverlapped As IntPtr,   ' OVERLAPPED* optional, in/out
    lpCompletionRoutine As IntPtr   ' LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
) As Integer
End Function
' Handle : SOCKET
' lpMsg : WSAMSG*
' dwFlags : DWORD
' lpNumberOfBytesSent : DWORD* optional, out
' lpOverlapped : OVERLAPPED* optional, in/out
' lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
Declare PtrSafe Function WSASendMsg Lib "ws2_32" ( _
    ByVal Handle As LongPtr, _
    ByVal lpMsg As LongPtr, _
    ByVal dwFlags As Long, _
    ByVal lpNumberOfBytesSent As LongPtr, _
    ByVal lpOverlapped As LongPtr, _
    ByVal lpCompletionRoutine As LongPtr) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

WSASendMsg = ctypes.windll.ws2_32.WSASendMsg
WSASendMsg.restype = ctypes.c_int
WSASendMsg.argtypes = [
    ctypes.c_size_t,  # Handle : SOCKET
    ctypes.c_void_p,  # lpMsg : WSAMSG*
    wintypes.DWORD,  # dwFlags : DWORD
    ctypes.POINTER(wintypes.DWORD),  # lpNumberOfBytesSent : DWORD* optional, out
    ctypes.c_void_p,  # lpOverlapped : OVERLAPPED* optional, in/out
    ctypes.c_void_p,  # lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('WS2_32.dll')
WSASendMsg = Fiddle::Function.new(
  lib['WSASendMsg'],
  [
    Fiddle::TYPE_UINTPTR_T,  # Handle : SOCKET
    Fiddle::TYPE_VOIDP,  # lpMsg : WSAMSG*
    -Fiddle::TYPE_INT,  # dwFlags : DWORD
    Fiddle::TYPE_VOIDP,  # lpNumberOfBytesSent : DWORD* optional, out
    Fiddle::TYPE_VOIDP,  # lpOverlapped : OVERLAPPED* optional, in/out
    Fiddle::TYPE_VOIDP,  # lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
  ],
  Fiddle::TYPE_INT)
#[link(name = "ws2_32")]
extern "system" {
    fn WSASendMsg(
        Handle: usize,  // SOCKET
        lpMsg: *mut WSAMSG,  // WSAMSG*
        dwFlags: u32,  // DWORD
        lpNumberOfBytesSent: *mut u32,  // DWORD* optional, out
        lpOverlapped: *mut OVERLAPPED,  // OVERLAPPED* optional, in/out
        lpCompletionRoutine: *const core::ffi::c_void  // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("WS2_32.dll", SetLastError = true)]
public static extern int WSASendMsg(UIntPtr Handle, IntPtr lpMsg, uint dwFlags, IntPtr lpNumberOfBytesSent, IntPtr lpOverlapped, IntPtr lpCompletionRoutine);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_WSASendMsg' -Namespace Win32 -PassThru
# $api::WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
#uselib "WS2_32.dll"
#func global WSASendMsg "WSASendMsg" sptr, sptr, sptr, sptr, sptr, sptr
; WSASendMsg Handle, varptr(lpMsg), dwFlags, varptr(lpNumberOfBytesSent), varptr(lpOverlapped), lpCompletionRoutine   ; 戻り値は stat
; Handle : SOCKET -> "sptr"
; lpMsg : WSAMSG* -> "sptr"
; dwFlags : DWORD -> "sptr"
; lpNumberOfBytesSent : DWORD* optional, out -> "sptr"
; lpOverlapped : OVERLAPPED* optional, in/out -> "sptr"
; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "WS2_32.dll"
#cfunc global WSASendMsg "WSASendMsg" sptr, var, int, var, var, sptr
; res = WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
; Handle : SOCKET -> "sptr"
; lpMsg : WSAMSG* -> "var"
; dwFlags : DWORD -> "int"
; lpNumberOfBytesSent : DWORD* optional, out -> "var"
; lpOverlapped : OVERLAPPED* optional, in/out -> "var"
; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "sptr"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; INT WSASendMsg(SOCKET Handle, WSAMSG* lpMsg, DWORD dwFlags, DWORD* lpNumberOfBytesSent, OVERLAPPED* lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
#uselib "WS2_32.dll"
#cfunc global WSASendMsg "WSASendMsg" intptr, var, int, var, var, intptr
; res = WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
; Handle : SOCKET -> "intptr"
; lpMsg : WSAMSG* -> "var"
; dwFlags : DWORD -> "int"
; lpNumberOfBytesSent : DWORD* optional, out -> "var"
; lpOverlapped : OVERLAPPED* optional, in/out -> "var"
; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "intptr"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procWSASendMsg = ws2_32.NewProc("WSASendMsg")
)

// Handle (SOCKET), lpMsg (WSAMSG*), dwFlags (DWORD), lpNumberOfBytesSent (DWORD* optional, out), lpOverlapped (OVERLAPPED* optional, in/out), lpCompletionRoutine (LPWSAOVERLAPPED_COMPLETION_ROUTINE optional)
r1, _, err := procWSASendMsg.Call(
	uintptr(Handle),
	uintptr(lpMsg),
	uintptr(dwFlags),
	uintptr(lpNumberOfBytesSent),
	uintptr(lpOverlapped),
	uintptr(lpCompletionRoutine),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function WSASendMsg(
  Handle: NativeUInt;   // SOCKET
  lpMsg: Pointer;   // WSAMSG*
  dwFlags: DWORD;   // DWORD
  lpNumberOfBytesSent: Pointer;   // DWORD* optional, out
  lpOverlapped: Pointer;   // OVERLAPPED* optional, in/out
  lpCompletionRoutine: Pointer   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSASendMsg';
result := DllCall("WS2_32\WSASendMsg"
    , "UPtr", Handle   ; SOCKET
    , "Ptr", lpMsg   ; WSAMSG*
    , "UInt", dwFlags   ; DWORD
    , "Ptr", lpNumberOfBytesSent   ; DWORD* optional, out
    , "Ptr", lpOverlapped   ; OVERLAPPED* optional, in/out
    , "Ptr", lpCompletionRoutine   ; LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
    , "Int")   ; return: INT
●WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine) = DLL("WS2_32.dll", "int WSASendMsg(int, void*, dword, void*, void*, void*)")
# 呼び出し: WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
# Handle : SOCKET -> "int"
# lpMsg : WSAMSG* -> "void*"
# dwFlags : DWORD -> "dword"
# lpNumberOfBytesSent : DWORD* optional, out -> "void*"
# lpOverlapped : OVERLAPPED* optional, in/out -> "void*"
# lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "ws2_32" fn WSASendMsg(
    Handle: usize, // SOCKET
    lpMsg: [*c]WSAMSG, // WSAMSG*
    dwFlags: u32, // DWORD
    lpNumberOfBytesSent: [*c]u32, // DWORD* optional, out
    lpOverlapped: [*c]OVERLAPPED, // OVERLAPPED* optional, in/out
    lpCompletionRoutine: ?*anyopaque // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
) callconv(std.os.windows.WINAPI) i32;
proc WSASendMsg(
    Handle: uint,  # SOCKET
    lpMsg: ptr WSAMSG,  # WSAMSG*
    dwFlags: uint32,  # DWORD
    lpNumberOfBytesSent: ptr uint32,  # DWORD* optional, out
    lpOverlapped: ptr OVERLAPPED,  # OVERLAPPED* optional, in/out
    lpCompletionRoutine: pointer  # LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): int32 {.importc: "WSASendMsg", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int WSASendMsg(
    size_t Handle,   // SOCKET
    WSAMSG* lpMsg,   // WSAMSG*
    uint dwFlags,   // DWORD
    uint* lpNumberOfBytesSent,   // DWORD* optional, out
    OVERLAPPED* lpOverlapped,   // OVERLAPPED* optional, in/out
    void* lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
);
ccall((:WSASendMsg, "WS2_32.dll"), stdcall, Int32,
      (Csize_t, Ptr{WSAMSG}, UInt32, Ptr{UInt32}, Ptr{OVERLAPPED}, Ptr{Cvoid}),
      Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
# Handle : SOCKET -> Csize_t
# lpMsg : WSAMSG* -> Ptr{WSAMSG}
# dwFlags : DWORD -> UInt32
# lpNumberOfBytesSent : DWORD* optional, out -> Ptr{UInt32}
# lpOverlapped : OVERLAPPED* optional, in/out -> Ptr{OVERLAPPED}
# lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> Ptr{Cvoid}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
int32_t WSASendMsg(
    uintptr_t Handle,
    void* lpMsg,
    uint32_t dwFlags,
    uint32_t* lpNumberOfBytesSent,
    void* lpOverlapped,
    void* lpCompletionRoutine);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
-- Handle : SOCKET
-- lpMsg : WSAMSG*
-- dwFlags : DWORD
-- lpNumberOfBytesSent : DWORD* optional, out
-- lpOverlapped : OVERLAPPED* optional, in/out
-- lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('WS2_32.dll');
const WSASendMsg = lib.func('__stdcall', 'WSASendMsg', 'int32_t', ['uintptr_t', 'void *', 'uint32_t', 'uint32_t *', 'void *', 'void *']);
// WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
// Handle : SOCKET -> 'uintptr_t'
// lpMsg : WSAMSG* -> 'void *'
// dwFlags : DWORD -> 'uint32_t'
// lpNumberOfBytesSent : DWORD* optional, out -> 'uint32_t *'
// lpOverlapped : OVERLAPPED* optional, in/out -> 'void *'
// lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
// コールバック(関数ポインタ)は koffi.proto/koffi.register で型を定義して渡す(素の void* では JS 関数を渡せない)。
const lib = Deno.dlopen("WS2_32.dll", {
  WSASendMsg: { parameters: ["usize", "pointer", "u32", "pointer", "pointer", "pointer"], result: "i32" },
});
// lib.symbols.WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine)
// Handle : SOCKET -> "usize"
// lpMsg : WSAMSG* -> "pointer"
// dwFlags : DWORD -> "u32"
// lpNumberOfBytesSent : DWORD* optional, out -> "pointer"
// lpOverlapped : OVERLAPPED* optional, in/out -> "pointer"
// lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "pointer"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
int32_t WSASendMsg(
    size_t Handle,
    void* lpMsg,
    uint32_t dwFlags,
    uint32_t* lpNumberOfBytesSent,
    void* lpOverlapped,
    void* lpCompletionRoutine);
C, "WS2_32.dll");
// $ffi->WSASendMsg(Handle, lpMsg, dwFlags, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine);
// Handle : SOCKET
// lpMsg : WSAMSG*
// dwFlags : DWORD
// lpNumberOfBytesSent : DWORD* optional, out
// lpOverlapped : OVERLAPPED* optional, in/out
// lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
// 構造体/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 WSASendMsg(
        long Handle,   // SOCKET
        Pointer lpMsg,   // WSAMSG*
        int dwFlags,   // DWORD
        IntByReference lpNumberOfBytesSent,   // DWORD* optional, out
        Pointer lpOverlapped,   // OVERLAPPED* optional, in/out
        Callback lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun WSASendMsg = WSASendMsg(
    Handle : LibC::SizeT,   # SOCKET
    lpMsg : WSAMSG*,   # WSAMSG*
    dwFlags : UInt32,   # DWORD
    lpNumberOfBytesSent : UInt32*,   # DWORD* optional, out
    lpOverlapped : OVERLAPPED*,   # OVERLAPPED* optional, in/out
    lpCompletionRoutine : Void*   # LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
  ) : Int32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef WSASendMsgNative = Int32 Function(UintPtr, Pointer<Void>, Uint32, Pointer<Uint32>, Pointer<Void>, Pointer<Void>);
typedef WSASendMsgDart = int Function(int, Pointer<Void>, int, Pointer<Uint32>, Pointer<Void>, Pointer<Void>);
final WSASendMsg = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<WSASendMsgNative, WSASendMsgDart>('WSASendMsg');
// Handle : SOCKET -> UintPtr
// lpMsg : WSAMSG* -> Pointer<Void>
// dwFlags : DWORD -> Uint32
// lpNumberOfBytesSent : DWORD* optional, out -> Pointer<Uint32>
// lpOverlapped : OVERLAPPED* optional, in/out -> Pointer<Void>
// lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function WSASendMsg(
  Handle: NativeUInt;   // SOCKET
  lpMsg: Pointer;   // WSAMSG*
  dwFlags: DWORD;   // DWORD
  lpNumberOfBytesSent: Pointer;   // DWORD* optional, out
  lpOverlapped: Pointer;   // OVERLAPPED* optional, in/out
  lpCompletionRoutine: Pointer   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSASendMsg';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "WSASendMsg"
  c_WSASendMsg :: CUIntPtr -> Ptr () -> Word32 -> Ptr Word32 -> Ptr () -> Ptr () -> IO Int32
-- Handle : SOCKET -> CUIntPtr
-- lpMsg : WSAMSG* -> Ptr ()
-- dwFlags : DWORD -> Word32
-- lpNumberOfBytesSent : DWORD* optional, out -> Ptr Word32
-- lpOverlapped : OVERLAPPED* optional, in/out -> Ptr ()
-- lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let wsasendmsg =
  foreign "WSASendMsg"
    (size_t @-> (ptr void) @-> uint32_t @-> (ptr uint32_t) @-> (ptr void) @-> (ptr void) @-> returning int32_t)
(* Handle : SOCKET -> size_t *)
(* lpMsg : WSAMSG* -> (ptr void) *)
(* dwFlags : DWORD -> uint32_t *)
(* lpNumberOfBytesSent : DWORD* optional, out -> (ptr uint32_t) *)
(* lpOverlapped : OVERLAPPED* optional, in/out -> (ptr void) *)
(* lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> (ptr void) *)
(* 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 ("WSASendMsg" wsasend-msg :convention :stdcall) :int32
  (handle :uint64)   ; SOCKET
  (lp-msg :pointer)   ; WSAMSG*
  (dw-flags :uint32)   ; DWORD
  (lp-number-of-bytes-sent :pointer)   ; DWORD* optional, out
  (lp-overlapped :pointer)   ; OVERLAPPED* optional, in/out
  (lp-completion-routine :pointer))   ; LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $WSASendMsg = Win32::API::More->new('WS2_32',
    'int WSASendMsg(WPARAM Handle, LPVOID lpMsg, DWORD dwFlags, LPVOID lpNumberOfBytesSent, LPVOID lpOverlapped, LPVOID lpCompletionRoutine)');
# my $ret = $WSASendMsg->Call($Handle, $lpMsg, $dwFlags, $lpNumberOfBytesSent, $lpOverlapped, $lpCompletionRoutine);
# Handle : SOCKET -> WPARAM
# lpMsg : WSAMSG* -> LPVOID
# dwFlags : DWORD -> DWORD
# lpNumberOfBytesSent : DWORD* optional, out -> LPVOID
# lpOverlapped : OVERLAPPED* optional, in/out -> LPVOID
# lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# コールバック(関数ポインタ)は Perl sub を直接渡せません。Win32::API::Callback を使用してください。

関連項目

公式の関連項目
使用する型