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

GetAddrInfoExA

関数
名前を非同期や拡張オプション付きでアドレス解決する。
DLLWS2_32.dll文字セットANSI (-A)呼出規約winapi対応OSWindows Vista 以降

シグネチャ

// WS2_32.dll  (ANSI / -A)
#include <windows.h>

INT GetAddrInfoExA(
    LPCSTR pName,   // optional
    LPCSTR pServiceName,   // optional
    DWORD dwNameSpace,
    GUID* lpNspId,   // optional
    const ADDRINFOEXA* hints,   // optional
    ADDRINFOEXA** ppResult,
    TIMEVAL* timeout,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,   // optional
    HANDLE* lpNameHandle   // optional
);

パラメーター

名前方向説明
pNameLPCSTRinoptionalホスト(ノード)名または数値形式のホストアドレス文字列を含む NULL 終端文字列へのポインター。インターネットプロトコルの場合、数値形式のホストアドレス文字列はドット区切りの 10 進 IPv4 アドレス、または 16 進表記の IPv6 アドレスです。
pServiceNameLPCSTRinoptional

サービス名またはポート番号を文字列として表したものを含む、省略可能な NULL 終端文字列へのポインター。

サービス名はポート番号に対する文字列のエイリアスです。たとえば “http” は、HTTP プロトコル用に Web サーバーが使用する既定のポートとして Internet Engineering Task Force (IETF) が定義したポート 80 のエイリアスです。ポート番号が指定されない場合に pServiceName パラメーターに指定可能な値は、次のファイルに記載されています。

%WINDIR%\system32\drivers\etc\services

dwNameSpaceDWORDin

どのネームスペースプロバイダーに問い合わせるかを決定する、省略可能なネームスペース識別子。特定のネームスペース識別子を渡すと、指定したネームスペースをサポートするネームスペースプロバイダーのみが問い合わせ対象となります。NS_ALL を指定すると、インストール済みでアクティブなすべてのネームスペースプロバイダーが問い合わせ対象となります。

dwNameSpace パラメーターのオプションは Winsock2.h インクルードファイルに記載されています。Windows Vista 以降では複数のネームスペースプロバイダーが追加されています。他のネームスペースプロバイダーをインストールすることもできるため、次に挙げる値は一般的に利用可能なものに過ぎません。これ以外にも多くの値が存在し得ます。

意味
NS_ALL
0
インストール済みでアクティブなすべてのネームスペース。
NS_DNS
12
ドメインネームシステム (DNS) ネームスペース。
NS_NETBT
13
NetBIOS over TCP/IP (NETBT) ネームスペース。
NS_WINS
14
Windows Internet Naming Service (NS_WINS) ネームスペース。
NS_NLA
15
ネットワークロケーション認識 (NLA) ネームスペース。

このネームスペース識別子は Windows XP 以降でサポートされます。

NS_BTH
16
Bluetooth ネームスペース。

このネームスペース識別子は Windows Vista 以降でサポートされます。

NS_NTDS
32
Windows NT Directory Services (NS_NTDS) ネームスペース。
NS_EMAIL
37
電子メールネームスペース。

このネームスペース識別子は Windows Vista 以降でサポートされます。

NS_PNRPNAME
38
特定のピア名に対するピアツーピアネームスペース。

このネームスペース識別子は Windows Vista 以降でサポートされます。

NS_PNRPCLOUD
39
ピア名の集合に対するピアツーピアネームスペース。

このネームスペース識別子は Windows Vista 以降でサポートされます。

lpNspIdGUID*inoptionalNS_DNS のような単一のネームスペースに複数のネームスペースプロバイダーが登録されている場合に、問い合わせる特定のネームスペースプロバイダーの GUID を指す省略可能なポインター。特定のネームスペースプロバイダーの GUID を渡すと、指定したネームスペースプロバイダーのみが問い合わせ対象となります。ネームスペースプロバイダーの GUID は WSAEnumNameSpaceProviders 関数を呼び出して取得できます。
hintsADDRINFOEXA*inoptional

呼び出し元がサポートするソケットの種類に関するヒントを提供する addrinfoex 構造体へのポインター。

pHints パラメーターが指す addrinfoex 構造体の ai_addrlenai_canonnameai_addrai_next の各メンバーは 0 または NULL でなければなりません。そうでない場合、GetAddrInfoEx 関数は WSANO_RECOVERY で失敗します。

詳細は「解説」を参照してください。

ppResultADDRINFOEXA**outホストに関する応答情報を含む 1 つ以上の addrinfoex 構造体の連結リストへのポインター。
timeoutTIMEVAL*inoptional

呼び出しを中止するまでにネームスペースプロバイダーからの応答を待機する時間をミリ秒単位で示す、省略可能なパラメーター。

このパラメーターは、GetAddrInfoEx 関数を呼び出す前にソースコードで UNICODE または _UNICODE マクロが定義されている場合にのみサポートされます。それ以外の場合、timeout オプションはサポートされないため、このパラメーターは現在予約されており、NULL に設定する必要があります。

lpOverlappedOVERLAPPED*inoptional

非同期操作に使用するオーバーラップ構造体への省略可能なポインター。

このパラメーターは、GetAddrInfoEx 関数を呼び出す前にソースコードで UNICODE または _UNICODE マクロが定義されている場合にのみサポートされます。

Windows 8 および Windows Server 2012 では、lpCompletionRoutine パラメーターが指定されない場合、非同期呼び出しの完了時に呼び出される手動リセットイベントを OVERLAPPED 構造体の hEvent メンバーに設定する必要があります。完了ルーチンが指定されている場合は、hEvent メンバーを NULL にする必要があります。hEvent で指定したイベントがシグナル状態になると、GetAddrInfoExOverlappedResult 関数を呼び出して操作の結果を取得できます。

Windows 8 および Windows Server 2012 では、UNICODE または _UNICODE マクロが定義されていない場合は常に、このパラメーターは現在予約されており、NULL に設定する必要があります。

Windows 7 および Windows Server 2008 R2 以前では、非同期操作がサポートされないため、このパラメーターは現在予約されており、NULL に設定する必要があります。

lpCompletionRoutineLPLOOKUPSERVICE_COMPLETION_ROUTINEinoptional

非同期操作が正常に完了したときに呼び出される関数への省略可能なポインター。

このパラメーターは、GetAddrInfoEx 関数を呼び出す前にソースコードで UNICODE または _UNICODE マクロが定義されている場合にのみサポートされます。

このパラメーターを指定する場合、次のシグネチャを持つ関数へのポインターでなければなりません。

typedef   
void   
(CALLBACK * LPLOOKUPSERVICE_COMPLETION_ROUTINE)(   
    __in      DWORD    dwError,   
    __in      DWORD    dwBytes,   
    __in      LPWSAOVERLAPPED lpOverlapped   
    );   

非同期操作が完了すると、完了ルーチンが呼び出され、その lpOverlapped パラメーターには GetAddrInfoEx に渡した lpOverlapped パラメーターの値が設定されます。OVERLAPPED 構造体の Pointer メンバーには、元の呼び出しの ppResult パラメーターの値が設定されます。Pointer メンバーが addrinfoex 構造体への非 NULL ポインターを指している場合、FreeAddrInfoEx を呼び出して addrinfoex 構造体を解放するのは呼び出し元の責任です。完了ルーチンに渡される dwError パラメーターには Winsock エラーコードが設定されます。dwBytes パラメーターは将来の使用のために予約されており、無視する必要があります。

Windows 8 および Windows Server 2012 では、UNICODE または _UNICODE マクロが定義されていない場合は常に、このパラメーターは現在予約されており、NULL に設定する必要があります。

Windows 7 および Windows Server 2008 R2 以前では、非同期操作がサポートされないため、このパラメーターは現在予約されており、NULL に設定する必要があります。

lpNameHandleHANDLE*outoptional

非同期操作にのみ使用される省略可能なポインター。

このパラメーターは、GetAddrInfoEx 関数を呼び出す前にソースコードで UNICODE または _UNICODE マクロが定義されている場合にのみサポートされます。

Windows 8 および Windows Server 2012 では、GetAddrInfoEx 関数が非同期に完了する場合、このフィールドで返されるポインターを GetAddrInfoExCancel 関数で使用できます。返されるハンドルは、GetAddrInfoEx が戻ってから、完了ルーチンが呼び出されるか、イベントがトリガーされるか、またはこのハンドルを指定して GetAddrInfoExCancel 関数が呼び出されるまで有効です。

Windows 8 および Windows Server 2012 では、UNICODE または _UNICODE マクロが定義されていない場合は常に、このパラメーターは現在予約されており、NULL に設定する必要があります。

Windows 7 および Windows Server 2008 R2 以前では、非同期操作がサポートされないため、このパラメーターは現在予約されており、NULL に設定する必要があります。

戻り値の型: INT

公式ドキュメント

プロトコルに依存しない名前解決を提供し、どのネームスペースプロバイダーが要求を処理するかを指定する追加パラメーターを備えています。(ANSI)

戻り値

成功した場合、GetAddrInfoExNO_ERROR (0) を返します。失敗した場合は、 Windows Sockets エラーコードに記載されている 0 以外の Windows Sockets エラーコードを返します。

GetAddrInfoEx 関数が返す 0 以外のエラーコードのほとんどは、Internet Engineering Task Force (IETF) の推奨に概説されたエラーの集合に対応しています。次の表は、これらのエラーコードとその WSA 相当を示します。WSA エラーコードは Winsock プログラマーにとってなじみがあり包括的なエラー情報を提供するため、WSA エラーコードの使用を推奨します。

エラー値 WSA 相当 説明
EAI_AGAIN WSATRY_AGAIN 名前解決で一時的な障害が発生しました。
EAI_BADFLAGS WSAEINVAL 無効なパラメーターが指定されました。このエラーは、予約済みパラメーターのいずれかが NULL でない場合に返されます。また、pHints パラメーターの ai_flags メンバーに無効な値が指定された場合にも返されます。
EAI_FAIL WSANO_RECOVERY 名前解決で回復不能な障害が発生しました。
EAI_FAMILY WSAEAFNOSUPPORT pHints パラメーターの ai_family メンバーがサポートされていません。
EAI_MEMORY WSA_NOT_ENOUGH_MEMORY メモリの割り当てに失敗しました。
EAI_NONAME WSAHOST_NOT_FOUND 指定されたパラメーターで名前が解決されないか、pName および pServiceName パラメーターが指定されませんでした。
EAI_SERVICE WSATYPE_NOT_FOUND pServiceName パラメーターが、pHints パラメーターで指定された ai_socktype メンバーに対してサポートされていません。
EAI_SOCKTYPE WSAESOCKTNOSUPPORT pHints パラメーターの ai_socktype メンバーがサポートされていません。

GetAddrInfoEx 関数が返す EAI コードに基づいてエラーメッセージを出力するには、 gai_strerror 関数を使用します。 gai_strerror 関数は IETF の推奨への準拠のために提供されていますが、スレッドセーフではありません。そのため、 WSAGetLastError などの従来の Windows Sockets 関数の使用を推奨します。

エラーコード 意味
WSA_NOT_ENOUGH_MEMORY
操作を実行するためのメモリが不足していました。
WSAEAFNOSUPPORT
要求されたプロトコルと互換性のないアドレスが使用されました。このエラーは、pHints パラメーターが指す addrinfoex 構造体の ai_family メンバーがサポートされていない場合に返されます。
WSAEINVAL
無効な引数が指定されました。このエラーは、pHints パラメーターが指す addrinfoex 構造体の ai_flags メンバーに無効な値が指定された場合に返されます。また、dwNameSpace パラメーターが NS_PNRPNAME または NS_PNRPCLOUD であり、ピアツーピアネームサービスが動作していない場合にも返されます。
WSAESOCKTNOSUPPORT
指定されたソケットの種類に対するサポートが、このアドレスファミリーには存在しません。このエラーは、pHints パラメーターが指す addrinfoex 構造体の ai_socktype メンバーがサポートされていない場合に返されます。
WSAHOST_NOT_FOUND
そのようなホストは認識されていません。このエラーは、指定されたパラメーターで名前が解決されないか、pName および pServiceName パラメーターが指定されなかった場合に返されます。
WSANO_DATA
要求された名前は有効ですが、要求された種類のデータが見つかりませんでした。
WSANO_RECOVERY
データベース検索中に回復不能なエラーが発生しました。このエラーは、名前解決で回復不能なエラーが発生した場合に返されます。
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSASERVICE_NOT_FOUND
そのようなサービスは認識されていません。指定されたネームスペースでサービスが見つかりません。このエラーは、dwNameSpace パラメーターで指定されたネームスペースに対して pName または pServiceName パラメーターが見つからない場合、または dwNameSpace パラメーターで指定されたネームスペースがインストールされていない場合に返されます。
WSATRY_AGAIN
これは通常、ホスト名解決中の一時的なエラーであり、ローカルサーバーが権威サーバーから応答を受け取らなかったことを意味します。このエラーは、名前解決で一時的な障害が発生した場合に返されます。
WSATYPE_NOT_FOUND
指定されたクラスが見つかりませんでした。pServiceName パラメーターは、pHints パラメーターが指す addrinfoex 構造体の指定された ai_socktype メンバーに対してサポートされていません。

解説(Remarks)

GetAddrInfoEx 関数は、ホスト名からアドレスへ、およびサービス名からポート番号へのプロトコルに依存しない変換を提供します。GetAddrInfoEx 関数は、getaddrinfo および GetAddrInfoW 関数の拡張版です。GetAddrInfoEx 関数では、クエリを解決するネームスペースプロバイダーを指定できます。

GetAddrInfoEx 関数は、特定のネームスペースプロバイダーが指定されていない限り、複数のネームスペースプロバイダーからの結果を集約して返します。IPv6 および IPv4 プロトコルで使用する場合、名前解決はドメインネームシステム (DNS)、ローカルの hosts ファイル、電子メールプロバイダー (NS_EMAIL ネームスペース)、またはその他の名前付けメカニズムによって行われます。

UNICODE または _UNICODE が定義されている場合、GetAddrInfoEx はこの関数の Unicode 版である GetAddrInfoExW に定義されます。文字列パラメーターは PWSTR データ型に定義され、ADDRINFOEXW 構造体が使用されます。Windows 8 および Windows Server 2012 では、timeoutlpOverlappedlpCompletionRoutinelpNameHandle の各パラメーターを使用して GetAddrInfoEx 関数を呼び出すことで、非同期に完了させることができます。

UNICODE または _UNICODE が定義されていない場合、GetAddrInfoEx はこの関数の ANSI 版である GetAddrInfoExA に定義されます。文字列パラメーターは PCSTR データ型となり、ADDRINFOEXA 構造体が使用されます。timeoutlpOverlappedlpCompletionRoutinelpNameHandle の各パラメーターは NULL に設定する必要があります。

pName または pServiceName パラメーターの一方または両方が NULL 終端文字列を指している必要があります。通常は両方が指定されます。

成功すると、 addrinfoex 構造体の連結リストが ppResult パラメーターに返されます。このリストは、返された各 addrinfoex 構造体の ai_next メンバーが提供するポインターを NULL ポインターに達するまでたどることで処理できます。返された各 addrinfoex 構造体では、ai_familyai_socktypeai_protocol の各メンバーが、 socket または WSASocket 関数呼び出しの対応する引数に対応します。また、返された各 addrinfoex 構造体の ai_addr メンバーは、内容が設定されたソケットアドレス構造体を指し、その長さは ai_addrlen メンバーで指定されます。

pName パラメーターがコンピューター名を指している場合、送信元アドレスとして使用できる、そのコンピューターのすべての永続アドレスが返されます。Windows Vista 以降では、これらのアドレスには、MIB_UNICASTIPADDRESS_ROW 構造体の SkipAsSource メンバーが false に設定されている、GetUnicastIpAddressTable または GetUnicastIpAddressEntry 関数が返すすべてのユニキャスト IP アドレスが含まれます。

pName パラメーターが "localhost" に等しい文字列を指している場合、ローカルコンピューター上のすべてのループバックアドレスが返されます。

pName パラメーターが空文字列を含む場合、ローカルコンピューター上に登録されているすべてのアドレスが返されます。

Windows Server 2003 以降では、pName パラメーターが "..localmachine" に等しい文字列を指している場合、ローカルコンピューター上に登録されているすべてのアドレスが返されます。

pName パラメーターがクラスター仮想サーバー名を参照している場合、仮想サーバーアドレスのみが返されます。Windows Vista 以降では、これらのアドレスには、MIB_UNICASTIPADDRESS_ROW 構造体の SkipAsSource メンバーが true に設定されている、GetUnicastIpAddressTable または GetUnicastIpAddressEntry 関数が返すすべてのユニキャスト IP アドレスが含まれます。クラスタリングの詳細については、Windows Clustering を参照してください。

Windows 7 Service Pack 1 (SP1) および Windows Server 2008 R2 Service Pack 1 (SP1) では、IP アドレスに SkipAsSource 属性を設定するためのサポートが Netsh.exe に追加されています。これにより、MIB_UNICASTIPADDRESS_ROW 構造体の SkipAsSource メンバーが false に設定されている場合は IP アドレスが DNS に登録されるという動作にも変わります。SkipAsSource メンバーが true に設定されている場合、IP アドレスは DNS に登録されません。

Windows 7 および Windows Server 2008 R2 には、IP アドレスに SkipAsSource 属性を設定するためのサポートを Netsh.exe に追加する修正プログラムが用意されています。この修正プログラムも、MIB_UNICASTIPADDRESS_ROW 構造体の SkipAsSource メンバーが false に設定されている場合は IP アドレスが DNS に登録されるという動作に変更します。SkipAsSource メンバーが true に設定されている場合、IP アドレスは DNS に登録されません。詳細については、サポート技術情報 (KB) 2386184 を参照してください。

Windows Vista Service Pack 2 (SP2) および Windows Server 2008 Service Pack 2 (SP2) にも、IP アドレスに SkipAsSource 属性を設定するためのサポートを Netsh.exe に追加する同様の修正プログラムが用意されています。この修正プログラムも、MIB_UNICASTIPADDRESS_ROW 構造体の SkipAsSource メンバーが false に設定されている場合は IP アドレスが DNS に登録されるという動作に変更します。SkipAsSource メンバーが true に設定されている場合、IP アドレスは DNS に登録されません。

GetAddrInfoEx 関数の呼び出し元は、pHints パラメーターが指す addrinfoex 構造体を通じて、サポートするソケットの種類に関するヒントを提供できます。pHints パラメーターを使用する場合、それに関連付けられた addrinfoex 構造体には次の規則が適用されます。

pHints パラメーターで提供される addrinfoex 構造体のその他の値は、特定の要件を示します。たとえば、呼び出し元が IPv4 のみを扱い IPv6 を扱わない場合は、ai_family メンバーを AF_INET に設定します。別の例として、呼び出し元が TCP のみを扱い UDP を扱わない場合は、ai_socktype メンバーを SOCK_STREAM に設定します。

pHints パラメーターが NULL ポインターの場合、 GetAddrInfoEx 関数は、pHintsaddrinfoex 構造体が ai_family メンバーを AF_UNSPEC に、その他のすべてのメンバーを NULL または 0 に初期化された状態であるかのように扱います。

GetAddrInfoEx がサービスから呼び出される場合、その操作がユーザープロセスによるサービス呼び出しの結果であれば、サービスはユーザーを偽装する必要があります。これはセキュリティを適切に適用できるようにするためです。

GetAddrInfoEx 関数は、IP アドレスのテキスト文字列表現を、その IP アドレスの sockaddr 構造体やその他の情報を含む addrinfoex 構造体に変換するために使用できます。このように使用するには、pName パラメーターが指す文字列に IP アドレスのテキスト表現が含まれ、かつ pHints パラメーターが指す addrinfoex 構造体の ai_flags メンバーに AI_NUMERICHOST フラグが設定されている必要があります。pName パラメーターが指す文字列には、IPv4 または IPv6 アドレスのいずれかのテキスト表現を含めることができます。テキスト IP アドレスは、ppResult パラメーターが指す addrinfoex 構造体に変換されます。返される addrinfoex 構造体には、IP アドレス用の sockaddr 構造体と、その IP アドレスに関する追加情報が含まれます。

ローカルコンピューターには、同一のネームスペースに対して複数のネームスペースプロバイダーがインストールされている場合があります。たとえば、基本的な Windows TCP/IP ネットワークソフトウェアは NS_DNS ネームスペースに登録します。Microsoft Forefront Threat Management Gateway (TMG) や、より古い Microsoft Internet Security and Acceleration (ISA) Server に含まれる Firewall Client ソフトウェアも NS_DNS ネームスペースに登録します。dwNameSpace パラメーターが値 (たとえば NS_DNS) に設定され、lpNspId パラメーターが NULL の場合、GetAddrInfoEx 関数が返す結果は、指定されたネームスペースに登録しているすべてのネームスペースプロバイダーからの結果を、重複を除去してマージしたものになります。単一のネームスペースプロバイダーのみを問い合わせる場合は、lpNspId パラメーターを特定のネームスペースプロバイダーの GUID に設定する必要があります。

pNameSpace パラメーターが NS_ALL に設定されている場合、すべてのネームスペースプロバイダーへの問い合わせ結果がマージされて返されます。この場合、複数のネームスペースプロバイダーが同じ情報を返すと、ppResult パラメーターが指す結果に重複した応答が返されることがあります。

Windows 8 および Windows Server 2012 では、GetAddrInfoEx 関数が非同期に完了する場合、lpNameHandle パラメーターで返されるポインターを GetAddrInfoExCancel 関数で使用できます。返されるハンドルは、GetAddrInfoEx が戻ってから、完了ルーチンが呼び出されるか、イベントがトリガーされるか、またはこのハンドルを指定して GetAddrInfoExCancel 関数が呼び出されるまで有効です。

動的に割り当てられたアドレス情報の解放

ppResult パラメーターが指す、 GetAddrInfoEx 関数が返すすべての情報は動的に割り当てられます。これには、すべての addrinfoex 構造体、ソケットアドレス構造体、および addrinfoex 構造体が指す正規ホスト名文字列が含まれます。この関数の呼び出しが成功して割り当てられたメモリは、その後 FreeAddrInfoEx を呼び出して解放する必要があります。

サンプルコード

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

#include <winsock2.h>
#include <ws2tcpip.h>
#include <objbase.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")

// Need to link with Ole32.lib to print GUID
#pragma comment(lib, "ole32.lib")

int __cdecl wmain(int argc, wchar_t ** argv)
{

    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult;

    DWORD dwRetval;

    int i = 1;

    DWORD dwNamespace = NS_ALL;
    LPGUID lpNspid = NULL;

    ADDRINFOEX *result = NULL;
    ADDRINFOEX *ptr = NULL;
    ADDRINFOEX hints;

    // LPSOCKADDR sockaddr_ip;
    struct sockaddr_in *sockaddr_ipv4;
    struct sockaddr_in6 *sockaddr_ipv6;

    // DWORD ipbufferlength = 46;
    wchar_t ipstringbuffer[46];

    // variables needed to print namespace provider GUID
    int iRet = 0;
    WCHAR GuidString[40] = { 0 };

    // Validate the parameters
    if (argc != 4) {
        wprintf(L"usage: %ws <hostname> <servicename> <namespace>\n", argv[0]);
        wprintf(L"getaddrinfoex provides protocol-independent translation\n");
        wprintf(L"   from a host name to an IP address\n");
        wprintf(L"%ws example usage\n", argv[0]);
        wprintf(L"   %ws www.contoso.com 0 12\n", argv[0]);
        wprintf(L"   looks up the www.contoso.com in the NS_DNS namespace\n",
                argv[0]);
        return 1;
    }
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }
    //--------------------------------
    // Setup the hints address info structure
    // which is passed to the getaddrinfo() function
    ZeroMemory(&hints, sizeof (hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    dwNamespace = (DWORD) _wtoi(argv[3]);

    wprintf(L"Calling GetAddrInfoEx with following parameters:\n");
    wprintf(L"\tName = %ws\n", argv[1]);
    wprintf(L"\tServiceName (or port) = %ws\n", argv[2]);
    wprintf(L"\tNamespace = %s (", argv[3]);
    switch (dwNamespace) {
    case NS_ALL:
        wprintf(L"(NS_ALL)\n");
        break;
    case NS_DNS:
        wprintf(L"(NS_DNS)\n");
        break;
    case NS_NETBT:
        wprintf(L"NS_NETBT");
        break;
    case NS_WINS:
        wprintf(L"NS_WINS");
        break;
    case NS_NLA:
        wprintf(L"NS_NLA");
        break;
    case NS_BTH:
        wprintf(L"NS_BTH");
        break;
    case NS_NTDS:
        wprintf(L"NS_NTDS");
        break;
    case NS_EMAIL:
        wprintf(L"NS_EMAIL");
        break;
    case NS_PNRPNAME:
        wprintf(L"NS_PNRPNAME");
        break;
    case NS_PNRPCLOUD:
        wprintf(L"NS_PNRPCLOUD");
        break;
    default:
        wprintf(L"Other");
        break;
    }
    wprintf(L")\n\n");

//--------------------------------
// Call getaddrinfoex(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
    dwRetval =
        GetAddrInfoEx(argv[1], argv[2], dwNamespace, lpNspid, &hints, &result,
                      NULL, NULL, NULL, NULL);
    if (dwRetval != 0) {
        wprintf(L"GetAddrInfoEx failed with error: %d\n", dwRetval);
        WSACleanup();
        return 1;
    }

    wprintf(L"GetAddrInfoEx returned success\n");

    // Retrieve each address and print out the hex bytes
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        wprintf(L"GetAddrInfoEx response %d\n", i++);
        wprintf(L"\tFlags: 0x%x\n", ptr->ai_flags);
        wprintf(L"\tFamily: ");
        switch (ptr->ai_family) {
        case AF_UNSPEC:
            wprintf(L"Unspecified\n");
            break;
        case AF_INET:
            wprintf(L"AF_INET (IPv4)\n");
            // the InetNtop function is available on Windows Vista and later
            sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
            wprintf(L"\tIPv4 address %ws\n",
                    InetNtop(AF_INET, &sockaddr_ipv4->sin_addr, ipstringbuffer,
                             46));

            // We could also use the WSAAddressToString function
            // sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
            // The buffer length is changed by each call to WSAAddresstoString
            // So we need to set it for each iteration through the loop for safety
            // ipbufferlength = 46;
            // iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, 
            //    ipstringbuffer, &ipbufferlength );
            // if (iRetval)
            //    wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
            // else    
            //    wprintf(L"\tIPv4 address %ws\n", ipstringbuffer);
            break;
        case AF_INET6:
            wprintf(L"AF_INET6 (IPv6)\n");
            // the InetNtop function is available on Windows Vista and later
            sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
            wprintf(L"\tIPv6 address %ws\n",
                    InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr,
                             ipstringbuffer, 46));

            // We could also use WSAAddressToString which also returns the scope ID
            // sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
            // The buffer length is changed by each call to WSAAddresstoString
            // So we need to set it for each iteration through the loop for safety
            // ipbufferlength = 46;
            //iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, 
            //    ipstringbuffer, &ipbufferlength );
            //if (iRetval)
            //    wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
            //else    
            //    wprintf(L"\tIPv6 address %ws\n", ipstringbuffer);
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_family);
            break;
        }
        wprintf(L"\tSocket type: ");
        switch (ptr->ai_socktype) {
        case 0:
            wprintf(L"Unspecified\n");
            break;
        case SOCK_STREAM:
            wprintf(L"SOCK_STREAM (stream)\n");
            break;
        case SOCK_DGRAM:
            wprintf(L"SOCK_DGRAM (datagram) \n");
            break;
        case SOCK_RAW:
            wprintf(L"SOCK_RAW (raw) \n");
            break;
        case SOCK_RDM:
            wprintf(L"SOCK_RDM (reliable message datagram)\n");
            break;
        case SOCK_SEQPACKET:
            wprintf(L"SOCK_SEQPACKET (pseudo-stream packet)\n");
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_socktype);
            break;
        }
        wprintf(L"\tProtocol: ");
        switch (ptr->ai_protocol) {
        case 0:
            wprintf(L"Unspecified\n");
            break;
        case IPPROTO_TCP:
            wprintf(L"IPPROTO_TCP (TCP)\n");
            break;
        case IPPROTO_UDP:
            wprintf(L"IPPROTO_UDP (UDP) \n");
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_protocol);
            break;
        }
        wprintf(L"\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
        wprintf(L"\tCanonical name: %s\n", ptr->ai_canonname);

        if (ptr->ai_blob == NULL)
            wprintf(L"\tBlob: (null)\n");
        else    
            wprintf(L"\tLength of the blob: %u\n",
                    (DWORD) ptr->ai_bloblen);

        if (ptr->ai_provider == NULL)
            wprintf(L"\tNamespace provider GUID: (null)\n");
        else {
            iRet =
                StringFromGUID2(*(ptr->ai_provider), (LPOLESTR) & GuidString,
                                39);
            // For c rather than C++ source code, the above line needs to be
            // iRet = StringFromGUID2(&ptr.ai_provider, (LPOLESTR) &GuidString, 39); 
            if (iRet == 0)
                wprintf(L"StringFromGUID2 failed\n");
            else {
                wprintf(L"\tNamespace provider: %ws\n", GuidString);
            }
        }
    }

    FreeAddrInfoEx(result);
    WSACleanup();

    return 0;
}

次の例は、GetAddrInfoEx 関数を非同期で使用して名前を IP アドレスに解決する方法を示しています。

//
//    This sample demonstrates how to use asynchronous GetAddrInfoEx to
//    resolve a name to an IP address.
//
//    ResolveName <QueryName>
//

#ifndef UNICODE
#define UNICODE
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")

#define MAX_ADDRESS_STRING_LENGTH   64

//
//  Asynchronous query context structure.
//

typedef struct _QueryContext
{
    OVERLAPPED      QueryOverlapped;
    PADDRINFOEX     QueryResults;
    HANDLE          CompleteEvent;
}QUERY_CONTEXT, *PQUERY_CONTEXT;

VOID
WINAPI
QueryCompleteCallback(
    _In_ DWORD Error,
    _In_ DWORD Bytes,
    _In_ LPOVERLAPPED Overlapped
    );

int
__cdecl
wmain(
    _In_ int Argc, PWCHAR Argv[]
    )
{
    INT                 Error = ERROR_SUCCESS;
    WSADATA             wsaData;
    BOOL                IsWSAStartupCalled = FALSE;
    ADDRINFOEX          Hints;
    QUERY_CONTEXT       QueryContext;
    HANDLE              CancelHandle = NULL;
    DWORD               QueryTimeout = 5 * 1000; // 5 seconds

    ZeroMemory(&QueryContext, sizeof(QueryContext));

    //
    //  Validate the parameters
    //

    if (Argc != 2)
    {
        wprintf(L"Usage: ResolveName <QueryName>\n");
        goto exit;
    }

    //
    //  All Winsock functions require WSAStartup() to be called first
    //

    Error = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (Error != 0)
    {
        wprintf(L"WSAStartup failed with %d\n", Error);
        goto exit;
    }

    IsWSAStartupCalled = TRUE;

    ZeroMemory(&Hints, sizeof(Hints));
    Hints.ai_family = AF_UNSPEC;

    //
    //  Note that this is a simple sample that waits/cancels a single
    //  asynchronous query. The reader may extend this to support
    //  multiple asynchronous queries.
    //

    QueryContext.CompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    if (QueryContext.CompleteEvent == NULL)
    {
        Error = GetLastError();
        wprintf(L"Failed to create completion event: Error %d\n",  Error);
        goto exit;
    }

    //
    //  Initiate asynchronous GetAddrInfoExW.
    //
    //  Note GetAddrInfoEx can also be invoked asynchronously using an event
    //  in the overlapped object (Just set hEvent in the Overlapped object
    //  and set NULL as completion callback.)
    //
    //  This sample uses the completion callback method.
    //

    Error = GetAddrInfoExW(Argv[1],
                           NULL,
                           NS_DNS,
                           NULL,
                           &Hints,
                           &QueryContext.QueryResults,
                           NULL,
                           &QueryContext.QueryOverlapped,
                           QueryCompleteCallback,
                           &CancelHandle);

    //
    //  If GetAddrInfoExW() returns  WSA_IO_PENDING, GetAddrInfoExW will invoke
    //  the completion routine. If GetAddrInfoExW returned anything else we must
    //  invoke the completion directly.
    //

    if (Error != WSA_IO_PENDING)
    {
        QueryCompleteCallback(Error, 0, &QueryContext.QueryOverlapped);
        goto exit;
    }

    //
    //  Wait for query completion for 5 seconds and cancel the query if it has
    //  not yet completed.
    //

    if (WaitForSingleObject(QueryContext.CompleteEvent,
                            QueryTimeout)  == WAIT_TIMEOUT )
    {

        //
        //  Cancel the query: Note that the GetAddrInfoExCancelcancel call does
        //  not block, so we must wait for the completion routine to be invoked.
        //  If we fail to wait, WSACleanup() could be called while an
        //  asynchronous query is still in progress, possibly causing a crash.
        //

        wprintf(L"The query took longer than %d seconds to complete; "
                L"cancelling the query...\n", QueryTimeout/1000);

        GetAddrInfoExCancel(&CancelHandle);

        WaitForSingleObject(QueryContext.CompleteEvent,
                            INFINITE);
    }

exit:

    if (IsWSAStartupCalled)
    {
        WSACleanup();
    }

    if (QueryContext.CompleteEvent)
    {
        CloseHandle(QueryContext.CompleteEvent);
    }

    return Error;
}

//
// Callback function called by Winsock as part of asynchronous query complete
//

VOID
WINAPI
QueryCompleteCallback(
    _In_ DWORD Error,
    _In_ DWORD Bytes,
    _In_ LPOVERLAPPED Overlapped
    )
{
    PQUERY_CONTEXT  QueryContext = NULL;
    PADDRINFOEX     QueryResults = NULL;
    WCHAR           AddrString[MAX_ADDRESS_STRING_LENGTH];
    DWORD           AddressStringLength;

    UNREFERENCED_PARAMETER(Bytes);

    QueryContext = CONTAINING_RECORD(Overlapped,
                                     QUERY_CONTEXT,
                                     QueryOverlapped);

    if (Error != ERROR_SUCCESS)
    {
        wprintf(L"ResolveName failed with %d\n", Error);
        goto exit;
    }

    wprintf(L"ResolveName succeeded. Query Results:\n");

    QueryResults = QueryContext->QueryResults;

    while(QueryResults)
    {
        AddressStringLength = MAX_ADDRESS_STRING_LENGTH;

        WSAAddressToString(QueryResults->ai_addr,
                           (DWORD)QueryResults->ai_addrlen,
                           NULL,
                           AddrString,
                           &AddressStringLength);

        wprintf(L"Ip Address: %s\n", AddrString);
        QueryResults = QueryResults->ai_next;
    }

exit:

    if (QueryContext->QueryResults)
    {
        FreeAddrInfoEx(QueryContext->QueryResults);
    }

    //
    //  Notify caller that the query completed
    //

    SetEvent(QueryContext->CompleteEvent);
    return;
}
注意 開発環境が、addrinfoex および GetAddrInfoEx の構造体と関数の定義をそれぞれ含む最新バージョンの Ws2tcpip.h を対象としていることを確認してください。

国際化ドメイン名

インターネットのホスト名は、通常、非常に限られた文字の集合で構成されます。

インターネットの成長に伴い、ASCII 文字セットでは表現されない他の言語のインターネットホスト名を識別する必要性が高まっています。この必要性に対応し、非 ASCII 文字 (Unicode) を特別な ASCII 文字列として表現できるようにする識別子は、国際化ドメイン名 (IDN) と呼ばれます。IDN を標準的な方法で扱うために、アプリケーションにおけるドメイン名の国際化 (IDNA) と呼ばれるメカニズムが使用されます。IDN および IDNA の仕様は、Internet Engineering Task Force (IETF) が公開した RFC 3490RTF 5890RFC 6365 に文書化されています。

Windows 8 および Windows Server 2012 では、GetAddrInfoEx 関数は、pName パラメーターに渡された名前に対して適用される国際化ドメイン名 (IDN) の解析をサポートします。Winsock が Punycode/IDN のエンコードと変換を実行します。この動作は、以下で説明する AI_DISABLE_IDN_ENCODING フラグを使用して無効にできます。

Windows 7 および Windows Server 2008 R2 以前では、GetAddrInfoEx 関数は、pName パラメーターに渡された名前に対して適用される IDN の解析を現在サポートしていません。GetAddrInfoEx 関数のワイド文字版は、RFC 3490 に従って IDN を Punycode 形式に変換するために Punycode を使用しません。GetAddrInfoEx 関数のワイド文字版は、DNS を問い合わせる際、Unicode 名を、企業環境の Microsoft DNS サーバーで使用される UTF-8 形式でエンコードします。

Windows Vista 以降では、IDN 内の Unicode ラベルとその ASCII 相当の間の変換をサポートする関数がいくつかあります。各 Unicode ラベルの結果の表現は ASCII 文字のみを含み、Unicode ラベルに非 ASCII 文字が含まれていた場合は xn-- というプレフィックスで始まります。これは、一部の DNS ツールやサーバーが ASCII 文字のみをサポートしているため、インターネット上の既存の DNS サーバーをサポートする目的によるものです (RFC 3490 を参照)。

IdnToAscii 関数は、RFC 3490 で定義された標準アルゴリズムを使用して、元の Unicode 文字列の ASCII 表現に IDN を変換するために Punycode を使用します。IdnToUnicode 関数は、IDN の ASCII 形式を通常の Unicode UTF-16 エンコード構文に変換します。詳細および関連するドラフト標準へのリンクについては、Handling Internationalized Domain Names (IDNs) を参照してください。

IdnToAscii 関数を使用すると、IDN 名を ASCII 形式に変換でき、この関数の ANSI 版が使用される場合 (UNICODE および _UNICODE が定義されていない場合) に、その ASCII 形式を GetAddrInfoEx 関数の pName パラメーターに渡すことができます。この関数のワイド文字版が使用される場合 (UNICODE または _UNICODE が定義されている場合) にこの IDN 名を GetAddrInfoEx 関数に渡すには、MultiByteToWideChar 関数を使用して CHAR 文字列を WCHAR 文字列に変換できます。

hints パラメーターでの ai_flags の使用

hints パラメーターで提供される省略可能な addrinfoex 構造体の ai_flags メンバーのフラグは、関数の動作を変更します。

これらのフラグビットは、Windows 7 用 Microsoft Windows Software Development Kit (SDK) では Ws2def.h ヘッダーファイルで定義されています。Windows Server 2008 および Windows Vista 用 Windows SDK では、これらのフラグビットは Ws2tcpip.h ヘッダーファイルで定義されています。Windows Server 2003 および Windows XP 用 Platform Software Development Kit (SDK) では、これらのフラグビットは Ws2tcpip.h ヘッダーファイルで定義されています。

フラグビットには、次の値を組み合わせて指定できます。

フラグビット 説明
AI_PASSIVE AI_PASSIVE フラグを設定すると、呼び出し元が、返されたソケットアドレス構造体を bind 関数の呼び出しで使用する意図があることを示します。AI_PASSIVE フラグが設定され、かつ pNameNULL ポインターの場合、ソケットアドレス構造体の IP アドレス部分は、IPv4 アドレスでは INADDR_ANY に、IPv6 アドレスでは IN6ADDR_ANY_INIT に設定されます。

AI_PASSIVE フラグが設定されていない場合、返されたソケットアドレス構造体は、コネクション指向プロトコルでは connect 関数の呼び出しに、コネクションレスプロトコルでは connectsendtosend のいずれかの関数の呼び出しに使用できる状態になります。この場合に pName パラメーターが NULL ポインターであれば、ソケットアドレス構造体の IP アドレス部分はループバックアドレスに設定されます。

AI_CANONNAME AI_CANONNAMEAI_NUMERICHOST も使用されない場合、 GetAddrInfoEx 関数は解決を試みます。リテラル文字列が渡された場合、 GetAddrInfoEx はその文字列の変換を試み、ホスト名が渡された場合、 GetAddrInfoEx 関数はその名前を 1 つまたは複数のアドレスに解決しようとします。

AI_CANONNAME ビットが設定されている場合、pName パラメーターを NULL にすることはできません。そうでない場合、 GetAddrInfoEx 関数は WSANO_RECOVERY で失敗します。

AI_CANONNAME ビットが設定され、かつ GetAddrInfoEx 関数が成功を返す場合、ppResult パラメーター内の ai_canonname メンバーは、指定されたノードの正規名を含む NULL 終端文字列を指します。

注意 GetAddrInfoEx 関数は、AI_CANONNAME フラグが設定されている場合でも、関連する addrinfo 構造体の ai_canonname メンバーが NULL のまま成功を返すことがあります。そのため、AI_CANONNAME フラグを使用する際は、関連する addrinfoex 構造体の ai_canonname メンバーが NULL かどうかをテストすることが推奨されます。
AI_NUMERICHOST AI_NUMERICHOST ビットが設定されている場合、pName パラメーターは非 NULL の数値形式のホストアドレス文字列を含む必要があり、そうでない場合は EAI_NONAME エラーが返されます。このフラグは名前解決サービスの呼び出しを防止します。
AI_NUMERICSERV AI_NUMERICSERV ビットが設定されている場合、pServiceName パラメーターは非 NULL の数値形式のポート番号を含む必要があり、そうでない場合は EAI_NONAME エラーが返されます。このフラグは名前解決サービスの呼び出しを防止します。

AI_NUMERICSERV フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_NUMERICSERV フラグは Microsoft のプロバイダーではサポートされていません。

AI_ALL AI_ALL ビットが設定されている場合、IPv6 アドレスと、AI_V4MAPPED を伴う IPv4 アドレスの要求が行われます。

AI_ALL フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_ALL フラグは Windows Vista 以降でサポートされます。

AI_ADDRCONFIG AI_ADDRCONFIG ビットが設定されている場合、GetAddrInfoEx はグローバルアドレスが構成されている場合にのみ解決を行います。AI_ADDRCONFIG フラグが指定されている場合、IPv4 アドレスはローカルシステムに IPv4 アドレスが構成されている場合にのみ返され、IPv6 アドレスはローカルシステムに IPv6 アドレスが構成されている場合にのみ返されます。IPv4 または IPv6 のループバックアドレスは、有効なグローバルアドレスとは見なされません。

AI_ADDRCONFIG フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_ADDRCONFIG フラグは Windows Vista 以降でサポートされます。

AI_V4MAPPED AI_V4MAPPED ビットが設定されていて IPv6 アドレスの要求が失敗した場合、IPv4 アドレスに対する名前サービス要求が行われ、それらのアドレスは IPv4 マップ IPv6 アドレス形式に変換されます。

AI_V4MAPPED フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_V4MAPPED フラグは Windows Vista 以降でサポートされます。

AI_NON_AUTHORITATIVE AI_NON_AUTHORITATIVE ビットが設定されている場合、NS_EMAIL ネームスペースプロバイダーは権威ある結果と権威のない結果の両方を返します。AI_NON_AUTHORITATIVE ビットが設定されていない場合、NS_EMAIL ネームスペースプロバイダーは権威ある結果のみを返します。

AI_NON_AUTHORITATIVE フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_NON_AUTHORITATIVE フラグは Windows Vista 以降でサポートされ、NS_EMAIL ネームスペースにのみ適用されます。

AI_SECURE AI_SECURE ビットが設定されている場合、NS_EMAIL ネームスペースプロバイダーは、可能なスプーフィングを最小限に抑えるために強化されたセキュリティで取得された結果を返します。

AI_SECURE フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_SECURE フラグは Windows Vista 以降でサポートされ、NS_EMAIL ネームスペースにのみ適用されます。

AI_RETURN_PREFERRED_NAMES AI_RETURN_PREFERRED_NAMES が設定されている場合、pName パラメーターに名前を指定してはなりません。NS_EMAIL ネームスペースプロバイダーは、公開用の優先名を返します。

AI_RETURN_PREFERRED_NAMES フラグは、Windows Vista 以降用 Windows SDK で定義されています。AI_RETURN_PREFERRED_NAMES フラグは Windows Vista 以降でサポートされ、NS_EMAIL ネームスペースにのみ適用されます。

AI_FQDN AI_FQDN が設定されていて、フラットな名前 (単一ラベル) が指定されている場合、GetAddrInfoEx は、その名前が最終的に解決された完全修飾ドメイン名を返します。完全修飾ドメイン名は、関連する addrinfoex 構造体の ai_canonname メンバーに返されます。これは、DNS に登録された正規名を返す AI_CANONNAME ビットフラグとは異なります。正規名は、フラットな名前が解決された完全修飾ドメイン名とは異なる場合があります。

AI_FQDN ビットが設定されている場合、pName パラメーターを NULL にすることはできません。そうでない場合、 GetAddrInfoEx 関数は WSANO_RECOVERY で失敗します。

Windows 8 および Windows Server 2012 では、AI_FQDNAI_CANONNAME の両方のビットを設定できます。GetAddrInfoEx 関数が AI_FQDNAI_CANONNAME の両方のビットを指定して呼び出された場合、ppResult パラメーターは addrinfoex 構造体ではなく addrinfoex2 構造体へのポインターを返します。

Windows 7 および Windows Server 2008 R2 では、AI_FQDNAI_CANONNAME のビットのうち 1 つだけを設定できます。両方のフラグが指定されている場合、GetAddrInfoEx 関数は EAI_BADFLAGS で失敗します。

Windows 7: AI_FQDN フラグは、Windows 7 以降用 Windows SDK で定義されています。AI_FQDN フラグは Windows 7 以降でサポートされます。

AI_FILESERVER AI_FILESERVER が設定されている場合、これは、問い合わせられているホスト名がファイル共有のシナリオで使用されていることをネームスペースプロバイダーに伝えるヒントです。ネームスペースプロバイダーはこのヒントを無視することがあります。

Windows 7: AI_FILESERVER フラグは、Windows 7 以降用 Windows SDK で定義されています。AI_FILESERVER フラグは Windows 7 以降でサポートされます。

AI_DISABLE_IDN_ENCODING AI_DISABLE_IDN_ENCODING が設定されている場合、GetAddrInfoEx 関数が呼び出す名前解決関数において、Punycode を使用した自動的な国際化ドメイン名エンコードが無効になります。

Windows 8: AI_DISABLE_IDN_ENCODING フラグは、Windows 8 以降用 Windows SDK で定義されています。AI_DISABLE_IDN_ENCODING フラグは Windows 8 以降でサポートされます。

メモ

ws2tcpip.h ヘッダーは GetAddrInfoEx を、UNICODE プリプロセッサ定数の定義に基づいてこの関数の ANSI 版または Unicode 版を自動的に選択するエイリアスとして定義します。エンコーディング中立のエイリアスの使用と、エンコーディング中立でないコードを混在させると、コンパイルエラーや実行時エラーを引き起こす不一致が生じる可能性があります。詳細については、Conventions for Function Prototypes を参照してください。

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

各言語での呼び出し定義

// WS2_32.dll  (ANSI / -A)
#include <windows.h>

INT GetAddrInfoExA(
    LPCSTR pName,   // optional
    LPCSTR pServiceName,   // optional
    DWORD dwNameSpace,
    GUID* lpNspId,   // optional
    const ADDRINFOEXA* hints,   // optional
    ADDRINFOEXA** ppResult,
    TIMEVAL* timeout,   // optional
    OVERLAPPED* lpOverlapped,   // optional
    LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,   // optional
    HANDLE* lpNameHandle   // optional
);
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
static extern int GetAddrInfoExA(
    [MarshalAs(UnmanagedType.LPStr)] string pName,   // LPCSTR optional
    [MarshalAs(UnmanagedType.LPStr)] string pServiceName,   // LPCSTR optional
    uint dwNameSpace,   // DWORD
    IntPtr lpNspId,   // GUID* optional
    IntPtr hints,   // ADDRINFOEXA* optional
    IntPtr ppResult,   // ADDRINFOEXA** out
    IntPtr timeout,   // TIMEVAL* optional
    IntPtr lpOverlapped,   // OVERLAPPED* optional
    IntPtr lpCompletionRoutine,   // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    IntPtr lpNameHandle   // HANDLE* optional, out
);
<DllImport("WS2_32.dll", CharSet:=CharSet.Ansi, ExactSpelling:=True)>
Public Shared Function GetAddrInfoExA(
    <MarshalAs(UnmanagedType.LPStr)> pName As String,   ' LPCSTR optional
    <MarshalAs(UnmanagedType.LPStr)> pServiceName As String,   ' LPCSTR optional
    dwNameSpace As UInteger,   ' DWORD
    lpNspId As IntPtr,   ' GUID* optional
    hints As IntPtr,   ' ADDRINFOEXA* optional
    ppResult As IntPtr,   ' ADDRINFOEXA** out
    timeout As IntPtr,   ' TIMEVAL* optional
    lpOverlapped As IntPtr,   ' OVERLAPPED* optional
    lpCompletionRoutine As IntPtr,   ' LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    lpNameHandle As IntPtr   ' HANDLE* optional, out
) As Integer
End Function
' pName : LPCSTR optional
' pServiceName : LPCSTR optional
' dwNameSpace : DWORD
' lpNspId : GUID* optional
' hints : ADDRINFOEXA* optional
' ppResult : ADDRINFOEXA** out
' timeout : TIMEVAL* optional
' lpOverlapped : OVERLAPPED* optional
' lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
' lpNameHandle : HANDLE* optional, out
Declare PtrSafe Function GetAddrInfoExA Lib "ws2_32" ( _
    ByVal pName As String, _
    ByVal pServiceName As String, _
    ByVal dwNameSpace As Long, _
    ByVal lpNspId As LongPtr, _
    ByVal hints As LongPtr, _
    ByVal ppResult As LongPtr, _
    ByVal timeout As LongPtr, _
    ByVal lpOverlapped As LongPtr, _
    ByVal lpCompletionRoutine As LongPtr, _
    ByVal lpNameHandle As LongPtr) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

GetAddrInfoExA = ctypes.windll.ws2_32.GetAddrInfoExA
GetAddrInfoExA.restype = ctypes.c_int
GetAddrInfoExA.argtypes = [
    wintypes.LPCSTR,  # pName : LPCSTR optional
    wintypes.LPCSTR,  # pServiceName : LPCSTR optional
    wintypes.DWORD,  # dwNameSpace : DWORD
    ctypes.c_void_p,  # lpNspId : GUID* optional
    ctypes.c_void_p,  # hints : ADDRINFOEXA* optional
    ctypes.c_void_p,  # ppResult : ADDRINFOEXA** out
    ctypes.c_void_p,  # timeout : TIMEVAL* optional
    ctypes.c_void_p,  # lpOverlapped : OVERLAPPED* optional
    ctypes.c_void_p,  # lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    ctypes.c_void_p,  # lpNameHandle : HANDLE* optional, out
]
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('WS2_32.dll')
GetAddrInfoExA = Fiddle::Function.new(
  lib['GetAddrInfoExA'],
  [
    Fiddle::TYPE_VOIDP,  # pName : LPCSTR optional
    Fiddle::TYPE_VOIDP,  # pServiceName : LPCSTR optional
    -Fiddle::TYPE_INT,  # dwNameSpace : DWORD
    Fiddle::TYPE_VOIDP,  # lpNspId : GUID* optional
    Fiddle::TYPE_VOIDP,  # hints : ADDRINFOEXA* optional
    Fiddle::TYPE_VOIDP,  # ppResult : ADDRINFOEXA** out
    Fiddle::TYPE_VOIDP,  # timeout : TIMEVAL* optional
    Fiddle::TYPE_VOIDP,  # lpOverlapped : OVERLAPPED* optional
    Fiddle::TYPE_VOIDP,  # lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    Fiddle::TYPE_VOIDP,  # lpNameHandle : HANDLE* optional, out
  ],
  Fiddle::TYPE_INT)
#[link(name = "ws2_32")]
extern "system" {
    fn GetAddrInfoExA(
        pName: *const u8,  // LPCSTR optional
        pServiceName: *const u8,  // LPCSTR optional
        dwNameSpace: u32,  // DWORD
        lpNspId: *mut GUID,  // GUID* optional
        hints: *const ADDRINFOEXA,  // ADDRINFOEXA* optional
        ppResult: *mut *mut ADDRINFOEXA,  // ADDRINFOEXA** out
        timeout: *mut TIMEVAL,  // TIMEVAL* optional
        lpOverlapped: *mut OVERLAPPED,  // OVERLAPPED* optional
        lpCompletionRoutine: *const core::ffi::c_void,  // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
        lpNameHandle: *mut *mut core::ffi::c_void  // HANDLE* optional, out
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("WS2_32.dll", CharSet = CharSet.Ansi)]
public static extern int GetAddrInfoExA([MarshalAs(UnmanagedType.LPStr)] string pName, [MarshalAs(UnmanagedType.LPStr)] string pServiceName, uint dwNameSpace, IntPtr lpNspId, IntPtr hints, IntPtr ppResult, IntPtr timeout, IntPtr lpOverlapped, IntPtr lpCompletionRoutine, IntPtr lpNameHandle);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_GetAddrInfoExA' -Namespace Win32 -PassThru
# $api::GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
#uselib "WS2_32.dll"
#func global GetAddrInfoExA "GetAddrInfoExA" sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr, sptr
; GetAddrInfoExA pName, pServiceName, dwNameSpace, varptr(lpNspId), varptr(hints), varptr(ppResult), varptr(timeout), varptr(lpOverlapped), lpCompletionRoutine, lpNameHandle   ; 戻り値は stat
; pName : LPCSTR optional -> "sptr"
; pServiceName : LPCSTR optional -> "sptr"
; dwNameSpace : DWORD -> "sptr"
; lpNspId : GUID* optional -> "sptr"
; hints : ADDRINFOEXA* optional -> "sptr"
; ppResult : ADDRINFOEXA** out -> "sptr"
; timeout : TIMEVAL* optional -> "sptr"
; lpOverlapped : OVERLAPPED* optional -> "sptr"
; lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> "sptr"
; lpNameHandle : HANDLE* optional, out -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "WS2_32.dll"
#cfunc global GetAddrInfoExA "GetAddrInfoExA" str, str, int, var, var, var, var, var, sptr, sptr
; res = GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
; pName : LPCSTR optional -> "str"
; pServiceName : LPCSTR optional -> "str"
; dwNameSpace : DWORD -> "int"
; lpNspId : GUID* optional -> "var"
; hints : ADDRINFOEXA* optional -> "var"
; ppResult : ADDRINFOEXA** out -> "var"
; timeout : TIMEVAL* optional -> "var"
; lpOverlapped : OVERLAPPED* optional -> "var"
; lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> "sptr"
; lpNameHandle : HANDLE* optional, out -> "sptr"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; INT GetAddrInfoExA(LPCSTR pName, LPCSTR pServiceName, DWORD dwNameSpace, GUID* lpNspId, ADDRINFOEXA* hints, ADDRINFOEXA** ppResult, TIMEVAL* timeout, OVERLAPPED* lpOverlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine, HANDLE* lpNameHandle)
#uselib "WS2_32.dll"
#cfunc global GetAddrInfoExA "GetAddrInfoExA" str, str, int, var, var, var, var, var, intptr, intptr
; res = GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
; pName : LPCSTR optional -> "str"
; pServiceName : LPCSTR optional -> "str"
; dwNameSpace : DWORD -> "int"
; lpNspId : GUID* optional -> "var"
; hints : ADDRINFOEXA* optional -> "var"
; ppResult : ADDRINFOEXA** out -> "var"
; timeout : TIMEVAL* optional -> "var"
; lpOverlapped : OVERLAPPED* optional -> "var"
; lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> "intptr"
; lpNameHandle : HANDLE* optional, out -> "intptr"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procGetAddrInfoExA = ws2_32.NewProc("GetAddrInfoExA")
)

// pName (LPCSTR optional), pServiceName (LPCSTR optional), dwNameSpace (DWORD), lpNspId (GUID* optional), hints (ADDRINFOEXA* optional), ppResult (ADDRINFOEXA** out), timeout (TIMEVAL* optional), lpOverlapped (OVERLAPPED* optional), lpCompletionRoutine (LPLOOKUPSERVICE_COMPLETION_ROUTINE optional), lpNameHandle (HANDLE* optional, out)
r1, _, err := procGetAddrInfoExA.Call(
	uintptr(unsafe.Pointer(windows.BytePtrFromString(pName))),
	uintptr(unsafe.Pointer(windows.BytePtrFromString(pServiceName))),
	uintptr(dwNameSpace),
	uintptr(lpNspId),
	uintptr(hints),
	uintptr(ppResult),
	uintptr(timeout),
	uintptr(lpOverlapped),
	uintptr(lpCompletionRoutine),
	uintptr(lpNameHandle),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function GetAddrInfoExA(
  pName: PAnsiChar;   // LPCSTR optional
  pServiceName: PAnsiChar;   // LPCSTR optional
  dwNameSpace: DWORD;   // DWORD
  lpNspId: PGUID;   // GUID* optional
  hints: Pointer;   // ADDRINFOEXA* optional
  ppResult: Pointer;   // ADDRINFOEXA** out
  timeout: Pointer;   // TIMEVAL* optional
  lpOverlapped: Pointer;   // OVERLAPPED* optional
  lpCompletionRoutine: Pointer;   // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
  lpNameHandle: Pointer   // HANDLE* optional, out
): Integer; stdcall;
  external 'WS2_32.dll' name 'GetAddrInfoExA';
result := DllCall("WS2_32\GetAddrInfoExA"
    , "AStr", pName   ; LPCSTR optional
    , "AStr", pServiceName   ; LPCSTR optional
    , "UInt", dwNameSpace   ; DWORD
    , "Ptr", lpNspId   ; GUID* optional
    , "Ptr", hints   ; ADDRINFOEXA* optional
    , "Ptr", ppResult   ; ADDRINFOEXA** out
    , "Ptr", timeout   ; TIMEVAL* optional
    , "Ptr", lpOverlapped   ; OVERLAPPED* optional
    , "Ptr", lpCompletionRoutine   ; LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    , "Ptr", lpNameHandle   ; HANDLE* optional, out
    , "Int")   ; return: INT
●GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle) = DLL("WS2_32.dll", "int GetAddrInfoExA(char*, char*, dword, void*, void*, void*, void*, void*, void*, void*)")
# 呼び出し: GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
# pName : LPCSTR optional -> "char*"
# pServiceName : LPCSTR optional -> "char*"
# dwNameSpace : DWORD -> "dword"
# lpNspId : GUID* optional -> "void*"
# hints : ADDRINFOEXA* optional -> "void*"
# ppResult : ADDRINFOEXA** out -> "void*"
# timeout : TIMEVAL* optional -> "void*"
# lpOverlapped : OVERLAPPED* optional -> "void*"
# lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> "void*"
# lpNameHandle : HANDLE* optional, out -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "ws2_32" fn GetAddrInfoExA(
    pName: [*c]const u8, // LPCSTR optional
    pServiceName: [*c]const u8, // LPCSTR optional
    dwNameSpace: u32, // DWORD
    lpNspId: [*c]GUID, // GUID* optional
    hints: [*c]ADDRINFOEXA, // ADDRINFOEXA* optional
    ppResult: [*c][*c]ADDRINFOEXA, // ADDRINFOEXA** out
    timeout: [*c]TIMEVAL, // TIMEVAL* optional
    lpOverlapped: [*c]OVERLAPPED, // OVERLAPPED* optional
    lpCompletionRoutine: ?*anyopaque, // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    lpNameHandle: ?*anyopaque // HANDLE* optional, out
) callconv(std.os.windows.WINAPI) i32;
proc GetAddrInfoExA(
    pName: cstring,  # LPCSTR optional
    pServiceName: cstring,  # LPCSTR optional
    dwNameSpace: uint32,  # DWORD
    lpNspId: ptr GUID,  # GUID* optional
    hints: ptr ADDRINFOEXA,  # ADDRINFOEXA* optional
    ppResult: ptr ADDRINFOEXA,  # ADDRINFOEXA** out
    timeout: ptr TIMEVAL,  # TIMEVAL* optional
    lpOverlapped: ptr OVERLAPPED,  # OVERLAPPED* optional
    lpCompletionRoutine: pointer,  # LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    lpNameHandle: pointer  # HANDLE* optional, out
): int32 {.importc: "GetAddrInfoExA", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int GetAddrInfoExA(
    const(char)* pName,   // LPCSTR optional
    const(char)* pServiceName,   // LPCSTR optional
    uint dwNameSpace,   // DWORD
    GUID* lpNspId,   // GUID* optional
    ADDRINFOEXA* hints,   // ADDRINFOEXA* optional
    ADDRINFOEXA** ppResult,   // ADDRINFOEXA** out
    TIMEVAL* timeout,   // TIMEVAL* optional
    OVERLAPPED* lpOverlapped,   // OVERLAPPED* optional
    void* lpCompletionRoutine,   // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    void* lpNameHandle   // HANDLE* optional, out
);
ccall((:GetAddrInfoExA, "WS2_32.dll"), stdcall, Int32,
      (Cstring, Cstring, UInt32, Ptr{GUID}, Ptr{ADDRINFOEXA}, Ptr{ADDRINFOEXA}, Ptr{TIMEVAL}, Ptr{OVERLAPPED}, Ptr{Cvoid}, Ptr{Cvoid}),
      pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
# pName : LPCSTR optional -> Cstring
# pServiceName : LPCSTR optional -> Cstring
# dwNameSpace : DWORD -> UInt32
# lpNspId : GUID* optional -> Ptr{GUID}
# hints : ADDRINFOEXA* optional -> Ptr{ADDRINFOEXA}
# ppResult : ADDRINFOEXA** out -> Ptr{ADDRINFOEXA}
# timeout : TIMEVAL* optional -> Ptr{TIMEVAL}
# lpOverlapped : OVERLAPPED* optional -> Ptr{OVERLAPPED}
# lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> Ptr{Cvoid}
# lpNameHandle : HANDLE* optional, out -> Ptr{Cvoid}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
int32_t GetAddrInfoExA(
    const char* pName,
    const char* pServiceName,
    uint32_t dwNameSpace,
    void* lpNspId,
    void* hints,
    void* ppResult,
    void* timeout,
    void* lpOverlapped,
    void* lpCompletionRoutine,
    void* lpNameHandle);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
-- pName : LPCSTR optional
-- pServiceName : LPCSTR optional
-- dwNameSpace : DWORD
-- lpNspId : GUID* optional
-- hints : ADDRINFOEXA* optional
-- ppResult : ADDRINFOEXA** out
-- timeout : TIMEVAL* optional
-- lpOverlapped : OVERLAPPED* optional
-- lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
-- lpNameHandle : HANDLE* optional, out
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('WS2_32.dll');
const GetAddrInfoExA = lib.func('__stdcall', 'GetAddrInfoExA', 'int32_t', ['str', 'str', 'uint32_t', 'void *', 'void *', 'void *', 'void *', 'void *', 'void *', 'void *']);
// GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
// pName : LPCSTR optional -> 'str'
// pServiceName : LPCSTR optional -> 'str'
// dwNameSpace : DWORD -> 'uint32_t'
// lpNspId : GUID* optional -> 'void *'
// hints : ADDRINFOEXA* optional -> 'void *'
// ppResult : ADDRINFOEXA** out -> 'void *'
// timeout : TIMEVAL* optional -> 'void *'
// lpOverlapped : OVERLAPPED* optional -> 'void *'
// lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> 'void *'
// lpNameHandle : HANDLE* optional, out -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
// コールバック(関数ポインタ)は koffi.proto/koffi.register で型を定義して渡す(素の void* では JS 関数を渡せない)。
const lib = Deno.dlopen("WS2_32.dll", {
  GetAddrInfoExA: { parameters: ["buffer", "buffer", "u32", "pointer", "pointer", "pointer", "pointer", "pointer", "pointer", "pointer"], result: "i32" },
});
// lib.symbols.GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
// pName : LPCSTR optional -> "buffer"
// pServiceName : LPCSTR optional -> "buffer"
// dwNameSpace : DWORD -> "u32"
// lpNspId : GUID* optional -> "pointer"
// hints : ADDRINFOEXA* optional -> "pointer"
// ppResult : ADDRINFOEXA** out -> "pointer"
// timeout : TIMEVAL* optional -> "pointer"
// lpOverlapped : OVERLAPPED* optional -> "pointer"
// lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> "pointer"
// lpNameHandle : HANDLE* optional, out -> "pointer"
// 文字列は "buffer"。ANSI(-A) は new TextEncoder() で UTF-8/ANSI バイト列(末尾に \x00)を渡す。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
int32_t GetAddrInfoExA(
    const char* pName,
    const char* pServiceName,
    uint32_t dwNameSpace,
    void* lpNspId,
    void* hints,
    void* ppResult,
    void* timeout,
    void* lpOverlapped,
    void* lpCompletionRoutine,
    void* lpNameHandle);
C, "WS2_32.dll");
// $ffi->GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId, hints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle);
// pName : LPCSTR optional
// pServiceName : LPCSTR optional
// dwNameSpace : DWORD
// lpNspId : GUID* optional
// hints : ADDRINFOEXA* optional
// ppResult : ADDRINFOEXA** out
// timeout : TIMEVAL* optional
// lpOverlapped : OVERLAPPED* optional
// lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
// lpNameHandle : HANDLE* optional, out
// 構造体/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, W32APIOptions.ASCII_OPTIONS);
    int GetAddrInfoExA(
        String pName,   // LPCSTR optional
        String pServiceName,   // LPCSTR optional
        int dwNameSpace,   // DWORD
        Pointer lpNspId,   // GUID* optional
        Pointer hints,   // ADDRINFOEXA* optional
        Pointer ppResult,   // ADDRINFOEXA** out
        Pointer timeout,   // TIMEVAL* optional
        Pointer lpOverlapped,   // OVERLAPPED* optional
        Callback lpCompletionRoutine,   // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
        Pointer lpNameHandle   // HANDLE* optional, out
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun GetAddrInfoExA = GetAddrInfoExA(
    pName : UInt8*,   # LPCSTR optional
    pServiceName : UInt8*,   # LPCSTR optional
    dwNameSpace : UInt32,   # DWORD
    lpNspId : GUID*,   # GUID* optional
    hints : ADDRINFOEXA*,   # ADDRINFOEXA* optional
    ppResult : ADDRINFOEXA**,   # ADDRINFOEXA** out
    timeout : TIMEVAL*,   # TIMEVAL* optional
    lpOverlapped : OVERLAPPED*,   # OVERLAPPED* optional
    lpCompletionRoutine : Void*,   # LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
    lpNameHandle : Void*   # HANDLE* optional, out
  ) : Int32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef GetAddrInfoExANative = Int32 Function(Pointer<Utf8>, Pointer<Utf8>, Uint32, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>);
typedef GetAddrInfoExADart = int Function(Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>, Pointer<Void>);
final GetAddrInfoExA = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<GetAddrInfoExANative, GetAddrInfoExADart>('GetAddrInfoExA');
// pName : LPCSTR optional -> Pointer<Utf8>
// pServiceName : LPCSTR optional -> Pointer<Utf8>
// dwNameSpace : DWORD -> Uint32
// lpNspId : GUID* optional -> Pointer<Void>
// hints : ADDRINFOEXA* optional -> Pointer<Void>
// ppResult : ADDRINFOEXA** out -> Pointer<Void>
// timeout : TIMEVAL* optional -> Pointer<Void>
// lpOverlapped : OVERLAPPED* optional -> Pointer<Void>
// lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> Pointer<Void>
// lpNameHandle : HANDLE* optional, out -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function GetAddrInfoExA(
  pName: PAnsiChar;   // LPCSTR optional
  pServiceName: PAnsiChar;   // LPCSTR optional
  dwNameSpace: DWORD;   // DWORD
  lpNspId: PGUID;   // GUID* optional
  hints: Pointer;   // ADDRINFOEXA* optional
  ppResult: Pointer;   // ADDRINFOEXA** out
  timeout: Pointer;   // TIMEVAL* optional
  lpOverlapped: Pointer;   // OVERLAPPED* optional
  lpCompletionRoutine: Pointer;   // LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
  lpNameHandle: Pointer   // HANDLE* optional, out
): Integer; stdcall;
  external 'WS2_32.dll' name 'GetAddrInfoExA';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "GetAddrInfoExA"
  c_GetAddrInfoExA :: CString -> CString -> Word32 -> Ptr () -> Ptr () -> Ptr () -> Ptr () -> Ptr () -> Ptr () -> Ptr () -> IO Int32
-- pName : LPCSTR optional -> CString
-- pServiceName : LPCSTR optional -> CString
-- dwNameSpace : DWORD -> Word32
-- lpNspId : GUID* optional -> Ptr ()
-- hints : ADDRINFOEXA* optional -> Ptr ()
-- ppResult : ADDRINFOEXA** out -> Ptr ()
-- timeout : TIMEVAL* optional -> Ptr ()
-- lpOverlapped : OVERLAPPED* optional -> Ptr ()
-- lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> Ptr ()
-- lpNameHandle : HANDLE* optional, out -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let getaddrinfoexa =
  foreign "GetAddrInfoExA"
    (string @-> string @-> uint32_t @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> (ptr void) @-> returning int32_t)
(* pName : LPCSTR optional -> string *)
(* pServiceName : LPCSTR optional -> string *)
(* dwNameSpace : DWORD -> uint32_t *)
(* lpNspId : GUID* optional -> (ptr void) *)
(* hints : ADDRINFOEXA* optional -> (ptr void) *)
(* ppResult : ADDRINFOEXA** out -> (ptr void) *)
(* timeout : TIMEVAL* optional -> (ptr void) *)
(* lpOverlapped : OVERLAPPED* optional -> (ptr void) *)
(* lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> (ptr void) *)
(* lpNameHandle : HANDLE* optional, out -> (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 ("GetAddrInfoExA" get-addr-info-ex-a :convention :stdcall) :int32
  (p-name :string)   ; LPCSTR optional
  (p-service-name :string)   ; LPCSTR optional
  (dw-name-space :uint32)   ; DWORD
  (lp-nsp-id :pointer)   ; GUID* optional
  (hints :pointer)   ; ADDRINFOEXA* optional
  (pp-result :pointer)   ; ADDRINFOEXA** out
  (timeout :pointer)   ; TIMEVAL* optional
  (lp-overlapped :pointer)   ; OVERLAPPED* optional
  (lp-completion-routine :pointer)   ; LPLOOKUPSERVICE_COMPLETION_ROUTINE optional
  (lp-name-handle :pointer))   ; HANDLE* optional, out
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $GetAddrInfoExA = Win32::API::More->new('WS2_32',
    'int GetAddrInfoExA(LPCSTR pName, LPCSTR pServiceName, DWORD dwNameSpace, LPVOID lpNspId, LPVOID hints, LPVOID ppResult, LPVOID timeout, LPVOID lpOverlapped, LPVOID lpCompletionRoutine, HANDLE lpNameHandle)');
# my $ret = $GetAddrInfoExA->Call($pName, $pServiceName, $dwNameSpace, $lpNspId, $hints, $ppResult, $timeout, $lpOverlapped, $lpCompletionRoutine, $lpNameHandle);
# pName : LPCSTR optional -> LPCSTR
# pServiceName : LPCSTR optional -> LPCSTR
# dwNameSpace : DWORD -> DWORD
# lpNspId : GUID* optional -> LPVOID
# hints : ADDRINFOEXA* optional -> LPVOID
# ppResult : ADDRINFOEXA** out -> LPVOID
# timeout : TIMEVAL* optional -> LPVOID
# lpOverlapped : OVERLAPPED* optional -> LPVOID
# lpCompletionRoutine : LPLOOKUPSERVICE_COMPLETION_ROUTINE optional -> LPVOID
# lpNameHandle : HANDLE* optional, out -> HANDLE
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# コールバック(関数ポインタ)は Perl sub を直接渡せません。Win32::API::Callback を使用してください。

関連項目

文字セット違い
公式の関連項目
使用する型