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

WSARecvFrom

関数
データグラムを受信し送信元アドレスを取得する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

INT WSARecvFrom(
    SOCKET s,
    WSABUF* lpBuffers,
    DWORD dwBufferCount,
    DWORD* lpNumberOfBytesRecvd,   // optional
    DWORD* lpFlags,
    SOCKADDR* lpFrom,   // optional
    INT* lpFromlen,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine   // optional
);

パラメーター

名前方向説明
sSOCKETinsocket を識別するディスクリプタ。
lpBuffersWSABUF*inWSABUF 構造体の配列へのポインタ。各 WSABUF 構造体には、バッファへのポインタとバッファの長さが含まれます。
dwBufferCountDWORDinlpBuffers 配列内の WSABUF 構造体の数。
lpNumberOfBytesRecvdDWORD*outoptional

WSARecvFrom 操作が即座に完了した場合に、この呼び出しで受信したバイト数を格納するポインタ。

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

lpFlagsDWORD*inoutWSARecvFrom 関数呼び出しの動作を変更するために使用するフラグへのポインタ。後述の解説を参照してください。
lpFromSOCKADDR*outoptionalオーバーラップ操作の完了時に送信元アドレスを保持するバッファへの、省略可能なポインタ。
lpFromlenINT*inoutoptional"from" バッファのサイズ(バイト単位)へのポインタ。lpFrom が指定されている場合にのみ必要です。
lpOverlappedOVERLAPPED*inoutoptionalWSAOVERLAPPED 構造体へのポインタ(非オーバーラップソケットでは無視されます)。
lpCompletionRoutineLPWSAOVERLAPPED_COMPLETION_ROUTINEinoptionalWSARecvFrom 操作が完了したときに呼び出される完了ルーチンへのポインタ(非オーバーラップソケットでは無視されます)。

戻り値の型: INT

公式ドキュメント

データグラムを受信し、送信元アドレスを格納します。

戻り値

エラーが発生せず、受信操作が即座に完了した場合、 WSARecvFrom はゼロを返します。この場合、呼び出し元スレッドがアラート可能状態になると、完了ルーチンが既に呼び出されるようスケジュールされています。それ以外の場合は SOCKET_ERROR が返され、 WSAGetLastError を呼び出すことで具体的なエラーコードを取得できます。エラーコード WSA_IO_PENDING は、オーバーラップ操作が正常に開始され、完了が後で通知されることを示します。それ以外のエラーコードは、オーバーラップ操作が正常に開始されず、完了通知が行われないことを示します。

エラーコード 意味
WSAECONNRESET
リモート側がハードクローズまたはアボート的なクローズを実行したため、仮想回線がリセットされました。socket はもはや使用できないため、アプリケーションはこれをクローズする必要があります。UDP データグラムソケットの場合、このエラーは、以前の送信操作が ICMP の "Port Unreachable"(ポート到達不能)メッセージを引き起こしたことを示します。
WSAEFAULT
lpBufferslpFlagslpFromlpNumberOfBytesRecvdlpFromlenlpOverlapped、または lpCompletionRoutine パラメータが、ユーザーアドレス空間の有効な部分に完全には含まれていません。lpFrom バッファが、ピアアドレスを格納するには小さすぎました。
WSAEINPROGRESS
ブロッキング型の Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理しています。
WSAEINTR
ブロッキング型の Windows Socket 1.1 呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEINVAL
socket が(たとえば bind によって)バインドされていません。
WSAEMSGSIZE
メッセージが指定されたバッファに対して大きすぎ、(信頼性のないプロトコルの場合のみ)バッファに収まらなかったメッセージの末尾部分は破棄されました。
WSAENETDOWN
ネットワークサブシステムが失敗しました。
WSAENETRESET
データグラムソケットの場合、このエラーは TTL(time to live)が期限切れになったことを示します。
WSAENOTCONN
socket が接続されていません(コネクション指向ソケットのみ)。
WSAEWOULDBLOCK
Windows NT:

オーバーラップソケット: 未処理のオーバーラップ I/O 要求が多すぎます。非オーバーラップソケット: socket は非ブロッキングとしてマークされており、受信操作を即座に完了できません。

WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSA_IO_PENDING
オーバーラップ操作が正常に開始され、完了は後で通知されます。
WSA_OPERATION_ABORTED
socket のクローズにより、オーバーラップ操作がキャンセルされました。

解説(Remarks)

WSARecvFrom 関数は、標準の recvfrom 関数に加えて、次の3つの重要な点で機能を提供します。

WSARecvFrom 関数は、主に s で指定されたコネクションレスソケットで使用されます。socket のローカルアドレスが既知である必要があります。サーバーアプリケーションの場合、これは通常 bind によって明示的に行われます。クライアントアプリケーションでは、明示的なバインドは推奨されません。この関数を使用するクライアントアプリケーションでは、socket は sendtoWSASendTo、または WSAJoinLeaf を通じて、ローカルアドレスに暗黙的にバインドされることがあります。

オーバーラップソケットの場合、この関数は、(場合によっては接続された)socket で受信データが利用可能になったときにそれを格納するための1つ以上のバッファをポストするために使用されます。その後、アプリケーションが指定した完了通知(完了ルーチンの呼び出し、またはイベントオブジェクトの設定)が行われます。操作が即座に完了しない場合、最終的な完了ステータスは、完了ルーチンまたは WSAGetOverlappedResult を通じて取得されます。また、lpFrom および lpFromlen が指す値は、完了自体が通知されるまで更新されません。アプリケーションはこれらの値が更新されるまで使用したり変更したりしてはなりません。したがって、これらのパラメータには自動変数(つまりスタックベースの変数)を使用してはなりません。

注意 あるスレッドによって開始されたすべての I/O は、そのスレッドが終了すると取り消されます。オーバーラップソケットの場合、操作が完了する前にスレッドがクローズされると、保留中の非同期操作が失敗することがあります。詳細については ExitThread を参照してください。
lpOverlappedlpCompletionRoutine の両方が NULL の場合、この関数の socket は非オーバーラップソケットとして扱われます。

非オーバーラップソケットの場合、ブロッキングのセマンティクスは標準の WSARecv 関数と同一であり、lpOverlapped および lpCompletionRoutine パラメータは無視されます。トランスポートによって既に受信されバッファリングされたデータは、ユーザーバッファにコピーされます。ブロッキングソケットでトランスポートによって現在受信およびバッファリングされたデータがない場合、呼び出しはデータが受信されるまでブロックします。

バッファは、lpBuffers が示す配列に現れる順序で埋められ、隙間が生じないように詰めて格納されます。

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

コネクションレスのソケット型の場合、データの送信元アドレスが lpFrom が示すバッファにコピーされます。lpFromlen が指す値は、このバッファのサイズに初期化され、完了時にそこに格納された実際のアドレスのサイズを示すように変更されます。前述のとおり、オーバーラップソケットの場合、lpFrom および lpFromlen パラメータは、オーバーラップ I/O が完了するまで更新されません。したがって、これらのパラメータが指すメモリはサービスプロバイダーが利用可能な状態を保つ必要があり、アプリケーションのスタックフレーム上に確保することはできません。コネクション指向ソケットの場合、lpFrom および lpFromlen パラメータは無視されます。

バイトストリーム型のソケット(たとえば SOCK_STREAM 型)の場合、受信データは次のいずれかになるまでバッファに格納されます。

受信データがすべてのバッファを満たすかどうかにかかわらず、オーバーラップソケットでは完了通知が行われます。メッセージ指向ソケットの場合、受信メッセージはバッファの合計サイズまでバッファに格納され、オーバーラップソケットでは完了通知が行われます。メッセージがバッファより大きい場合、バッファにはメッセージの最初の部分が格納されます。基盤となるサービスプロバイダーが MSG_PARTIAL 機能をサポートしている場合、lpFlagsMSG_PARTIAL フラグが設定され、後続の受信操作でメッセージの残りが取得されます。MSG_PARTIAL がサポートされていないがプロトコルが信頼性のあるものである場合、 WSARecvFrom はエラー WSAEMSGSIZE を生成し、より大きなバッファを使用した後続の受信操作でメッセージ全体を取得できます。それ以外の場合(つまり、プロトコルが信頼性がなく MSG_PARTIAL をサポートしていない場合)、超過分のデータは失われ、 WSARecvFrom はエラー WSAEMSGSIZE を生成します。

lpFlags パラメータは、関連付けられた socket に指定されたオプションを超えて、関数呼び出しの動作に影響を与えるために使用できます。すなわち、この関数のセマンティクスは、ソケットオプションと lpFlags パラメータによって決定されます。後者は、次の表に示す値のいずれかをビット単位の OR 演算子で組み合わせて構築します。

意味
MSG_PEEK 受信データをプレビューします。データはバッファにコピーされますが、入力キューからは削除されません。このフラグは非オーバーラップソケットでのみ有効です。
MSG_OOB OOB データを処理します。
MSG_PARTIAL このフラグはメッセージ指向ソケットでのみ使用します。出力時には、このフラグは、データが送信側によって送信されたメッセージの一部であることを示します。メッセージの残りの部分は、後続の受信操作で送信されます。MSG_PARTIAL フラグがクリアされた後続の受信操作は、送信側のメッセージの終わりを示します。

入力パラメータとしては、このフラグは、メッセージの一部のみがサービスプロバイダーによって受信された場合でも受信操作を完了すべきであることを示します。

メッセージ指向ソケットの場合、部分的なメッセージを受信すると lpFlags パラメータに MSG_PARTIAL ビットが設定されます。完全なメッセージを受信した場合、lpFlagsMSG_PARTIAL はクリアされます。完了が遅延する場合、lpFlags が指す値は更新されません。完了が通知されたら、アプリケーションは WSAGetOverlappedResult を呼び出し、lpdwFlags パラメータが指すフラグを調べる必要があります。

注意 lpOverlapped パラメータを NULL に設定して WSARecvFrom のようなブロッキング型の Winsock 呼び出しを発行する場合、呼び出しが完了する前に Winsock がネットワークイベントを待機する必要が生じることがあります。この状況では Winsock はアラート可能な待機を実行し、これは同じスレッドでスケジュールされた非同期プロシージャ呼び出し(APC)によって中断される可能性があります。進行中のブロッキング型 Winsock 呼び出しを中断した APC の内部で、同じスレッド上の別のブロッキング型 Winsock 呼び出しを発行すると、未定義の動作につながるため、Winsock クライアントは決してこれを試みてはなりません。

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

オーバーラップ操作が即座に完了した場合、 WSARecvFrom はゼロを返し、lpNumberOfBytesRecvd パラメータは受信したバイト数で更新され、lpFlags パラメータが指すフラグビットも更新されます。オーバーラップ操作が正常に開始され後で完了する場合、 WSARecvFromSOCKET_ERROR を返し、エラーコード WSA_IO_PENDING を示します。この場合、lpNumberOfBytesRecvd および lpFlags は更新されません。オーバーラップ操作が完了すると、転送されたデータ量は、(指定されている場合は)完了ルーチンの cbTransferred パラメータを通じて、または WSAGetOverlappedResultlpcbTransfer パラメータを通じて示されます。フラグ値は、完了ルーチンの dwFlags パラメータを通じて、または WSAGetOverlappedResultlpdwFlags パラメータを調べることで取得されます。

WSARecvFrom 関数は、以前の WSARecvWSARecvFromWSASend、または WSASendTo 関数の完了ルーチン内から呼び出すことができます。所与の socket について、I/O 完了ルーチンがネストされることはありません。これにより、時間的制約のあるデータ送信を、プリエンプティブなコンテキスト内で完結させることができます。

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 関数を呼び出した場合に生じうるような、スレッドがアラート可能な待機状態になるまで呼び出されません。

IO 完了ポートが使用され、lpCompletionRoutine パラメータと hEvent パラメータが NULL の場合、操作の結果は IO 完了ポートにスケジュールされます。これは、操作が即座に完了するかどうかにかかわらず、すべての成功した操作で発生します。

トランスポートプロバイダーは、アプリケーションが 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 パラメータには、受信操作が即座に完了した場合に lpFlags に現れたであろう情報が含まれます。この関数は値を返しません。

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

サンプルコード

次の例は、WSARecvFrom 関数の使用方法を示しています。
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

int __cdecl main()
{

    WSADATA wsaData;
    WSABUF DataBuf;
    WSAOVERLAPPED Overlapped;

    SOCKET RecvSocket = INVALID_SOCKET;
    struct sockaddr_in RecvAddr;
    struct sockaddr_in SenderAddr;

    int SenderAddrSize = sizeof (SenderAddr);
    u_short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;
    DWORD BytesRecv = 0;
    DWORD Flags = 0;

    int err = 0;
    int rc;
    int retval = 0;
    
    //-----------------------------------------------
    // Initialize Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        /* Could not find a usable Winsock DLL */
        wprintf(L"WSAStartup failed with error: %ld\n", rc);
        return 1;
    }

    // Make sure the Overlapped struct is zeroed out
    SecureZeroMemory((PVOID) &Overlapped, sizeof(WSAOVERLAPPED) );

    // Create an event handle and setup the overlapped structure.
    Overlapped.hEvent = WSACreateEvent();
    if (Overlapped.hEvent == NULL) {
        wprintf(L"WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = WSASocket(AF_INET,
                           SOCK_DGRAM,
                           IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

    if (RecvSocket == INVALID_SOCKET) {
        /* Could not open a socket */
        wprintf(L"WSASocket failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (rc != 0) {
        /* Bind to the socket failed */
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(RecvSocket);
        WSACleanup();
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    DataBuf.len = BufLen;
    DataBuf.buf = RecvBuf;
    wprintf(L"Listening for incoming datagrams on port=%d\n", Port);
    rc = WSARecvFrom(RecvSocket,
                      &DataBuf,
                      1,
                      &BytesRecv,
                      &Flags,
                      (SOCKADDR *) & SenderAddr,
                      &SenderAddrSize, &Overlapped, NULL);

    if (rc != 0) {
        err = WSAGetLastError();
        if (err != WSA_IO_PENDING) {
            wprintf(L"WSARecvFrom failed with error: %ld\n", err);
            WSACloseEvent(Overlapped.hEvent);
            closesocket(RecvSocket);
            WSACleanup();
            return 1;
        }
        else {
            rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
            if (rc == WSA_WAIT_FAILED) {
                wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }

            rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,
                                FALSE, &Flags);
            if (rc == FALSE) {
                wprintf(L"WSArecvFrom failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }
            else
                wprintf(L"Number of received bytes = %d\n", BytesRecv);
                
            wprintf(L"Finished receiving. Closing socket.\n");
        }
        
    }
    //---------------------------------------------
    // When the application is finished receiving, close the socket.

    WSACloseEvent(Overlapped.hEvent);
    closesocket(RecvSocket);
    wprintf(L"Exiting.\n");

    //---------------------------------------------
    // Clean up and quit.
    WSACleanup();
    return (retval);
}

Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストアアプリでサポートされています。

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 WSARecvFrom(
    SOCKET s,
    WSABUF* lpBuffers,
    DWORD dwBufferCount,
    DWORD* lpNumberOfBytesRecvd,   // optional
    DWORD* lpFlags,
    SOCKADDR* lpFrom,   // optional
    INT* lpFromlen,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine   // optional
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern int WSARecvFrom(
    UIntPtr s,   // SOCKET
    IntPtr lpBuffers,   // WSABUF*
    uint dwBufferCount,   // DWORD
    IntPtr lpNumberOfBytesRecvd,   // DWORD* optional, out
    ref uint lpFlags,   // DWORD* in/out
    IntPtr lpFrom,   // SOCKADDR* optional, out
    IntPtr lpFromlen,   // INT* optional, in/out
    IntPtr lpOverlapped,   // OVERLAPPED* optional, in/out
    IntPtr lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function WSARecvFrom(
    s As UIntPtr,   ' SOCKET
    lpBuffers As IntPtr,   ' WSABUF*
    dwBufferCount As UInteger,   ' DWORD
    lpNumberOfBytesRecvd As IntPtr,   ' DWORD* optional, out
    ByRef lpFlags As UInteger,   ' DWORD* in/out
    lpFrom As IntPtr,   ' SOCKADDR* optional, out
    lpFromlen As IntPtr,   ' INT* optional, in/out
    lpOverlapped As IntPtr,   ' OVERLAPPED* optional, in/out
    lpCompletionRoutine As IntPtr   ' LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
) As Integer
End Function
' s : SOCKET
' lpBuffers : WSABUF*
' dwBufferCount : DWORD
' lpNumberOfBytesRecvd : DWORD* optional, out
' lpFlags : DWORD* in/out
' lpFrom : SOCKADDR* optional, out
' lpFromlen : INT* optional, in/out
' lpOverlapped : OVERLAPPED* optional, in/out
' lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
Declare PtrSafe Function WSARecvFrom Lib "ws2_32" ( _
    ByVal s As LongPtr, _
    ByVal lpBuffers As LongPtr, _
    ByVal dwBufferCount As Long, _
    ByVal lpNumberOfBytesRecvd As LongPtr, _
    ByRef lpFlags As Long, _
    ByVal lpFrom As LongPtr, _
    ByVal lpFromlen 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

WSARecvFrom = ctypes.windll.ws2_32.WSARecvFrom
WSARecvFrom.restype = ctypes.c_int
WSARecvFrom.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
    ctypes.c_void_p,  # lpBuffers : WSABUF*
    wintypes.DWORD,  # dwBufferCount : DWORD
    ctypes.POINTER(wintypes.DWORD),  # lpNumberOfBytesRecvd : DWORD* optional, out
    ctypes.POINTER(wintypes.DWORD),  # lpFlags : DWORD* in/out
    ctypes.c_void_p,  # lpFrom : SOCKADDR* optional, out
    ctypes.POINTER(ctypes.c_int),  # lpFromlen : INT* optional, in/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')
WSARecvFrom = Fiddle::Function.new(
  lib['WSARecvFrom'],
  [
    Fiddle::TYPE_UINTPTR_T,  # s : SOCKET
    Fiddle::TYPE_VOIDP,  # lpBuffers : WSABUF*
    -Fiddle::TYPE_INT,  # dwBufferCount : DWORD
    Fiddle::TYPE_VOIDP,  # lpNumberOfBytesRecvd : DWORD* optional, out
    Fiddle::TYPE_VOIDP,  # lpFlags : DWORD* in/out
    Fiddle::TYPE_VOIDP,  # lpFrom : SOCKADDR* optional, out
    Fiddle::TYPE_VOIDP,  # lpFromlen : INT* optional, in/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 WSARecvFrom(
        s: usize,  // SOCKET
        lpBuffers: *mut WSABUF,  // WSABUF*
        dwBufferCount: u32,  // DWORD
        lpNumberOfBytesRecvd: *mut u32,  // DWORD* optional, out
        lpFlags: *mut u32,  // DWORD* in/out
        lpFrom: *mut SOCKADDR,  // SOCKADDR* optional, out
        lpFromlen: *mut i32,  // INT* optional, in/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 WSARecvFrom(UIntPtr s, IntPtr lpBuffers, uint dwBufferCount, IntPtr lpNumberOfBytesRecvd, ref uint lpFlags, IntPtr lpFrom, IntPtr lpFromlen, IntPtr lpOverlapped, IntPtr lpCompletionRoutine);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_WSARecvFrom' -Namespace Win32 -PassThru
# $api::WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
#uselib "WS2_32.dll"
#func global WSARecvFrom "WSARecvFrom" sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr
; WSARecvFrom s, varptr(lpBuffers), dwBufferCount, varptr(lpNumberOfBytesRecvd), varptr(lpFlags), varptr(lpFrom), varptr(lpFromlen), varptr(lpOverlapped), lpCompletionRoutine   ; 戻り値は stat
; s : SOCKET -> "sptr"
; lpBuffers : WSABUF* -> "sptr"
; dwBufferCount : DWORD -> "sptr"
; lpNumberOfBytesRecvd : DWORD* optional, out -> "sptr"
; lpFlags : DWORD* in/out -> "sptr"
; lpFrom : SOCKADDR* optional, out -> "sptr"
; lpFromlen : INT* optional, in/out -> "sptr"
; lpOverlapped : OVERLAPPED* optional, in/out -> "sptr"
; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "WS2_32.dll"
#cfunc global WSARecvFrom "WSARecvFrom" sptr, var, int, var, var, var, var, var, sptr
; res = WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
; s : SOCKET -> "sptr"
; lpBuffers : WSABUF* -> "var"
; dwBufferCount : DWORD -> "int"
; lpNumberOfBytesRecvd : DWORD* optional, out -> "var"
; lpFlags : DWORD* in/out -> "var"
; lpFrom : SOCKADDR* optional, out -> "var"
; lpFromlen : INT* optional, in/out -> "var"
; lpOverlapped : OVERLAPPED* optional, in/out -> "var"
; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> "sptr"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; INT WSARecvFrom(SOCKET s, WSABUF* lpBuffers, DWORD dwBufferCount, DWORD* lpNumberOfBytesRecvd, DWORD* lpFlags, SOCKADDR* lpFrom, INT* lpFromlen, OVERLAPPED* lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
#uselib "WS2_32.dll"
#cfunc global WSARecvFrom "WSARecvFrom" intptr, var, int, var, var, var, var, var, intptr
; res = WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
; s : SOCKET -> "intptr"
; lpBuffers : WSABUF* -> "var"
; dwBufferCount : DWORD -> "int"
; lpNumberOfBytesRecvd : DWORD* optional, out -> "var"
; lpFlags : DWORD* in/out -> "var"
; lpFrom : SOCKADDR* optional, out -> "var"
; lpFromlen : INT* optional, in/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")
	procWSARecvFrom = ws2_32.NewProc("WSARecvFrom")
)

// s (SOCKET), lpBuffers (WSABUF*), dwBufferCount (DWORD), lpNumberOfBytesRecvd (DWORD* optional, out), lpFlags (DWORD* in/out), lpFrom (SOCKADDR* optional, out), lpFromlen (INT* optional, in/out), lpOverlapped (OVERLAPPED* optional, in/out), lpCompletionRoutine (LPWSAOVERLAPPED_COMPLETION_ROUTINE optional)
r1, _, err := procWSARecvFrom.Call(
	uintptr(s),
	uintptr(lpBuffers),
	uintptr(dwBufferCount),
	uintptr(lpNumberOfBytesRecvd),
	uintptr(lpFlags),
	uintptr(lpFrom),
	uintptr(lpFromlen),
	uintptr(lpOverlapped),
	uintptr(lpCompletionRoutine),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function WSARecvFrom(
  s: NativeUInt;   // SOCKET
  lpBuffers: Pointer;   // WSABUF*
  dwBufferCount: DWORD;   // DWORD
  lpNumberOfBytesRecvd: Pointer;   // DWORD* optional, out
  lpFlags: Pointer;   // DWORD* in/out
  lpFrom: Pointer;   // SOCKADDR* optional, out
  lpFromlen: Pointer;   // INT* optional, in/out
  lpOverlapped: Pointer;   // OVERLAPPED* optional, in/out
  lpCompletionRoutine: Pointer   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSARecvFrom';
result := DllCall("WS2_32\WSARecvFrom"
    , "UPtr", s   ; SOCKET
    , "Ptr", lpBuffers   ; WSABUF*
    , "UInt", dwBufferCount   ; DWORD
    , "Ptr", lpNumberOfBytesRecvd   ; DWORD* optional, out
    , "Ptr", lpFlags   ; DWORD* in/out
    , "Ptr", lpFrom   ; SOCKADDR* optional, out
    , "Ptr", lpFromlen   ; INT* optional, in/out
    , "Ptr", lpOverlapped   ; OVERLAPPED* optional, in/out
    , "Ptr", lpCompletionRoutine   ; LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
    , "Int")   ; return: INT
●WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine) = DLL("WS2_32.dll", "int WSARecvFrom(int, void*, dword, void*, void*, void*, void*, void*, void*)")
# 呼び出し: WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
# s : SOCKET -> "int"
# lpBuffers : WSABUF* -> "void*"
# dwBufferCount : DWORD -> "dword"
# lpNumberOfBytesRecvd : DWORD* optional, out -> "void*"
# lpFlags : DWORD* in/out -> "void*"
# lpFrom : SOCKADDR* optional, out -> "void*"
# lpFromlen : INT* optional, in/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 WSARecvFrom(
    s: usize, // SOCKET
    lpBuffers: [*c]WSABUF, // WSABUF*
    dwBufferCount: u32, // DWORD
    lpNumberOfBytesRecvd: [*c]u32, // DWORD* optional, out
    lpFlags: [*c]u32, // DWORD* in/out
    lpFrom: [*c]SOCKADDR, // SOCKADDR* optional, out
    lpFromlen: [*c]i32, // INT* optional, in/out
    lpOverlapped: [*c]OVERLAPPED, // OVERLAPPED* optional, in/out
    lpCompletionRoutine: ?*anyopaque // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
) callconv(std.os.windows.WINAPI) i32;
proc WSARecvFrom(
    s: uint,  # SOCKET
    lpBuffers: ptr WSABUF,  # WSABUF*
    dwBufferCount: uint32,  # DWORD
    lpNumberOfBytesRecvd: ptr uint32,  # DWORD* optional, out
    lpFlags: ptr uint32,  # DWORD* in/out
    lpFrom: ptr SOCKADDR,  # SOCKADDR* optional, out
    lpFromlen: ptr int32,  # INT* optional, in/out
    lpOverlapped: ptr OVERLAPPED,  # OVERLAPPED* optional, in/out
    lpCompletionRoutine: pointer  # LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): int32 {.importc: "WSARecvFrom", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int WSARecvFrom(
    size_t s,   // SOCKET
    WSABUF* lpBuffers,   // WSABUF*
    uint dwBufferCount,   // DWORD
    uint* lpNumberOfBytesRecvd,   // DWORD* optional, out
    uint* lpFlags,   // DWORD* in/out
    SOCKADDR* lpFrom,   // SOCKADDR* optional, out
    int* lpFromlen,   // INT* optional, in/out
    OVERLAPPED* lpOverlapped,   // OVERLAPPED* optional, in/out
    void* lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
);
ccall((:WSARecvFrom, "WS2_32.dll"), stdcall, Int32,
      (Csize_t, Ptr{WSABUF}, UInt32, Ptr{UInt32}, Ptr{UInt32}, Ptr{SOCKADDR}, Ptr{Int32}, Ptr{OVERLAPPED}, Ptr{Cvoid}),
      s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
# s : SOCKET -> Csize_t
# lpBuffers : WSABUF* -> Ptr{WSABUF}
# dwBufferCount : DWORD -> UInt32
# lpNumberOfBytesRecvd : DWORD* optional, out -> Ptr{UInt32}
# lpFlags : DWORD* in/out -> Ptr{UInt32}
# lpFrom : SOCKADDR* optional, out -> Ptr{SOCKADDR}
# lpFromlen : INT* optional, in/out -> Ptr{Int32}
# 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 WSARecvFrom(
    uintptr_t s,
    void* lpBuffers,
    uint32_t dwBufferCount,
    uint32_t* lpNumberOfBytesRecvd,
    uint32_t* lpFlags,
    void* lpFrom,
    int32_t* lpFromlen,
    void* lpOverlapped,
    void* lpCompletionRoutine);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
-- s : SOCKET
-- lpBuffers : WSABUF*
-- dwBufferCount : DWORD
-- lpNumberOfBytesRecvd : DWORD* optional, out
-- lpFlags : DWORD* in/out
-- lpFrom : SOCKADDR* optional, out
-- lpFromlen : INT* optional, in/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 WSARecvFrom = lib.func('__stdcall', 'WSARecvFrom', 'int32_t', ['uintptr_t', 'void *', 'uint32_t', 'uint32_t *', 'uint32_t *', 'void *', 'int32_t *', 'void *', 'void *']);
// WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
// s : SOCKET -> 'uintptr_t'
// lpBuffers : WSABUF* -> 'void *'
// dwBufferCount : DWORD -> 'uint32_t'
// lpNumberOfBytesRecvd : DWORD* optional, out -> 'uint32_t *'
// lpFlags : DWORD* in/out -> 'uint32_t *'
// lpFrom : SOCKADDR* optional, out -> 'void *'
// lpFromlen : INT* optional, in/out -> 'int32_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", {
  WSARecvFrom: { parameters: ["usize", "pointer", "u32", "pointer", "pointer", "pointer", "pointer", "pointer", "pointer"], result: "i32" },
});
// lib.symbols.WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine)
// s : SOCKET -> "usize"
// lpBuffers : WSABUF* -> "pointer"
// dwBufferCount : DWORD -> "u32"
// lpNumberOfBytesRecvd : DWORD* optional, out -> "pointer"
// lpFlags : DWORD* in/out -> "pointer"
// lpFrom : SOCKADDR* optional, out -> "pointer"
// lpFromlen : INT* optional, in/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 WSARecvFrom(
    size_t s,
    void* lpBuffers,
    uint32_t dwBufferCount,
    uint32_t* lpNumberOfBytesRecvd,
    uint32_t* lpFlags,
    void* lpFrom,
    int32_t* lpFromlen,
    void* lpOverlapped,
    void* lpCompletionRoutine);
C, "WS2_32.dll");
// $ffi->WSARecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
// s : SOCKET
// lpBuffers : WSABUF*
// dwBufferCount : DWORD
// lpNumberOfBytesRecvd : DWORD* optional, out
// lpFlags : DWORD* in/out
// lpFrom : SOCKADDR* optional, out
// lpFromlen : INT* optional, in/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 WSARecvFrom(
        long s,   // SOCKET
        Pointer lpBuffers,   // WSABUF*
        int dwBufferCount,   // DWORD
        IntByReference lpNumberOfBytesRecvd,   // DWORD* optional, out
        IntByReference lpFlags,   // DWORD* in/out
        Pointer lpFrom,   // SOCKADDR* optional, out
        IntByReference lpFromlen,   // INT* optional, in/out
        Pointer lpOverlapped,   // OVERLAPPED* optional, in/out
        Callback lpCompletionRoutine   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun WSARecvFrom = WSARecvFrom(
    s : LibC::SizeT,   # SOCKET
    lpBuffers : WSABUF*,   # WSABUF*
    dwBufferCount : UInt32,   # DWORD
    lpNumberOfBytesRecvd : UInt32*,   # DWORD* optional, out
    lpFlags : UInt32*,   # DWORD* in/out
    lpFrom : SOCKADDR*,   # SOCKADDR* optional, out
    lpFromlen : Int32*,   # INT* optional, in/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 WSARecvFromNative = Int32 Function(UintPtr, Pointer<Void>, Uint32, Pointer<Uint32>, Pointer<Uint32>, Pointer<Void>, Pointer<Int32>, Pointer<Void>, Pointer<Void>);
typedef WSARecvFromDart = int Function(int, Pointer<Void>, int, Pointer<Uint32>, Pointer<Uint32>, Pointer<Void>, Pointer<Int32>, Pointer<Void>, Pointer<Void>);
final WSARecvFrom = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<WSARecvFromNative, WSARecvFromDart>('WSARecvFrom');
// s : SOCKET -> UintPtr
// lpBuffers : WSABUF* -> Pointer<Void>
// dwBufferCount : DWORD -> Uint32
// lpNumberOfBytesRecvd : DWORD* optional, out -> Pointer<Uint32>
// lpFlags : DWORD* in/out -> Pointer<Uint32>
// lpFrom : SOCKADDR* optional, out -> Pointer<Void>
// lpFromlen : INT* optional, in/out -> Pointer<Int32>
// lpOverlapped : OVERLAPPED* optional, in/out -> Pointer<Void>
// lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function WSARecvFrom(
  s: NativeUInt;   // SOCKET
  lpBuffers: Pointer;   // WSABUF*
  dwBufferCount: DWORD;   // DWORD
  lpNumberOfBytesRecvd: Pointer;   // DWORD* optional, out
  lpFlags: Pointer;   // DWORD* in/out
  lpFrom: Pointer;   // SOCKADDR* optional, out
  lpFromlen: Pointer;   // INT* optional, in/out
  lpOverlapped: Pointer;   // OVERLAPPED* optional, in/out
  lpCompletionRoutine: Pointer   // LPWSAOVERLAPPED_COMPLETION_ROUTINE optional
): Integer; stdcall;
  external 'WS2_32.dll' name 'WSARecvFrom';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "WSARecvFrom"
  c_WSARecvFrom :: CUIntPtr -> Ptr () -> Word32 -> Ptr Word32 -> Ptr Word32 -> Ptr () -> Ptr Int32 -> Ptr () -> Ptr () -> IO Int32
-- s : SOCKET -> CUIntPtr
-- lpBuffers : WSABUF* -> Ptr ()
-- dwBufferCount : DWORD -> Word32
-- lpNumberOfBytesRecvd : DWORD* optional, out -> Ptr Word32
-- lpFlags : DWORD* in/out -> Ptr Word32
-- lpFrom : SOCKADDR* optional, out -> Ptr ()
-- lpFromlen : INT* optional, in/out -> Ptr Int32
-- lpOverlapped : OVERLAPPED* optional, in/out -> Ptr ()
-- lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let wsarecvfrom =
  foreign "WSARecvFrom"
    (size_t @-> (ptr void) @-> uint32_t @-> (ptr uint32_t) @-> (ptr uint32_t) @-> (ptr void) @-> (ptr int32_t) @-> (ptr void) @-> (ptr void) @-> returning int32_t)
(* s : SOCKET -> size_t *)
(* lpBuffers : WSABUF* -> (ptr void) *)
(* dwBufferCount : DWORD -> uint32_t *)
(* lpNumberOfBytesRecvd : DWORD* optional, out -> (ptr uint32_t) *)
(* lpFlags : DWORD* in/out -> (ptr uint32_t) *)
(* lpFrom : SOCKADDR* optional, out -> (ptr void) *)
(* lpFromlen : INT* optional, in/out -> (ptr int32_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 ("WSARecvFrom" wsarecv-from :convention :stdcall) :int32
  (s :uint64)   ; SOCKET
  (lp-buffers :pointer)   ; WSABUF*
  (dw-buffer-count :uint32)   ; DWORD
  (lp-number-of-bytes-recvd :pointer)   ; DWORD* optional, out
  (lp-flags :pointer)   ; DWORD* in/out
  (lp-from :pointer)   ; SOCKADDR* optional, out
  (lp-fromlen :pointer)   ; INT* optional, in/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 $WSARecvFrom = Win32::API::More->new('WS2_32',
    'int WSARecvFrom(WPARAM s, LPVOID lpBuffers, DWORD dwBufferCount, LPVOID lpNumberOfBytesRecvd, LPVOID lpFlags, LPVOID lpFrom, LPVOID lpFromlen, LPVOID lpOverlapped, LPVOID lpCompletionRoutine)');
# my $ret = $WSARecvFrom->Call($s, $lpBuffers, $dwBufferCount, $lpNumberOfBytesRecvd, $lpFlags, $lpFrom, $lpFromlen, $lpOverlapped, $lpCompletionRoutine);
# s : SOCKET -> WPARAM
# lpBuffers : WSABUF* -> LPVOID
# dwBufferCount : DWORD -> DWORD
# lpNumberOfBytesRecvd : DWORD* optional, out -> LPVOID
# lpFlags : DWORD* in/out -> LPVOID
# lpFrom : SOCKADDR* optional, out -> LPVOID
# lpFromlen : INT* optional, in/out -> LPVOID
# lpOverlapped : OVERLAPPED* optional, in/out -> LPVOID
# lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE optional -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# コールバック(関数ポインタ)は Perl sub を直接渡せません。Win32::API::Callback を使用してください。

関連項目

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