调用使用 Java + JNA 的 WinInet 函数

Posted

技术标签:

【中文标题】调用使用 Java + JNA 的 WinInet 函数【英文标题】:Invoke WinInet Functions Used Java + JNA 【发布时间】:2011-03-31 14:52:03 【问题描述】:

对不起我的英语。

我尝试调用 WinInet InternetSetOptionW 方法来设置 IE 代理。 InternetSetOptionW 返回“true”,但 IE 代理没有改变。

我做错了什么?

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.win32.StdCallLibrary;


public interface WinInet extends StdCallLibrary 
    public WinInet INSTANCE = (WinInet) Native.loadLibrary("Wininet", WinInet.class);

    public boolean InternetSetOptionW(int unused, int dwOption,
            Pointer lpBuffer, int dwBufferLength);


import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Union;
import com.sun.jna.WString;


public class WindowsProxy 
public static final int INTERNET_OPTION_SETTINGS_CHANGED = 39;
public static final int INTERNET_OPTION_REFRESH = 37;

public static final int INTERNET_PER_CONN_FLAGS = 1;
public static final int INTERNET_PER_CONN_PROXY_SERVER = 2;
public static final int INTERNET_PER_CONN_PROXY_BYPASS  = 3;
public static final int INTERNET_PER_CONN_AUTOCONFIG_URL = 4;
public static final int INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5;

public static final int PROXY_TYPE_AUTO_PROXY_URL = 4;

public static final int INTERNET_OPTION_PER_CONNECTION_OPTION = 75;

public static class INTERNET_PER_CONN_OPTION extends Structure 
    public int dwOption;
    public Value value;

    public static class FILETIME extends Structure 
        public int dwLowDateTime;
        public int dwHighDateTime;
    

    public static class Value extends Union 
        public int dwValue;
        public WString pszValue;
        public FILETIME ftValue;
    


public static class INTERNET_PER_CONN_OPTION_LIST extends Structure 
    public int dwSize;
    public WString pszConnection;
    public int dwOptionCount;
    public int dwOptionError;
    public Pointer pOptions;


public static void setProxySettings() 
    INTERNET_PER_CONN_OPTION_LIST list = new INTERNET_PER_CONN_OPTION_LIST();

    INTERNET_PER_CONN_OPTION option = new INTERNET_PER_CONN_OPTION();

    option.dwOption = INTERNET_PER_CONN_PROXY_SERVER;
    option.value.pszValue = new WString("http://localhost:8080");

    list.pszConnection = null;
    list.dwOptionCount = 1;
    list.dwOptionError = 0;
    list.pOptions = option.getPointer();
    list.dwSize = list.size();

    int size = list.size();

    boolean result = WinInet.INSTANCE.InternetSetOptionW(0,
            INTERNET_OPTION_PER_CONNECTION_OPTION, list.getPointer(), size);

    System.out.println(result);

    result = WinInet.INSTANCE.InternetSetOptionW(0,
            INTERNET_OPTION_SETTINGS_CHANGED, null, 0);

    System.out.println(result);

    result = WinInet.INSTANCE.InternetSetOptionW(0,
            INTERNET_OPTION_REFRESH, null, 0);

    System.out.println(result);


public static void main(String[] args) 
    setProxySettings();


感谢您的帮助!

英语

【问题讨论】:

上面的一些方法在 kernel32.GetLastError() 调用后返回 1008。 HINTERNET 不是 int;它是wininet.h C/C++ 标头中的LPVOID。因此,它必须是 Java 中的 Pointerwininet.h 标头是一个非常大的文件。您需要小心地将其翻译成 Java。 【参考方案1】:

我曾尝试将wininet.h 标头手动翻译成Java,但结构太多,相当复杂。

也许你可以试试 JNAerator http://code.google.com/p/jnaerator/

已编辑:

我已经设法使用以下WinInet 结构运行了一些WinInet 方法,但我被WinInet.INTERNET_PER_CONN_OPTION_LISTW 使用InternetQueryOption 用于WinInet.INTERNET_OPTION_PER_CONNECTION_OPTION 查询,它返回GetLastError 值12010。

我不确定 Java 如何将 C/C++ List.dwSize=sizeof(INTERNET_PER_CONN_OPTION_LISTW) 转换为 Java 等价物 optionlist.dwSize = new DWORD(optionlist.size());

Kernel32.java:

import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;

public interface Kernel32 extends StdCallLibrary 
    public Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("Kernel32", Kernel32.class);

    public int GetLastError();

WinInet.java:

    import java.util.HashMap;
    import java.util.Map;
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    import com.sun.jna.Union;
    import com.sun.jna.WString;
    import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR;
    import com.sun.jna.platform.win32.WinBase.FILETIME;
    import com.sun.jna.platform.win32.WinDef.DWORD;
    import com.sun.jna.ptr.IntByReference;
    import com.sun.jna.win32.StdCallLibrary;
    import com.sun.jna.win32.W32APIFunctionMapper;
    import com.sun.jna.win32.W32APITypeMapper;


    /*
     * http://source.winehq.org/source/include/wininet.h
     */
    public interface WinInet extends StdCallLibrary 
        final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() 
            private static final long serialVersionUID = 1L;
            
                put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
                put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
            
        ;

        public WinInet INSTANCE = (WinInet) Native.loadLibrary("Wininet", WinInet.class, WIN32API_OPTIONS);

        public static final DWORD INTERNET_PER_CONN_FLAGS                        = new DWORD(1);
        public static final DWORD INTERNET_PER_CONN_PROXY_SERVER                 = new DWORD(2);
        public static final DWORD INTERNET_PER_CONN_PROXY_BYPASS                 = new DWORD(3);
        public static final DWORD INTERNET_PER_CONN_AUTOCONFIG_URL               = new DWORD(4);
        public static final DWORD INTERNET_PER_CONN_AUTODISCOVERY_FLAGS          = new DWORD(5);
        public static final DWORD INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL     = new DWORD(6);
        public static final DWORD INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = new DWORD(7);
        public static final DWORD INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME  = new DWORD(8);
        public static final DWORD INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL   = new DWORD(9); 

        /* Values for INTERNET_PER_CONN_FLAGS */
        public static final DWORD PROXY_TYPE_DIRECT                              = new DWORD(0x00000001);
        public static final DWORD PROXY_TYPE_PROXY                               = new DWORD(0x00000002);
        public static final DWORD PROXY_TYPE_AUTO_PROXY_URL                      = new DWORD(0x00000004);
        public static final DWORD PROXY_TYPE_AUTO_DETECT                         = new DWORD(0x00000008);

        public static final DWORD INTERNET_OPTION_REFRESH                 = new DWORD(37);
        public static final DWORD INTERNET_OPTION_SETTINGS_CHANGED        = new DWORD(39);
        public static final DWORD INTERNET_OPTION_VERSION                 = new DWORD(40);
        public static final DWORD INTERNET_OPTION_USER_AGENT              = new DWORD(41);
        public static final DWORD INTERNET_OPTION_PER_CONNECTION_OPTION   = new DWORD(75);
        public static final DWORD INTERNET_OPTION_PROXY_SETTINGS_CHANGED  = new DWORD(95);

        /*
            typedef struct 
                DWORD dwMajorVersion;
                DWORD dwMinorVersion;
             INTERNET_VERSION_INFO,* LPINTERNET_VERSION_INFO;
         */     
        public class INTERNET_VERSION_INFO extends Structure 
            public DWORD dwMajorVersion;
            public DWORD dwMinorVersion;
            public INTERNET_VERSION_INFO() 
                super();
                initFieldOrder();
            
            protected void initFieldOrder() 
                setFieldOrder(new java.lang.String[]"dwMajorVersion", "dwMinorVersion");
            
            public INTERNET_VERSION_INFO(DWORD dwMajorVersion, DWORD dwMinorVersion) 
                super();
                this.dwMajorVersion = dwMajorVersion;
                this.dwMinorVersion = dwMinorVersion;
                initFieldOrder();
            
            public static class ByReference extends INTERNET_VERSION_INFO implements Structure.ByReference 

            ;
            public static class ByValue extends INTERNET_VERSION_INFO implements Structure.ByValue 

            ;
           

        /*
            typedef struct _INTERNET_PER_CONN_OPTIONW 
                DWORD dwOption;
                union 
                    DWORD    dwValue;
                    LPWSTR    pszValue;
                    FILETIME ftValue;
                 Value;
             INTERNET_PER_CONN_OPTIONW, *LPINTERNET_PER_CONN_OPTIONW; 
         */
        public class INTERNET_PER_CONN_OPTIONW extends Structure 
            public DWORD dwOption;
            public Value_union Value;
            public static class Value_union extends Union 
                public DWORD dwValue;
                public WString pszValue;
                public FILETIME ftValue;
                public Value_union() 
                    super();
                
                public static class ByReference extends Value_union implements Structure.ByReference 

                ;
                public static class ByValue extends Value_union implements Structure.ByValue 

                ;
            ;
            public INTERNET_PER_CONN_OPTIONW() 
                super();
                initFieldOrder();
            
            protected void initFieldOrder() 
                setFieldOrder(new java.lang.String[]"dwOption", "Value");
            
            public INTERNET_PER_CONN_OPTIONW(DWORD dwOption, Value_union Value) 
                super();
                this.dwOption = dwOption;
                this.Value = Value;
                initFieldOrder();
            
            public static class ByReference extends INTERNET_PER_CONN_OPTIONW implements Structure.ByReference 

            ;
            public static class ByValue extends INTERNET_PER_CONN_OPTIONW implements Structure.ByValue 

            ;
        

        /*
        typedef struct _INTERNET_PER_CONN_OPTION_LISTW 
            DWORD                       dwSize;
            LPWSTR                      pszConnection;
            DWORD                       dwOptionCount;
            DWORD                       dwOptionError;
            LPINTERNET_PER_CONN_OPTIONW pOptions;
         INTERNET_PER_CONN_OPTION_LISTW, *LPINTERNET_PER_CONN_OPTION_LISTW;    
         */
        public class INTERNET_PER_CONN_OPTION_LISTW extends Structure 
            public DWORD dwSize;
            public WString pszConnection;
            public DWORD dwOptionCount;
            public DWORD dwOptionError;
            public INTERNET_PER_CONN_OPTIONW.ByReference pOptions;
            public INTERNET_PER_CONN_OPTION_LISTW() 
                super();
                initFieldOrder();
            
            protected void initFieldOrder() 
                setFieldOrder(new java.lang.String[]"dwSize", "pszConnection", "dwOptionCount", "dwOptionError", "pOptions");
            
            public INTERNET_PER_CONN_OPTION_LISTW(DWORD dwSize, WString pszConnection, DWORD dwOptionCount, DWORD dwOptionError, INTERNET_PER_CONN_OPTIONW.ByReference pOptions) 
                super();
                this.dwSize = dwSize;
                this.pszConnection = pszConnection;
                this.dwOptionCount = dwOptionCount;
                this.dwOptionError = dwOptionError;
                this.pOptions = pOptions;
                initFieldOrder();
            
            public static class ByReference extends INTERNET_PER_CONN_OPTION_LISTW implements Structure.ByReference 

            ;
            public static class ByValue extends INTERNET_PER_CONN_OPTION_LISTW implements Structure.ByValue 

            ;
        
        /*
        BOOL InternetSetOption(
                  __in  HINTERNET hInternet,
                  __in  DWORD dwOption,
                  __in  LPVOID lpBuffer,
                  __in  DWORD dwBufferLength
                );
         */    
        public boolean InternetSetOption(
                Pointer hInternet, 
                DWORD dwOption,
                Pointer lpBuffer, 
                IntByReference dwBufferLength);

        public boolean InternetSetOption(
                Pointer hInternet, 
                DWORD dwOption,
                WinInet.INTERNET_PER_CONN_OPTION_LISTW lpBuffer, 
                IntByReference dwBufferLength);

        //BOOLAPI InternetQueryOptionW(HINTERNET ,DWORD ,LPVOID ,LPDWORD);  
        public boolean InternetQueryOption(
                Pointer hInternet,
                DWORD dwOption,
                Pointer lpBuffer,
                IntByReference len
                );
        public boolean InternetQueryOption(
                Pointer hInternet,
                DWORD dwOption,
                WinInet.INTERNET_VERSION_INFO lpBuffer,
                IntByReference len
                );
        public boolean InternetQueryOption(
                Pointer hInternet,
                DWORD dwOption,
                WinInet.INTERNET_PER_CONN_OPTION_LISTW lpBuffer,
                IntByReference len
                );


    

WindowsProxy.java:

import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.ptr.IntByReference;

public class WindowsProxy 

    public static void setProxySettings() 

        Pointer hInternet = null;
        IntByReference len = new IntByReference();

        System.out.println("Get version...");

        WinInet.INTERNET_VERSION_INFO versionInfo = null;

        if (!WinInet.INSTANCE.InternetQueryOption(hInternet,WinInet.INTERNET_OPTION_VERSION, versionInfo, len))
        /*
            ERROR_INSUFFICIENT_BUFFER
            122 (0x7A)
            The data area passed to a system call is too small.     
        */
            System.out.println("InternetQueryOption failed!:" + Kernel32.INSTANCE.GetLastError());
        

        versionInfo = new WinInet.INTERNET_VERSION_INFO();

        if (!WinInet.INSTANCE.InternetQueryOption(hInternet,WinInet.INTERNET_OPTION_VERSION, versionInfo, len))
            System.out.println("InternetQueryOption failed!:" + Kernel32.INSTANCE.GetLastError());
        
        System.out.println("Version:" + versionInfo.dwMajorVersion + "." + versionInfo.dwMinorVersion); //IE5+ = 1.2

        System.out.println("Set proxy...");

        WinInet.INTERNET_PER_CONN_OPTION_LISTW optionlist2 = new WinInet.INTERNET_PER_CONN_OPTION_LISTW();

        WinInet.INTERNET_PER_CONN_OPTIONW.ByReference ref2 = new WinInet.INTERNET_PER_CONN_OPTIONW.ByReference();
        WinInet.INTERNET_PER_CONN_OPTIONW[] option2 = (WinInet.INTERNET_PER_CONN_OPTIONW[])ref2.toArray(3);

        option2[0].dwOption = WinInet.INTERNET_PER_CONN_PROXY_SERVER;
        option2[0].Value.pszValue = new WString("http=http://localhost:8080");

        option2[1].dwOption = WinInet.INTERNET_PER_CONN_FLAGS; 
        option2[1].Value.dwValue = new DWORD(WinInet.PROXY_TYPE_PROXY.byteValue() | WinInet.PROXY_TYPE_DIRECT.byteValue());

        option2[2].dwOption = WinInet.INTERNET_PER_CONN_PROXY_BYPASS; 
        option2[2].Value.pszValue = new WString("<local>"); 

        optionlist2.pszConnection = null;
        optionlist2.dwOptionCount = new DWORD(3);
        optionlist2.dwOptionError = new DWORD(0);
        optionlist2.pOptions = ref2;

        if (!WinInet.INSTANCE.InternetSetOption(hInternet,WinInet.INTERNET_OPTION_PER_CONNECTION_OPTION, optionlist2, len))
            System.out.println("InternetSetOption failed!:" + Kernel32.INSTANCE.GetLastError());
        

//      System.out.println("Set changed...");
//      
//      if (!WinInet.INSTANCE.InternetSetOption(hInternet,WinInet.INTERNET_OPTION_SETTINGS_CHANGED, (Pointer)null, len))
//          System.out.println("InternetSetOption failed!:" + Kernel32.INSTANCE.GetLastError());
//      

        System.out.println("Set refreshed...");

        if (!WinInet.INSTANCE.InternetSetOption(hInternet,WinInet.INTERNET_OPTION_REFRESH, (Pointer)null, len))
            System.out.println("InternetSetOption failed!:" + Kernel32.INSTANCE.GetLastError());
        


        System.out.println("Get options...");

        WinInet.INTERNET_PER_CONN_OPTION_LISTW optionlist = new WinInet.INTERNET_PER_CONN_OPTION_LISTW();

        WinInet.INTERNET_PER_CONN_OPTIONW.ByReference ref = new WinInet.INTERNET_PER_CONN_OPTIONW.ByReference();
        WinInet.INTERNET_PER_CONN_OPTIONW[] option = (WinInet.INTERNET_PER_CONN_OPTIONW[])ref.toArray(5);

        option[0].dwOption = WinInet.INTERNET_PER_CONN_AUTOCONFIG_URL;
        option[1].dwOption = WinInet.INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
        option[2].dwOption = WinInet.INTERNET_PER_CONN_FLAGS;
        option[3].dwOption = WinInet.INTERNET_PER_CONN_PROXY_BYPASS;
        option[4].dwOption = WinInet.INTERNET_PER_CONN_PROXY_SERVER;

        optionlist.pszConnection = null;
        optionlist.dwOptionCount = new DWORD(5);
        optionlist.dwOptionError = new DWORD(0);
        optionlist.pOptions = ref;
        optionlist.dwSize = new DWORD(optionlist.size());

        if (!WinInet.INSTANCE.InternetQueryOption(hInternet,WinInet.INTERNET_OPTION_PER_CONNECTION_OPTION, optionlist, len))
        /*
            ERROR_INTERNET_BAD_OPTION_LENGTH
            12010
            The length of an option supplied to InternetQueryOption or InternetSetOption is incorrect for the type of option specified. 
        */

            System.out.println("InternetQueryOption failed!:" + Kernel32.INSTANCE.GetLastError());
        

        if(option[0].Value.pszValue != null)
            System.out.println(option[0].Value.pszValue);

        if((option[2].Value.dwValue.byteValue() & WinInet.PROXY_TYPE_AUTO_PROXY_URL.byteValue()) == WinInet.PROXY_TYPE_AUTO_PROXY_URL.byteValue())
            System.out.println("PROXY_TYPE_AUTO_PROXY_URL");

        if((option[2].Value.dwValue.byteValue() & WinInet.PROXY_TYPE_AUTO_DETECT.byteValue()) == WinInet.PROXY_TYPE_AUTO_DETECT.byteValue())
            System.out.println("PROXY_TYPE_AUTO_DETECT");    

    

    public static void main(String[] args) 
        setProxySettings();
    

输出:

Get version...
InternetQueryOption failed!:122
Version:1.2
Set proxy...
Set refreshed...
Get options...
InternetQueryOption failed!:12010

WindowsProxy.java中的测试代码取自http://support.microsoft.com/kb/226473

已编辑

当进行以下修改(通过将大小值分配给len 对象)时,输出中的InternetQueryOption failed!:12010 错误消失:

len.setValue(optionlist.size());

if (!WinInet.INSTANCE.InternetQueryOption(hInternet,WinInet.INTERNET_OPTION_PER_CONNECTION_OPTION, optionlist, len))
/*
    ERROR_INTERNET_BAD_OPTION_LENGTH
    12010
    The length of an option supplied to InternetQueryOption or InternetSetOption is incorrect for the type of option specified. 
*/

    System.out.println("InternetQueryOption failed!:" + Kernel32.INSTANCE.GetLastError());

【讨论】:

以上是关于调用使用 Java + JNA 的 WinInet 函数的主要内容,如果未能解决你的问题,请参考以下文章

使用JNA,让java调用原生代码

JNA调用DLL简单使用

Java跨语言调用,使用JNA访问Java外部接口

Java JNA 本机库调用 NoClassDefFoundError

使用 JNA 从 Java 调用 C++ dll 方法并避免方法名称修改

JNA调用库文件