设置与获取系统代理信息

设置与读取上图中的脚本地址,用于HTTP请求与下载时可以走代理环境

 

 

头文件

#include"wininet.h"
#pragma comment(lib, "Wininet.lib")

 

给系统设置代理信息

#if defined(OS_WIN)
 
BOOL SetSystemProxyFromPacUrl(wchar_t* conn_name, wchar_t* proxy_full_addr) {
    //conn_name: active connection name.
    //proxy_full_addr : eg "210.78.22.87:8000"
    INTERNET_PER_CONN_OPTION_LISTW list;
    BOOL bReturn;
    DWORD dwBufSize = sizeof(list);
 
    // Fill out list struct.
    list.dwSize = sizeof(list);
 
    // NULL == LAN, otherwise connectoid name.
    list.pszConnection = conn_name;
 
    // Set three options.
    list.dwOptionCount = 2;
    list.pOptions = new INTERNET_PER_CONN_OPTIONW[2];
 
    // Make sure the memory was allocated.
    if (NULL == list.pOptions) {
        // Return FALSE if the memory wasn't allocated.
        LOG_ERROR << "failed to allocat memory in SetConnectionOptions()";
        return FALSE;
    }
 
    // Set flags.
    list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
     list.pOptions[0].Value.dwValue = PROXY_TYPE_AUTO_PROXY_URL;
 
    // Set proxy name.
    list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
    list.pOptions[1].Value.pszValue = proxy_full_addr;
 
    // Set the options on the connection.
    bReturn = InternetSetOption(NULL,
                   INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);
 
    // Free the allocated memory.
    delete[] list.pOptions;
 
    InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
    InternetSetOption(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
 
    return bReturn;
}
#else
bool SetSystemProxyFromPacUrl(const std::string& pacUrl) {
    if (!base::dbus::CallMethodWithNoResult(
        base::dbus::Type::kSession, "com.deepin.daemon.Network", "SetAutoProxy", pacUrl)) {
        LOG_ERROR << "SetAutoProxy call failed.";
        return false;
    }
    return base::dbus::CallMethodWithNoResult(
        base::dbus::Type::kSession, "com.deepin.daemon.Network", "SetProxyMethod", "auto");
}
#endif

 

 

读取系统设置代理信息

方式1:

BOOL QueryProxy() {
    BOOL ret = FALSE;
 
    INTERNET_PER_CONN_OPTION_LIST List;
    INTERNET_PER_CONN_OPTION Option[5];
 
    unsigned long nSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
 
    Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
    Option[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
    Option[2].dwOption = INTERNET_PER_CONN_FLAGS;
    Option[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
    Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
 
    List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
    List.pszConnection = NULL;
    List.dwOptionCount = 5;
    List.dwOptionError = 0;
    List.pOptions = Option;
 
    if (!InternetQueryOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
        _tprintf(_T("InternetQueryOption failed! (%d)\n"), GetLastError());
    if (Option[0].Value.pszValue != NULL)
        _tprintf(_T("%s\n"), Option[0].Value.pszValue);
    if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL)
        _tprintf(_T("PROXY_TYPE_AUTO_PROXY_URL\n"));
    if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT)
        _tprintf(_T("PROXY_TYPE_AUTO_DETECT\n"));
    if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) {
        _tprintf(_T("Proxy ENABLED!\n"));
        ret = TRUE;
    } else _tprintf(_T("Proxy DISABLED!\n"));
 
    _tprintf(_T("Current proxy:%s\n"), Option[4].Value.pszValue);
 
    INTERNET_VERSION_INFO Version;
    nSize = sizeof(INTERNET_VERSION_INFO);
 
    InternetQueryOption(NULL, INTERNET_OPTION_VERSION, &Version, &nSize)
    if (Option[0].Value.pszValue != NULL)
        GlobalFree(Option[0].Value.pszValue);
    if (Option[3].Value.pszValue != NULL)
        GlobalFree(Option[3].Value.pszValue);
    if (Option[4].Value.pszValue != NULL)
        GlobalFree(Option[4].Value.pszValue);
    return ret;
}

 

方式2:

BOOL GetWinetProxy(LPSTR lpszProxy, UINT nProxyLen) {
    //unsigned long nSize = 4096;
    //char szBuf[4096] = { 0 };
    //INTERNET_PROXY_INFO* pProxyInfo = (INTERNET_PROXY_INFO*)szBuf;
    //if (!InternetQueryOption(NULL, INTERNET_OPTION_PROXY, pProxyInfo, &nSize)) {
    // return FALSE;
    //}
    //if (pProxyInfo->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
    // return FALSE;
    //}
 
    ////这里是代理列表,以\0分隔,结束处两个\0\0,一般我们取第一条代理就够了
    //LPCSTR lpszProxyList = (LPCSTR)(pProxyInfo + 1);
    //int nLen = strlen(lpszProxyList);
    //if (lpszProxy) {
    // nProxyLen = min(nLen, nProxyLen - 1);
    // strncpy_s(lpszProxy, nProxyLen + 1, lpszProxyList, nLen);
    // lpszProxy[nProxyLen] = 0;
    //}
    //return nLen;
 
 
    // 方法2
    INTERNET_PER_CONN_OPTION_LISTA List;
    INTERNET_PER_CONN_OPTIONA Option[1];
    unsigned long nSize = sizeof(INTERNET_PER_CONN_OPTION_LISTA);
    Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
 
    List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
    List.pszConnection = NULL;
    List.dwOptionCount = 1;
    List.dwOptionError = 0;
    List.pOptions = Option;
 
    if (!InternetQueryOptionA(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
        return FALSE;
    }
 
    if (Option[0].Value.pszValue != NULL) {
        int nLen = strlen(Option[0].Value.pszValue);
        if (lpszProxy) {
            nProxyLen = min(nLen, nProxyLen - 1);
            strncpy_s(lpszProxy, nProxyLen + 1, Option[0].Value.pszValue, nProxyLen);
            lpszProxy[nProxyLen] = 0;
        }
        GlobalFree(Option[0].Value.pszValue);
        return nLen;
    }
    return FALSE;
}

 

(看到上面的辣么多方法,系不系狠鸡冻。别急着拷代码,先看完“使用说明”)
神坑、巨坑、无底洞--以上的方式只适用于用户进程、管理员进程;不适用于服务进程!!!

 

原因:从微软官方文档看,当程序时服务时,Microsoft Win32 Internet将不给予支持。即wininet.h、wininet.lib不能适用

链接:

https://docs.microsoft.com/zh-cn/troubleshoot/browsers/wininet-not-supported-in-services

https://docs.microsoft.com/en-us/windows/win32/api/wininet/ns-wininet-internet_per_conn_optiona

 

 

本质原因:上述的方法,无论API获取还是查询代理列表,都是读取注册表。但是这些信息都存在于“HKEY_CURRENT_USER”根目录下。即服务进程无法读取或写入的目录

如图:

 

 

解决方法:

(一)模拟一个普通用户登陆,可以操作 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion

(二) 获取 SID,操作HKEY_CURRENT_USER被重定向到 HKEY_USERS 的值。

参考链接:https://blog.csdn.net/zhouguangcai8/article/details/28280449

 

方法1实现:

#if defined(OS_WIN)
#include <windows.h>
#include <Wtsapi32.h>
#include <UserEnv.h>
#pragma comment(lib, "WtsApi32.lib")
#pragma comment(lib,"Userenv.lib")
#pragma comment(lib, "WtsApi32.lib")
#endif
 
bool GetSystemProxyUrl(std::string& proxyUrl) {
    HANDLE hToken = NULL;
    BOOL bImpersonated = FALSE;
    PROFILEINFOA cuProfileInfo;
    TCHAR szUsername[MAX_PATH];
    DWORD dwUsernameLen = MAX_PATH;
    DWORD seesionid = WTSGetActiveConsoleSessionId();
    bool isSuccess = false;
    if (WTSQueryUserToken(seesionid, &hToken)) {
        if (ImpersonateLoggedOnUser(hToken)) {
            bImpersonated = TRUE;
        }
 
        if (!GetUserName(szUsername, &dwUsernameLen)) {
            LOG_WARN << "Failed to GetUserName.errCode:" << std::to_string(GetLastError());
            return false;
        }
 
        memset(&cuProfileInfo, 0, sizeof(cuProfileInfo));
        cuProfileInfo.dwSize = sizeof(PROFILEINFOA);
        cuProfileInfo.lpUserName = szUsername;
        cuProfileInfo.dwFlags = 1;
 
        if (bImpersonated) {
            RevertToSelf();
            bImpersonated = FALSE;
        }
 
        HKEY hKey;
        char szTmp[256] = { 0 };
        if (LoadUserProfile(hToken, &cuProfileInfo)) {
            LONG lRet = RegOpenKeyEx((struct HKEY__ *)cuProfileInfo.hProfile,
                                     "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
                                     0, KEY_ALL_ACCESS, &hKey);
            if (lRet == ERROR_SUCCESS) {
                DWORD dwLen = 255;
                RegQueryValueEx(hKey, "AutoConfigURL", NULL, NULL, (unsigned char*)szTmp, &dwLen);
                if (szTmp[0] != 0) {
                    proxyUrl = std::string(szTmp);
                    isSuccess = true;
                }
                RegCloseKey(hKey);
            }else {
                LOG_WARN << "Failed to RegOpenKeyEx.errCode:" << std::to_string(GetLastError());
            }
        } else {
            LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER,
                           "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
                            0, KEY_ALL_ACCESS, &hKey);
            if (lRet == ERROR_SUCCESS) {
                DWORD dwLen = 255;
                RegQueryValueEx(hKey, "AutoConfigURL", NULL, NULL, (unsigned char*)szTmp, &dwLen);
                if (szTmp[0] != 0) {
                    proxyUrl = std::string(szTmp);
                    isSuccess = true;
                }
                RegCloseKey(hKey);
            }else {
                LOG_WARN << "Failed to LoadUserProfile and RegOpenKeyEx.errCode:" << std::to_string(GetLastError());
            }
        }
    }
    return isSuccess ? true : false;
}

 

 

 

 

 

 

 

 

 

 
 
 
 
 
 

 

posted @ 2021-07-18 22:37  gd_沐辰  阅读(1028)  评论(0编辑  收藏  举报