如何获取Windows系统的代理服务器地址 C++ API

目录

背景

官方文档地址

官方文档内容

在会话上设置代理配置

应用程序在用户帐户上运行

应用程序作为服务运行

在单个请求上设置代理配置

使用自动代理配置

不使用自动代理配置

示例代码

其他方法


背景

客户端应用程序在用户设置了系统代理后如何保证正常运行,方法一般有二:1)客户端支持用户手动配置代理;2)支持自动获取系统代理(类新版Chrome)。为在windows系统下实现方法2中的系统代理信息获取,特查了下windows官方文档,现将关键内容及测试代码整理如下。

官方文档地址

在 WinHTTP 中设置 WinINet 代理配置 - Win32 apps | Microsoft Learn

官方文档内容

在会话上设置代理配置

应用程序在用户帐户上运行

在创建会话之前,应用程序会调用 WinHttpGetIEProxyConfigForCurrentUser 来获取 IE 代理设置。 应用程序必须以用户帐户身份运行才能获取这些设置。 pProxyConfig 参数是指向WINHTTP_CURRENT_USER_IE_PROXY_CONFIG结构的指针,该结构包含代理名称 (lpszProxy) 和代理绕过 (lpszProxyBypass) 服务器。 然后使用 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 结构的代理名称和代理绕过值来初始化 WinHTTP 会话。 通过使用从 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 结构的lpszProxy 和 lpszProxyBypass 成员获取的 pwszProxyName 和 pwszProxyBypass 参数调用 WinHttpOpen 来初始化会话。

应用程序作为服务运行

应用程序必须确保在调用 WinHttpGetIEProxyConfigForCurrentUser 之前将单个用户的注册表设置加载到注册表中。 如果未将这些设置加载到注册表中, WinHttpGetIEProxyConfigForCurrentUser 将无法获取代理设置。 可以通过调用 LoadUserProfile 函数将单个用户的注册表设置加载到注册表中。 如果无法加载用户的注册表设置,应用程序可以使用 dwAcessType 参数中指定的WINHTTP_ACCESS_TYPE_DEFAULT_PROXY调用 WinHttpOpen。 在调用 WinHttpOpen 时指定默认代理会告知 WinHTTP API 使用 WinHTTP proxycfg.exe 实用工具检索代理配置集。 加载单个用户的注册表设置后,应用程序将按照 应用程序在用户帐户上运行 下概述的步骤来设置代理名称和代理绕过服务器。

在单个请求上设置代理配置

在创建会话之前,应用程序调用 WinHttpGetIEProxyConfigForCurrentUser 以确定 WinINet 和 IE 是否配置为使用 WPAD。 WinHttpGetIEProxyConfigForCurrentUser 返回包含 fAutoDetect 成员的 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 结构。 此成员的值为 TRUE 表示使用了 WPAD,并且 lpszAutoConfigUrl 成员包含 WPAD URL。

使用自动代理配置

如果使用 WPAD,应用程序会调用 WinHttpGetProxyForUrl 来检索请求的代理。 lpwszUrl 参数包含请求要发送到的 URL,pAutoProxyOptions 参数包含指向包含 autoproxy 选项WINHTTP_AUTOPROXY_OPTIONS) 结构的指针 (。 应用程序使用调用 WinHttpGetIEProxyConfigForCurrentUser 时从 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 结构返回的设置初始化 WINHTTP_AUTOPROXY_OPTIONS 结构。 WINHTTP_AUTOPROXY_CONFIG_URL 标志在 WINHTTP_AUTOPROXY_OPTIONS 结构的 dwFlags 成员中指定,lpszAutoconfigUrl 成员包含WINHTTP_CURRENT_USER_IE_PROXY_CONFIG结构的代理自动配置 URL。 WinHttpGetProxyForUrl 函数返回WINHTTP_PROXY_INFO结构的 lpszProxy 和 lpszProxyBypass 成员中的代理名称和代理绕过列表。

从 WinHttpGetProxyForUrl 获取请求的代理后,应用程序使用 WinHttpOpenRequest 创建请求。 然后调用 WinHttpSetOption ,通过在 hInternet 参数中指定请求句柄来设置请求的代理。 调用 WinHttpSetOption 中的 dwOption 参数应设置为 WINHTTP_OPTION_PROXYlpBuffer 参数是指向包含要用于请求的代理和代理旁路的WINHTTP_PROXY_INFO结构的指针。

不使用自动代理配置

如果对 WinHttpGetIEProxyConfigForCurrentUser 的 调用指示不使用 autoproxy,则应用程序只需使用 WinHttpOpenRequest 创建请求。 代理配置对整个会话都是相同的,并且不需要按请求进行更改。

示例代码

应用程序在用户帐户上运行:

#include "winhttp.h"
#pragma comment(lib, "Winhttp.lib")
void testGetIEProxy()
{
    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG pProxyConfig;
    pProxyConfig.fAutoDetect = TRUE;
    WinHttpGetIEProxyConfigForCurrentUser(&pProxyConfig);
    _tprintf(_T("fAutoDetect:%d\n"), pProxyConfig.fAutoDetect);
    _tprintf(_T("lpszAutoConfigUrl:%ls\n"), pProxyConfig.lpszAutoConfigUrl);
    _tprintf(_T("lpszProxy:%ls\n"), pProxyConfig.lpszProxy);
    _tprintf(_T("lpszProxyBypass:%ls\n"), pProxyConfig.lpszProxyBypass);
}

应用程序作为服务运行,可参考上文说明,前置调用 LoadUserProfile 函数。

其他方法

基于 wininet 提供的方法也可实现同样的需求,可对照官网文档进行使用。

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

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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值