0

(おそらく私は厄介なレベルの詳細で問題を説明しました、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];

    }
}
4

1 に答える 1

1

WinSockを正しくアンロードするには、2回呼び出すWSAStartup()必要があります。WSACleanup()一度だけ電話する必要がありますWSAStartup()

構造体のszProtocolメンバーは要素 WSAPROTOCOL_INFOの配列です。呼び出し元のアプリがANSI/MBCS用にコンパイルされているかUNICODE用にコンパイルされているかに応じて、マップします。そのため、ws2_32.dllには関数がありません。代わりに、( Ansiの場合)と(Unicodeの場合)別々の関数があります。JavaはUnicode文字列を使用するため、JNAコードでを使用する必要があります。 を使用せず、のみを使用します。そのため、個別の関数はありません。TCHARTCHARcharwchar_tWSAEnumProtocols()WSAEnumProtocolsA()WSAEnumProtocolsW()WSAEnumProtocolsW()WSAStartup()TCHARcharWSAStartupA()WSAStartupW()

JNAコードが正しく機能しない場合は、間違って宣言/使用している可能性がWSAEnumProtocols()ありWSAGetLastError()ますが、そのコードは表示されていないため、なぜ機能しないのかは誰にもわかりません。

更新:次のようなものを試してください(私はJNAを使用していないので、微調整が必​​要な場合がありますが、これで一般的なアイデアが得られます):

public interface Ws2_32 extends Library {

    // I don't know how to declare fixed size arrays in JNA,
    // so you will have to adjust these Structue declarations
    // as needed...

    public static class WSAData extends Structure {
        short wVersion;
        short wHighVersion;
        byte  szDescription[257];
        byte  szSystemStatus[129];
        short iMaxSockets;
        short iMaxUdpDg;
        String lpVendorInfo;
    };

    public static class WSAPROTOCOLCHAIN extends Structure {
        int ChainLen;
        int ChainEntries[7];
    };

    public static class WSAPROTOCOL_INFOW extends Structure {
        int dwServiceFlags1;
        int dwServiceFlags2;
        int dwServiceFlags3;
        int dwServiceFlags4;
        int dwProviderFlags;
        GUID ProviderId;
        int dwCatalogEntryId;
        WSAPROTOCOLCHAIN ProtocolChain;
        int iVersion;
        int iAddressFamily;
        int iMaxSockAddr;
        int iMinSockAddr;
        int iSocketType;
        int iProtocol;
        int iProtocolMaxOffset;
        int iNetworkByteOrder;
        int iSecurityScheme;
        int dwMessageSize;
        int dwProviderReserved;
        char szProtocol[256];
    };

    Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);

    int WSAStartup(short version, WSADATA lpwsaData);
    int WSAEnumProtocolsW(int[] lpiProtocols, WSAPROTOCOL_INFOW[] lpProtocolBuffer, IntByReference lpdwBufferLength);
    int WSACleanup();
    int WSAGetLastError();
    int WSASetLastError(int iError);
}

public static void main(String[] args){
    WSADATA     wsaData = new WSADATA();
    short       version = 2;
    int         result = Ws2_32.INSTANCE.WSAStartup(version, wsaData);

    System.out.println("WSAStartup() returned: " + result);

    if(result == 0){
        System.out.println("WSADATA struct:");
        System.out.println("wVersion: " + wsaData.wVersion);
        System.out.println("wHighVersion: " + wsaData.wHighVersion);

        System.out.print("szDescription: ");
        for(byte b : wsaData.szDescription){
            System.out.print((char) b);
        }
        System.out.print("\n");

        System.out.print("szSystemStatus: ");
        for(byte b : wsaData.szSystemStatus){
            System.out.print((char) b);
        }
        System.out.print("\n");

        System.out.println("iMaxSockets: " + wsaData.iMaxSockets);
        System.out.println("iMaxUdpDg: " + wsaData.iMaxUdpDg");
    }
}

public class TestWSAEnumProtocolsA {

    public void start(){

        WSAPROTOCOL_INFOW[]     wsaprotocol_info = new WSAPROTOCOL_INFOW[1];
        WSADATA                 wsaData = new WSADATA();
        IntByReference          dwBufferLength = new IntByReference(628); // sizeof WSAPROTOCOL_INFOW, in bytes
        int                     result = 0;
        short                   version = 2;

        if((result = Ws2_32.INSTANCE.WSAStartup(version, wsaData)) != 0){
            System.out.println("Error #" + result + " at WSAStartup()");
            return;
        }

        System.out.println("WSAStartup() finished correctly.");

        if((result = Ws2_32.INSTANCE.WSAEnumProtocolsW(null, wsaprotocol_info, dwBufferLength)) == -1){
            System.out.println("WSAEnumProtocolsW() returned: " + result);
            System.out.println("dwBufferLength is: " + dwBufferLength.getValue());
            System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
        }
    }
}
于 2013-02-28T20:05:00.780 に答える