设置与获取系统代理信息
设置与读取上图中的脚本地址,用于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; }