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

WSAJoinLeaf

関数
マルチポイントセッションにリーフノードとして参加する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

SOCKET WSAJoinLeaf(
    SOCKET s,
    const SOCKADDR* name,
    INT namelen,
    WSABUF* lpCallerData,   // optional
    WSABUF* lpCalleeData,   // optional
    QOS* lpSQOS,   // optional
    QOS* lpGQOS,   // optional
    DWORD dwFlags
);

パラメーター

名前方向説明
sSOCKETinマルチポイントソケットを識別する記述子です。
nameSOCKADDR*inソケットの参加先となるピアの名前です。
namelenINTinname の長さ (バイト単位) です。
lpCallerDataWSABUF*inoptionalマルチポイントセッション確立時にピアへ転送されるユーザーデータへのポインターです。
lpCalleeDataWSABUF*outoptionalマルチポイントセッション確立時にピアから返送されるユーザーデータへのポインターです。
lpSQOSQOS*inoptionalソケット s に対する FLOWSPEC 構造体へのポインターです。各方向に 1 つずつ指定します。
lpGQOSQOS*inoptional将来のソケットグループでの使用のために予約されています。ソケットグループに対する FLOWSPEC 構造体へのポインターです (該当する場合)。
dwFlagsDWORDinソケットが送信側 (JL_SENDER_ONLY)、受信側 (JL_RECEIVER_ONLY)、またはその両方 (JL_BOTH) として動作することを示すフラグです。

戻り値の型: SOCKET

公式ドキュメント

WSAJoinLeaf 関数は、リーフノードをマルチポイントセッションに参加させ、接続データを交換し、指定された FLOWSPEC 構造体に基づいて必要なサービス品質 (QoS) を指定します。

戻り値

エラーが発生しなかった場合、 WSAJoinLeaf は新しく作成されたマルチポイントソケットの記述子である SOCKET 型の値を返します。それ以外の場合は INVALID_SOCKET が返され、 WSAGetLastError を呼び出すことで具体的なエラーコードを取得できます。

ブロッキングソケットでは、戻り値は参加操作の成功または失敗を示します。

ノンブロッキングソケットでは、有効なソケット記述子が返されることで参加操作の開始が成功したことを示します。その後、参加操作が成功または失敗のいずれかで完了すると、元のソケット s に対して FD_CONNECT が通知されます。アプリケーションは、参加操作がいつ完了したかを判断するために、FD_CONNECT イベントを登録した WSAAsyncSelect または WSAEventSelect を使用し、関連するエラーコードを確認して操作の成否を判断する必要があります。 select 関数は、参加操作の完了を判断するために使用することはできません。

また、マルチポイントセッションへの参加試行が完了するまで、同じソケットに対する以後の WSAJoinLeaf 呼び出しはすべてエラーコード WSAEALREADY で失敗します。 WSAJoinLeaf 操作が正常に完了した後は、通常、以後の試行はエラーコード WSAEISCONN で失敗します。WSAEISCONN ルールの例外は、root が開始する参加を許可する c_root ソケットで発生します。この場合、先行する WSAJoinLeaf 操作の完了後に別の参加を開始できます。

戻り値のエラーコードがマルチポイントセッションへの参加試行の失敗を示している場合 (すなわち WSAECONNREFUSEDWSAENETUNREACHWSAETIMEDOUT)、アプリケーションは同じソケットに対して再度 WSAJoinLeaf を呼び出すことができます。

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSAEADDRINUSE
ソケットのローカルアドレスが既に使用されており、ソケットが SO_REUSEADDR でアドレスの再利用を許可するように設定されていませんでした。このエラーは通常 bind の時点で発生しますが、 bind が部分的にワイルドカードのアドレス (ADDR_ANY を含む) に対して行われ、この関数の時点で特定のアドレスを確定する必要がある場合には、この関数まで遅延することがあります。
WSAEADDRNOTAVAIL
リモートアドレスが有効なアドレスではありません (ADDR_ANY など)。
WSAEAFNOSUPPORT
指定されたファミリのアドレスは、このソケットでは使用できません。
WSAEALREADY
指定されたソケットでノンブロッキングの WSAJoinLeaf 呼び出しが進行中です。
WSAECONNREFUSED
参加の試行が強制的に拒否されました。
WSAEFAULT
name または namelen パラメーターがユーザーアドレス空間の有効な部分ではない、namelen パラメーターが小さすぎる、lpCalleeDatalpSQOSlpGQOS のバッファー長が小さすぎる、または lpCallerData のバッファー長が大きすぎます。
WSAEINVAL
WSA_FLAG_MULTIPOINT_C_LEAF または WSA_FLAG_MULTIPOINT_D_LEAF マルチポイントフラグを設定せずに開かれた UDP ソケットに対して WSAJoinLeaf 関数が呼び出されました。
WSAEISCONN
ソケットは既にマルチポイントセッションのメンバーです。
WSAEINTR
ブロッキングの Windows Socket 1.1 呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEINPROGRESS
ブロッキングの Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理しています。
WSAENETDOWN
ネットワークサブシステムに障害が発生しました。
WSAENETUNREACH
現時点でこのホストからネットワークに到達できません。
WSAENOBUFS
利用可能なバッファー領域がありません。ソケットを参加させることができません。
WSAENOTSOCK
記述子がソケットではありません。
WSAEOPNOTSUPP
lpSQOS および lpGQOS で指定された FLOWSPEC 構造体を満たすことができません。
WSAEPROTONOSUPPORT
lpCallerData 引数はサービスプロバイダーでサポートされていません。
WSAETIMEDOUT
マルチポイントセッションを確立できないまま、参加の試行がタイムアウトしました。

解説(Remarks)

WSAJoinLeaf 関数は、リーフノードをマルチポイントセッションに参加させるために使用されるほか、セッション参加時に発生するその他の補助的な操作を多数実行します。ソケット s がバインドされていない場合、システムによってローカルの関連付けに一意の値が割り当てられ、ソケットはバインド済みとしてマークされます。

WSAJoinLeaf 関数は、ソケット記述子を返す点 ( WSAAccept と同様) と、追加の dwFlags パラメーターを持つ点を除き、 WSAConnect と同じパラメーターおよびセマンティクスを持ちます。この関数の入力パラメーター s として使用できるのは、適切なマルチポイントフラグを設定して WSASocket で作成されたマルチポイントソケットのみです。返されたソケット記述子は、参加操作が完了するまで使用できません。たとえば、ソケットがノンブロッキングモードの場合は、元のソケット s に対して WSAAsyncSelect または WSAEventSelect から対応する FD_CONNECT 通知を受け取った後に使用できます。ただし、保留中の参加操作をキャンセルするために、この新しいソケット記述子に対して closesocket を呼び出すことはできます。マルチポイントセッションの root アプリケーションは、複数のリーフノードを追加するために WSAJoinLeaf を 1 回以上呼び出すことができますが、一度に未完了にできるマルチポイント接続要求は最大 1 つです。詳細については、 Multipoint and Multicast Semantics を参照してください。

ノンブロッキングソケットでは、接続を即座に完了できないことがよくあります。その場合、この関数はまだ使用できないソケット記述子を返し、操作は続行されます。この場合、関数は実質的に開始成功を示しているため、 WSAEWOULDBLOCK のようなエラーコードは発生しません。最終的な成否が判明すると、クライアントが元のソケット s での通知をどのように登録しているかに応じて、 WSAAsyncSelect または WSAEventSelect を通じて報告されることがあります。いずれの場合も、通知は FD_CONNECT で通知され、FD_CONNECT に関連付けられたエラーコードが成功または失敗の具体的な理由を示します。 select 関数は、 WSAJoinLeaf の完了通知を検出するために使用することはできません。

WSAJoinLeaf が返すソケット記述子は、入力ソケット記述子 s が c_root か c_leaf かによって異なります。c_root ソケットで使用される場合、name パラメーターは追加する特定のリーフノードを指定し、返されるソケット記述子は新しく追加されたリーフノードに対応する c_leaf ソケットです。新しく作成されたソケットは、 WSAAsyncSelect または WSAEventSelect で登録された非同期イベントを含め、s と同じプロパティを持ちます。これはマルチポイントデータの交換に使用することを意図したものではなく、特定の c_leaf との間に存在する接続に対するネットワークイベント通知 (たとえば FD_CLOSE) を受信するために使用されます。一部のマルチポイント実装では、このソケットを root と個々のリーフノードとの間のサイドチャットに使用することも許可されています。対応するリーフノードがマルチポイントセッションから抜けるために closesocket を呼び出すと、このソケットに対して FD_CLOSE が通知されます。対称的に、 WSAJoinLeaf から返された c_leaf ソケットに対して closesocket を呼び出すと、対応するリーフノードのソケットが FD_CLOSE 通知を受け取ります。

WSAJoinLeaf が c_leaf ソケットで呼び出されると、name パラメーターには root アプリケーションのアドレス (ルート化された制御方式の場合) または既存のマルチポイントセッションのアドレス (非ルート化された制御方式の場合) が含まれ、返されるソケット記述子は入力ソケット記述子と同じになります。言い換えると、新しいソケット記述子は割り当てられません。ルート化された制御方式では、root アプリケーションは listen を呼び出して c_root ソケットをリッスンモードにします。リーフノードがマルチポイントセッションへの参加を要求すると、標準の FD_ACCEPT 通知が配信されます。root アプリケーションは、通常の accept または WSAAccept 関数を使用して新しいリーフノードを受け入れます。 accept または WSAAccept から返される値も、 WSAJoinLeaf から返されるものと同様の c_leaf ソケット記述子です。root が開始する参加とリーフが開始する参加の両方を許可するマルチポイント方式に対応するため、既にリッスンモードになっている c_root ソケットを WSAJoinLeaf の入力として使用することも許容されます。

アプリケーションは、指定するパラメーターが直接的または間接的に指すメモリ領域の割り当てに責任を負います。

lpCallerData は値パラメーターであり、マルチポイントセッションの参加要求とともに送信されるユーザーデータを含みます。lpCallerDataNULL の場合、ユーザーデータはピアに渡されません。lpCalleeData は結果パラメーターであり、マルチポイントセッション確立の一部としてピアから返されるユーザーデータを含みます。lpCalleeData パラメーターが指す WSABUF 構造体の len メンバーには、最初はアプリケーションが割り当てて WSABUF 構造体の buf メンバーが指すバッファーの長さが含まれます。ユーザーデータが返されなかった場合、lpCalleeData パラメーターが指す WSABUF 構造体の len メンバーはゼロに設定されます。lpCalleeData の情報は、マルチポイント参加操作が完了したときに有効になります。

ブロッキングソケットの場合、これは WSAJoinLeaf 関数が戻ったときです。ノンブロッキングソケットの場合、これは参加操作が完了した後です。たとえば、元のソケット s に対する FD_CONNECT 通知の後に発生する可能性があります。lpCalleeDataNULL の場合、ユーザーデータは返されません。ユーザーデータの正確な形式は、ソケットが属するアドレスファミリに固有です。

マルチポイントセッション確立時に、アプリケーションは lpSQOS または lpGQOS パラメーターを使用して、SIO_SET_QOS または SIO_SET_GROUP_QOS オペコードを指定した WSAIoctl によってソケットに対して以前に行われたサービス品質の指定を上書きできます。

lpSQOS パラメーターは、ソケット s に対する FLOWSPEC 構造体を各方向に 1 つずつ指定し、その後に任意の追加のプロバイダー固有パラメーターを続けます。関連するトランスポートプロバイダー全般、または特定の種類のソケットがサービス品質の要求を満たせない場合、以下に示すようにエラーが返されます。単方向ソケットの場合、それぞれの送信または受信のフロー仕様値は無視されます。プロバイダー固有パラメーターを指定しない場合、lpCalleeData パラメーターが指す WSABUF 構造体の buf および len メンバーは、それぞれ NULL とゼロに設定する必要があります。lpSQOSNULL 値は、アプリケーションが提供するサービス品質がないことを示します。

将来のソケットグループのために予約されています。lpGQOS パラメーターは、ソケットグループに対する FLOWSPEC 構造体 (該当する場合) を各方向に 1 つずつ指定し、その後に任意の追加のプロバイダー固有パラメーターを続けます。プロバイダー固有パラメーターを指定しない場合、lpCalleeData パラメーターが指す WSABUF 構造体の buf および len メンバーは、それぞれ NULL とゼロに設定する必要があります。lpGQOSNULL 値は、アプリケーションが提供するグループサービス品質がないことを示します。このパラメーターは、s がソケットグループの作成者でない場合は無視されます。

接続済みソケットが切断された場合 (すなわち、何らかの理由で閉じられた場合) は、それらを破棄して再作成する必要があります。接続済みソケットで何らかの理由により問題が発生した場合は、安定した状態に戻すために、アプリケーションが必要なソケットを破棄して再作成しなければならないと想定するのが最も安全です。

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

SOCKET WSAJoinLeaf(
    SOCKET s,
    const SOCKADDR* name,
    INT namelen,
    WSABUF* lpCallerData,   // optional
    WSABUF* lpCalleeData,   // optional
    QOS* lpSQOS,   // optional
    QOS* lpGQOS,   // optional
    DWORD dwFlags
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern UIntPtr WSAJoinLeaf(
    UIntPtr s,   // SOCKET
    IntPtr name,   // SOCKADDR*
    int namelen,   // INT
    IntPtr lpCallerData,   // WSABUF* optional
    IntPtr lpCalleeData,   // WSABUF* optional, out
    IntPtr lpSQOS,   // QOS* optional
    IntPtr lpGQOS,   // QOS* optional
    uint dwFlags   // DWORD
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function WSAJoinLeaf(
    s As UIntPtr,   ' SOCKET
    name As IntPtr,   ' SOCKADDR*
    namelen As Integer,   ' INT
    lpCallerData As IntPtr,   ' WSABUF* optional
    lpCalleeData As IntPtr,   ' WSABUF* optional, out
    lpSQOS As IntPtr,   ' QOS* optional
    lpGQOS As IntPtr,   ' QOS* optional
    dwFlags As UInteger   ' DWORD
) As UIntPtr
End Function
' s : SOCKET
' name : SOCKADDR*
' namelen : INT
' lpCallerData : WSABUF* optional
' lpCalleeData : WSABUF* optional, out
' lpSQOS : QOS* optional
' lpGQOS : QOS* optional
' dwFlags : DWORD
Declare PtrSafe Function WSAJoinLeaf Lib "ws2_32" ( _
    ByVal s As LongPtr, _
    ByVal name As LongPtr, _
    ByVal namelen As Long, _
    ByVal lpCallerData As LongPtr, _
    ByVal lpCalleeData As LongPtr, _
    ByVal lpSQOS As LongPtr, _
    ByVal lpGQOS As LongPtr, _
    ByVal dwFlags As Long) As LongPtr
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

WSAJoinLeaf = ctypes.windll.ws2_32.WSAJoinLeaf
WSAJoinLeaf.restype = ctypes.c_size_t
WSAJoinLeaf.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
    ctypes.c_void_p,  # name : SOCKADDR*
    ctypes.c_int,  # namelen : INT
    ctypes.c_void_p,  # lpCallerData : WSABUF* optional
    ctypes.c_void_p,  # lpCalleeData : WSABUF* optional, out
    ctypes.c_void_p,  # lpSQOS : QOS* optional
    ctypes.c_void_p,  # lpGQOS : QOS* optional
    wintypes.DWORD,  # dwFlags : DWORD
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

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

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procWSAJoinLeaf = ws2_32.NewProc("WSAJoinLeaf")
)

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

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

typedef WSAJoinLeafNative = UintPtr Function(UintPtr, Pointer<Void>, Int32, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Uint32);
typedef WSAJoinLeafDart = int Function(int, Pointer<Void>, int, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, int);
final WSAJoinLeaf = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<WSAJoinLeafNative, WSAJoinLeafDart>('WSAJoinLeaf');
// s : SOCKET -> UintPtr
// name : SOCKADDR* -> Pointer<Void>
// namelen : INT -> Int32
// lpCallerData : WSABUF* optional -> Pointer<Void>
// lpCalleeData : WSABUF* optional, out -> Pointer<Void>
// lpSQOS : QOS* optional -> Pointer<Void>
// lpGQOS : QOS* optional -> Pointer<Void>
// dwFlags : DWORD -> Uint32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function WSAJoinLeaf(
  s: NativeUInt;   // SOCKET
  name: Pointer;   // SOCKADDR*
  namelen: Integer;   // INT
  lpCallerData: Pointer;   // WSABUF* optional
  lpCalleeData: Pointer;   // WSABUF* optional, out
  lpSQOS: Pointer;   // QOS* optional
  lpGQOS: Pointer;   // QOS* optional
  dwFlags: DWORD   // DWORD
): NativeUInt; stdcall;
  external 'WS2_32.dll' name 'WSAJoinLeaf';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "WSAJoinLeaf"
  c_WSAJoinLeaf :: CUIntPtr -> Ptr () -> Int32 -> Ptr () -> Ptr () -> Ptr () -> Ptr () -> Word32 -> IO CUIntPtr
-- s : SOCKET -> CUIntPtr
-- name : SOCKADDR* -> Ptr ()
-- namelen : INT -> Int32
-- lpCallerData : WSABUF* optional -> Ptr ()
-- lpCalleeData : WSABUF* optional, out -> Ptr ()
-- lpSQOS : QOS* optional -> Ptr ()
-- lpGQOS : QOS* optional -> Ptr ()
-- dwFlags : DWORD -> Word32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let wsajoinleaf =
  foreign "WSAJoinLeaf"
    (size_t @-> (ptr void) @-> int32_t @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> uint32_t @-> returning size_t)
(* s : SOCKET -> size_t *)
(* name : SOCKADDR* -> (ptr void) *)
(* namelen : INT -> int32_t *)
(* lpCallerData : WSABUF* optional -> (ptr void) *)
(* lpCalleeData : WSABUF* optional, out -> (ptr void) *)
(* lpSQOS : QOS* optional -> (ptr void) *)
(* lpGQOS : QOS* optional -> (ptr void) *)
(* dwFlags : DWORD -> uint32_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 ("WSAJoinLeaf" wsajoin-leaf :convention :stdcall) :uint64
  (s :uint64)   ; SOCKET
  (name :pointer)   ; SOCKADDR*
  (namelen :int32)   ; INT
  (lp-caller-data :pointer)   ; WSABUF* optional
  (lp-callee-data :pointer)   ; WSABUF* optional, out
  (lp-sqos :pointer)   ; QOS* optional
  (lp-gqos :pointer)   ; QOS* optional
  (dw-flags :uint32))   ; DWORD
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $WSAJoinLeaf = Win32::API::More->new('WS2_32',
    'WPARAM WSAJoinLeaf(WPARAM s, LPVOID name, int namelen, LPVOID lpCallerData, LPVOID lpCalleeData, LPVOID lpSQOS, LPVOID lpGQOS, DWORD dwFlags)');
# my $ret = $WSAJoinLeaf->Call($s, $name, $namelen, $lpCallerData, $lpCalleeData, $lpSQOS, $lpGQOS, $dwFlags);
# s : SOCKET -> WPARAM
# name : SOCKADDR* -> LPVOID
# namelen : INT -> int
# lpCallerData : WSABUF* optional -> LPVOID
# lpCalleeData : WSABUF* optional, out -> LPVOID
# lpSQOS : QOS* optional -> LPVOID
# lpGQOS : QOS* optional -> LPVOID
# dwFlags : DWORD -> DWORD
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

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