沙滩星空的博客沙滩星空的博客

Go语言和C#调用WinAPI(Wininet.dll)修改windows系统代理

Go语言设置windows系统代理

package main

import (
    "flag"
    "fmt"
    "syscall"
    "unsafe"
)

const (
    INTERNET_PER_CONN_FLAGS               = 1
    INTERNET_PER_CONN_PROXY_SERVER        = 2
    INTERNET_PER_CONN_PROXY_BYPASS        = 3
    INTERNET_OPTION_REFRESH               = 37
    INTERNET_OPTION_SETTINGS_CHANGED      = 39
    INTERNET_OPTION_PER_CONNECTION_OPTION = 75
)

/*
typedef struct {
  DWORD dwOption;
  union {
    DWORD    dwValue;
    LPSTR    pszValue;
    FILETIME ftValue;
  } Value;
} INTERNET_PER_CONN_OPTIONA, *LPINTERNET_PER_CONN_OPTIONA;

typedef struct _FILETIME {
  DWORD dwLowDateTime;
  DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
*/
type INTERNET_PER_CONN_OPTION struct {
    dwOption uint32
    dwValue  uint64    // 注意 32位 和 64位 struct 和 union 内存对齐
}

type INTERNET_PER_CONN_OPTION_LIST struct {
    dwSize        uint32
    pszConnection *uint16
    dwOptionCount uint32
    dwOptionError uint32
    pOptions      uintptr
}

func SetProxy(proxy string) error {
    winInet, err := syscall.LoadLibrary("Wininet.dll")
    if err != nil {
        return fmt.Errorf(fmt.Sprintf("LoadLibrary Wininet.dll Error: %s", err))
    }
    InternetSetOptionW, err := syscall.GetProcAddress(winInet, "InternetSetOptionW")
    if err != nil {
        return fmt.Errorf(fmt.Sprintf("GetProcAddress InternetQueryOptionW Error: %s", err))
    }

    options := [3]INTERNET_PER_CONN_OPTION{}
    options[0].dwOption = INTERNET_PER_CONN_FLAGS
    if proxy == "" {
        options[0].dwValue = 1
    } else {
        options[0].dwValue = 2
    }
    options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER
    options[1].dwValue = uint64(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(proxy))))
    options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS
    options[2].dwValue = uint64(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;172.32.*;192.168.*"))))

    list := INTERNET_PER_CONN_OPTION_LIST{}
    list.dwSize = uint32(unsafe.Sizeof(list))
    list.pszConnection = nil
    list.dwOptionCount = 3
    list.dwOptionError = 0
    list.pOptions = uintptr(unsafe.Pointer(&options))

    // https://www.cnpython.com/qa/361707
    callInternetOptionW := func(dwOption uintptr, lpBuffer uintptr, dwBufferLength uintptr) error {
        r1, _, err := syscall.Syscall6(InternetSetOptionW, 4, 0, dwOption, lpBuffer, dwBufferLength, 0, 0)
        if r1 != 1 {
            return err
        }
        return nil
    }

    err = callInternetOptionW(INTERNET_OPTION_PER_CONNECTION_OPTION, uintptr(unsafe.Pointer(&list)), uintptr(unsafe.Sizeof(list)))
    if err != nil {
        return fmt.Errorf("INTERNET_OPTION_PER_CONNECTION_OPTION Error: %s", err)
    }
    err = callInternetOptionW(INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)
    if err != nil {
        return fmt.Errorf("INTERNET_OPTION_SETTINGS_CHANGED Error: %s", err)
    }
    err = callInternetOptionW(INTERNET_OPTION_REFRESH, 0, 0)
    if err != nil {
        return fmt.Errorf("INTERNET_OPTION_REFRESH Error: %s", err)
    }
    return nil
}

func main() {
    proxy := flag.String("p", "127.0.0.1:10809", "(-p host:port 设置并启用代理服务器, -p c 取消设置")
    flag.Parse()
    if *proxy == "c" {
        if err := SetProxy(""); err == nil {
            fmt.Println("取消代理设置成功!")
        } else {
            fmt.Printf("取消代理设置失败: %s\n", err)
        }
    } else {
        if err := SetProxy(*proxy); err == nil {
            fmt.Printf("设置代理服务器: %s 成功!\n", *proxy)
        } else {
            fmt.Printf("设置代理服务器: %s 失败, : %s\n", *proxy, err)
        }
    }
}

C#语言设置windows系统代理

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace proxysetting
{
    public class ProxyManager
    {
        [DllImport("wininet.dll", SetLastError = true)]
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lPBuffer, int lpdwBufferLength);
        private const int INTERNET_OPTION_REFRESH = 0x000025;
        private const int INTERNET_OPTION_SETTINGS_CHANGED = 0x000027;
        private const string regeditKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
        private List<string> proxyLibs = new List<string>();

        private void Reflush()
        {
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
        }

        public void Add(string server)
        {
            this.proxyLibs.Add(server);
        }

        public void Run()
        {
            RegistryKey key = Registry.CurrentUser.OpenSubKey(regeditKey, true);
            key.SetValue("ProxyServer", String.Join(";", this.proxyLibs.ToArray()));
            key.SetValue("ProxyEnable", 1);
            key.Close();
            this.Reflush();
        }

        public void Stop()
        {
            RegistryKey key = Registry.CurrentUser.OpenSubKey(regeditKey, true);
            key.SetValue("ProxyEnable", 0);
            key.Close();
            this.Reflush();
        }
    }
}

封装至主程序:

namespace proxysetting
{
    class Program
    {
        static void Main(string[] args)
        {

            var pm = new ProxyManager();
            if (args.Length < 1) return;
            if (args[0] == "stop")
            {
                pm.Stop();
            }
            else
            {
                for (var i = 0; i < args.Length; i++)
                {
                    pm.Add(args[i]);
                }
                pm.Run();
            }
        }
    }
}

通过命令行传递参数调用:

# 设置http和https代理,代理ip为127.0.0.1,端口号17173
proxysetting http=127.0.0.1:17173 https=127.0.0.1:17173

# 取消代理
proxysetting stop

修改注册表设置windows系统代理

控制系统代理的2个注册表:

计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable
计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer

代码实现(无法立即生效,可能要重启电脑):

package main

import (
    "bytes"
    "encoding/binary"
    "flag"
    "fmt"

    "os"
    "os/exec"

    "golang.org/x/sys/windows/registry"
)

var setproxy string
var unsetproxy bool

func main() {
    var err error
    flag.StringVar(&setproxy, "setproxy", "", "set sys proxy")
    flag.BoolVar(&unsetproxy, "unsetproxy", false, "unset sys proxy")
    flag.Parse()
    if setproxy != "" {
        err = setProxy(setproxy)
        if err != nil {
            fmt.Println("设置代理失败:", err)
            panic(err)
        }
        fmt.Println("代理已设置:", setproxy)
        return
    }
    if unsetproxy {
        // 取消代理
        err = unsetProxy()
        if err != nil {
            fmt.Println("取消代理失败:", err)
            panic(err)
        }
        fmt.Println("代理已取消")
    }
}

func getRegistryKey() (k registry.Key, err error) {
    registryKeyPath := `Software\Microsoft\Windows\CurrentVersion\Internet Settings`
    k, exist, err := registry.CreateKey(registry.CURRENT_USER, registryKeyPath, registry.ALL_ACCESS)
    if err != nil {
        return k, err
    }
    if !exist {
        panic(registryKeyPath + "not existed")
    }
    return k, nil
}

func setProxy(proxyAddress string) error {
    k, err := getRegistryKey()
    if err != nil {
        return err
    }
    defer k.Close()

    // 设置代理
    err = k.SetStringValue("ProxyServer", proxyAddress)
    if err != nil {
        return err
    }

    // 启用代理
    // err = k.SetBinaryValue("ProxyEnable", IntToBytes(1))
    err = k.SetDWordValue("ProxyEnable", 1)
    if err != nil {
        return err
    }

    return refreshProxy()
}

func refreshProxy() error {
    var err error
    // 刷新系统代理设置
    // InetCpl.cpl 出错 丢失条目: ProxyRunDll
    cmd := exec.Command("Rundll32.exe", "InetCpl.cpl,ProxyRunDll")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err = cmd.Run()
    if err != nil {
        return err
    }
    return nil
}

func unsetProxy() error {
    // 禁用代理
    k, err := getRegistryKey()
    if err != nil {
        return err
    }
    defer k.Close()
    // err = k.SetBinaryValue("ProxyEnable", IntToBytes(0))
    err = k.SetDWordValue("ProxyEnable", 0)
    if err != nil {
        return err
    }

    return refreshProxy()
}

func IntToBytes(n int) []byte {
    x := int32(n)
    bytesBuffer := bytes.NewBuffer([]byte{})
    binary.Write(bytesBuffer, binary.BigEndian, x)
    return bytesBuffer.Bytes()
}

Golang sysproxy https://blog.csdn.net/q1009020096/article/details/108181729
Golang 调用WinAPI 修改代理 https://blog.csdn.net/leoforbest/article/details/120166881
使用程序修改系统(IE)代理设置 https://www.cnblogs.com/honghongming/archive/2014/01/24/3532567.html
用代码为windows设置代理(修改注册表)https://codeleading.com/article/29115078136/
Go 命令行桌面版设置代理(可能是AI生成的,代码跑不了,Rundll32.exe命令也报错) https://www.jianshu.com/p/d2cf825ce93b

未经允许不得转载:沙滩星空的博客 » Go语言和C#调用WinAPI(Wininet.dll)修改windows系统代理

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址