(おそらく私は厄介なレベルの詳細で問題を説明しました、tl; drバージョンは一番下にあります)
私はJNAを使用して、Javaで単純なWinsockテストアプリケーションを作成しようとしています。私が最初に呼び出した関数は、次のコードを使用したWSAStartup()でした。
public interface Ws2_32 extends Library {
Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);
int WSAStartup(short version, LPWSADATA lpwsaData);
}
public static void main(String[] args){
LPWSADATA lpwsaData = new LPWSADATA();
short version = 2;
int result = Ws2_32.INSTANCE.WSAStartup(version,lpwsaData);
System.out.println("WSAStartup() returned: " + result);
if((resultado = Ws2_32.INSTANCE.WSAStartup(version,lpwsaData)) == 0){
System.out.println("LPWSADATA struct:");
System.out.println("wVersion: " + lpwsaData.wVersion);
System.out.println("wHighVersion: " + lpwsaData.wHighVersion);
System.out.print("szDescription: ");
for(byte b : lpwsaData.szDescription){
System.out.print((char) b);
}
System.out.print("\n");
System.out.print("szSystemStatus: ");
for(byte b : lpwsaData.szSystemStatus){
System.out.print((char) b);
}
System.out.print("\n");
System.out.println("iMaxSockets: " + lpwsaData.iMaxSockets);
System.out.println("iMaxUdpDg: " + lpwsaData.iMaxUdpDg");
}
}
これは機能し、次の値を取得します。
wバージョン:2
wHighVersion:514
szDescription:WinSock 2.0
szSystemStatus:実行中
iMaxSockets:0
iMaxUdpDg:0
WSAStartup()が正常に返された後、WSAEnumProtocols()を呼び出そうとしましたが、次のエラーが発生しました。
スレッド"main"の例外java.lang.UnsatisfiedLinkError:関数'WSAEnumProtocols'の検索中にエラーが発生しました:指定されたプロシージャが見つかりませんでした。
次に、Dependency Walkerを使用してws2_32.dllを開きましたが、その名前の関数がないことがわかりました。WSAEnumProtocolsA()、WSAEnumProtocolsW()、WSCEnumProtocols()という同じ名前の3つしか見つかりませんでした。例としてWSAEnumProtocolsA()を使用しますが、3つすべてで次のプロシージャを使用し、同じ結果が得られました。
最初にWSAStartup()を呼び出しましたが、エラーは返されませんでした。WSAEnumProtocolsのMSDN定義によると、関数の最初の呼び出しは次のようになります。WSAEnumProtocols(null、wsaprotocol_info、lpdwBufferLength)最初のパラメーターはnull、2番目はWSAPROTOCOL_INFO構造体へのポインター、3番目はバッファ。その長さがゼロの場合、関数は-1(SOCKET_ERROR)を返し、WSAGetLastError()の呼び出しはWSAENOBUFSを返す必要があります。つまり、バッファーはWSAEnumProtocols()によって返される情報を含むのに十分な大きさではなく、変数lpdwBufferLengthを設定する必要があります。要求されたすべての情報を取得するためにWSAEnumProtocolsに渡すことができる最小バッファー・サイズを使用します。これを機能させることができません。
また、WSASetLastError()を使用して他のエラーコードに設定し、WSAGetLastError()を呼び出しようとしましたが、常に0が返されました。
tl; dr WSAEnumProtocols(null、wsaprotocol_info、lpdwBufferLength)を機能させることができません。WSAEnumProtocols()は-1を返しますが、lpdwBufferLengthの値は変更されず、WSAGetLastError()は10055ではなく0を返します(WSAENOBUFS)
アップデート:
これは、Winsock関数を宣言するために使用しているインターフェイスです
public interface Ws2_32 extends Library {
Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);
int WSAStartup(short version, LPWSADATA lpwsaData);
int WSAEnumProtocolsW(int[] lpiProtocols, WSAPROTOCOL_INFO lpProtocolBuffer, int lpdwBufferLength);
int WSACleanup();
int WSAGetLastError();
int WSASetLastError(int iError);
}
これは私が関数を呼び出しているところからのコードです:
public class TestWSAEnumProtocolsA {
public void start(){
WSAPROTOCOL_INFO wsaprotocol_info = new WSAPROTOCOL_INFO();
LPWSADATA lpwsaData = new LPWSADATA();
int lpdwBufferLength = -2;
int result = 0;
short version = 514;
if((result = Ws2_32.INSTANCE.WSAStartup(version, lpwsaData)) != 0){
System.out.println("Error #" + result + " at WSAStartup()");
return;
} else {
System.out.println("WSAStartup() finished correctly.");
if((result = Ws2_32.INSTANCE.WSAEnumProtocols(null, wsaprotocol_info, lpdwBufferLength)) == -1){
System.out.println("WSAEnumProtocolsW() returned: " + result);
System.out.println("lpdwBufferLength is: " + lpdwBufferLength);
System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
System.out.println("Now I'm setting it to 10004");
Ws2_32.INSTANCE.WSASetLastError(10004);
System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
}
}
}
}
そのコードは次の出力を生成しました:
WSAStartup()は正しく終了しました。
WSAEnumProtocolsW()が返されました:-1
lpdwBufferLengthは次のとおりです:-2
WSAGetLastError()が返されました:0
今は10004に設定しています
WSAGetLastError()が返されました:0
これらの関数を呼び出すときに使用する構造を定義した方法は次のとおりです。
public class WinSock2_structs {
public static class LPWSADATA extends Structure{
public short wVersion;
public short wHighVersion;
public byte szDescription[] = new byte[256+1];
public byte szSystemStatus[] = new byte[128+1];
public short iMaxSockets;
public short iMaxUdpDg;
public char lpVendorInfo;
}
public static class WSAPROTOCOLCHAIN extends Structure{
public int ChainLen;
public int ChainEntries[] = new int[7];
}
public static class GUID extends Structure{
public int Data1;
public short Data2;
public short Data3;
public short Data4;
public byte Data5[] = new byte[8];
}
public static class WSAPROTOCOL_INFO extends Structure{
public int dwServiceFlags1;
public int dwServiceFlags2;
public int dwServiceFlags3;
public int dwServiceFlags4;
public int dwProviderFlags;
public GUID ProviderId;
public int dwCatalogEntryId;
public WSAPROTOCOLCHAIN ProtocolChain;
public int iVersion;
public int iAddressFamily;
public int iMaxSockAddr;
public int iMinSockAddr;
public int iSocketType;
public int iProtocol;
public int iProtocolMaxOffset;
public int iNetworkByteOrder;
public int iSecurityScheme;
public int dwMessageSize;
public int dwProviderReserved;
public char szProtocol[] = new char[256];
}
}