检测 IE 代理设置并与 TIdHTTP 一起使用
Posted
技术标签:
【中文标题】检测 IE 代理设置并与 TIdHTTP 一起使用【英文标题】:Detecting IE Proxy settings and using with TIdHTTP 【发布时间】:2012-02-16 04:33:39 【问题描述】:如何设置 TIdHTTP 以使用 IE 代理配置? 应该兼容XP/Vista/Win7,可靠。
【问题讨论】:
【参考方案1】:Indy 不使用 Internet Explorer 的代理设置,因此您必须自己获取它,例如使用 InternetQueryOption
函数。
更新:
这是使用WinHTTP
的代码,它应该尝试从 IE 接收设置。如果它们可用并且设置了 自动检测代理设置 或 自动配置脚本 URL 选项,则将执行代理检测。当 IE 设置不可用时,也会执行自动检测。
免责声明:
以下代码仅针对最简单的情况进行了测试,即 IE 设置可用且代理设置未配置为自动检测(没有环境)。另请注意,本单元中的一些函数、结构和常量是附加的。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
Private declarations
public
Public declarations
end;
type
HINTERNET = Pointer;
$EXTERNALSYM HINTERNET
INTERNET_PORT = Word;
$EXTERNALSYM INTERNET_PORT
PWinHTTPProxyInfo = ^TWinHTTPProxyInfo;
WINHTTP_PROXY_INFO = record
dwAccessType: DWORD;
lpszProxy: LPWSTR;
lpszProxyBypass: LPWSTR;
end;
$EXTERNALSYM WINHTTP_PROXY_INFO
TWinHTTPProxyInfo = WINHTTP_PROXY_INFO;
LPWINHTTP_PROXY_INFO = PWinHTTPProxyInfo;
$EXTERNALSYM LPWINHTTP_PROXY_INFO
PWinHTTPAutoProxyOptions = ^TWinHTTPAutoProxyOptions;
WINHTTP_AUTOPROXY_OPTIONS = record
dwFlags: DWORD;
dwAutoDetectFlags: DWORD;
lpszAutoConfigUrl: LPCWSTR;
lpvReserved: Pointer;
dwReserved: DWORD;
fAutoLogonIfChallenged: BOOL;
end;
$EXTERNALSYM WINHTTP_AUTOPROXY_OPTIONS
TWinHTTPAutoProxyOptions = WINHTTP_AUTOPROXY_OPTIONS;
LPWINHTTP_AUTOPROXY_OPTIONS = PWinHTTPAutoProxyOptions;
$EXTERNALSYM LPWINHTTP_AUTOPROXY_OPTIONS
PWinHTTPCurrentUserIEProxyConfig = ^TWinHTTPCurrentUserIEProxyConfig;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG = record
fAutoDetect: BOOL;
lpszAutoConfigUrl: LPWSTR;
lpszProxy: LPWSTR;
lpszProxyBypass: LPWSTR;
end;
$EXTERNALSYM WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
TWinHTTPCurrentUserIEProxyConfig = WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
LPWINHTTP_CURRENT_USER_IE_PROXY_CONFIG = PWinHTTPCurrentUserIEProxyConfig;
$EXTERNALSYM LPWINHTTP_CURRENT_USER_IE_PROXY_CONFIG
function WinHttpOpen(pwszUserAgent: LPCWSTR; dwAccessType: DWORD;
pwszProxyName, pwszProxyBypass: LPCWSTR; dwFlags: DWORD): HINTERNET; stdcall;
external 'winhttp.dll' name 'WinHttpOpen';
$EXTERNALSYM WinHttpOpen
function WinHttpConnect(hSession: HINTERNET; pswzServerName: LPCWSTR;
nServerPort: INTERNET_PORT; dwReserved: DWORD): HINTERNET; stdcall;
external 'winhttp.dll' name 'WinHttpConnect';
$EXTERNALSYM WinHttpConnect
function WinHttpOpenRequest(hConnect: HINTERNET; pwszVerb: LPCWSTR;
pwszObjectName: LPCWSTR; pwszVersion: LPCWSTR; pwszReferer: LPCWSTR;
ppwszAcceptTypes: PLPWSTR; dwFlags: DWORD): HINTERNET; stdcall;
external 'winhttp.dll' name 'WinHttpOpenRequest';
$EXTERNALSYM WinHttpOpenRequest
function WinHttpQueryOption(hInet: HINTERNET; dwOption: DWORD;
lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall;
external 'winhttp.dll' name 'WinHttpQueryOption';
$EXTERNALSYM WinHttpQueryOption
function WinHttpGetProxyForUrl(hSession: HINTERNET; lpcwszUrl: LPCWSTR;
pAutoProxyOptions: LPWINHTTP_AUTOPROXY_OPTIONS;
var pProxyInfo: WINHTTP_PROXY_INFO): BOOL; stdcall;
external 'winhttp.dll' name 'WinHttpGetProxyForUrl';
$EXTERNALSYM WinHttpGetProxyForUrl
function WinHttpGetIEProxyConfigForCurrentUser(
var pProxyInfo: WINHTTP_CURRENT_USER_IE_PROXY_CONFIG): BOOL; stdcall;
external 'winhttp.dll' name 'WinHttpGetIEProxyConfigForCurrentUser';
$EXTERNALSYM WinHttpGetIEProxyConfigForCurrentUser
function WinHttpCloseHandle(hInternet: HINTERNET): BOOL; stdcall;
external 'winhttp.dll' name 'WinHttpCloseHandle';
$EXTERNALSYM WinHttpCloseHandle
const
WINHTTP_NO_REFERER = nil;
$EXTERNALSYM WINHTTP_NO_REFERER
WINHTTP_NO_PROXY_NAME = nil;
$EXTERNALSYM WINHTTP_NO_PROXY_NAME
WINHTTP_NO_PROXY_BYPASS = nil;
$EXTERNALSYM WINHTTP_NO_PROXY_BYPASS
WINHTTP_DEFAULT_ACCEPT_TYPES = nil;
$EXTERNALSYM WINHTTP_DEFAULT_ACCEPT_TYPES
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0;
$EXTERNALSYM WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
WINHTTP_ACCESS_TYPE_NO_PROXY = 1;
$EXTERNALSYM WINHTTP_ACCESS_TYPE_NO_PROXY
WINHTTP_OPTION_PROXY = 38;
$EXTERNALSYM WINHTTP_OPTION_PROXY
WINHTTP_OPTION_PROXY_USERNAME = $1002;
$EXTERNALSYM WINHTTP_OPTION_PROXY_USERNAME
WINHTTP_OPTION_PROXY_PASSWORD = $1003;
$EXTERNALSYM WINHTTP_OPTION_PROXY_PASSWORD
WINHTTP_AUTOPROXY_AUTO_DETECT = $00000001;
$EXTERNALSYM WINHTTP_AUTOPROXY_AUTO_DETECT
WINHTTP_AUTOPROXY_CONFIG_URL = $00000002;
$EXTERNALSYM WINHTTP_AUTOPROXY_CONFIG_URL
WINHTTP_AUTO_DETECT_TYPE_DHCP = $00000001;
$EXTERNALSYM WINHTTP_AUTO_DETECT_TYPE_DHCP
WINHTTP_AUTO_DETECT_TYPE_DNS_A = $00000002;
$EXTERNALSYM WINHTTP_AUTO_DETECT_TYPE_DNS_A
WINHTTP_FLAG_BYPASS_PROXY_CACHE = $00000100;
$EXTERNALSYM WINHTTP_FLAG_BYPASS_PROXY_CACHE
WINHTTP_FLAG_REFRESH = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
$EXTERNALSYM WINHTTP_FLAG_REFRESH
var
Form1: TForm1;
implementation
$R *.dfm
type
TProxyInfo = record
ProxyURL: WideString;
ProxyBypass: WideString;
ProxyAutoDetected: Boolean;
end;
function GetProxyInfo(const AURL: WideString; var AProxyInfo: TProxyInfo): DWORD;
var
Session: HINTERNET;
AutoDetectProxy: Boolean;
WinHttpProxyInfo: TWinHTTPProxyInfo;
AutoProxyOptions: TWinHTTPAutoProxyOptions;
IEProxyConfig: TWinHTTPCurrentUserIEProxyConfig;
begin
// initialize the result
Result := 0;
// initialize auto-detection to off
AutoDetectProxy := False;
// initialize the result structure
AProxyInfo.ProxyURL := '';
AProxyInfo.ProxyBypass := '';
AProxyInfo.ProxyAutoDetected := False;
// initialize the auto-proxy options
FillChar(AutoProxyOptions, SizeOf(AutoProxyOptions), 0);
// check if the Internet Explorer's proxy configuration is
// available and if so, check its settings for auto-detect
// proxy settings and auto-config script URL options
if WinHttpGetIEProxyConfigForCurrentUser(IEProxyConfig) then
begin
// if the Internet Explorer is configured to auto-detect
// proxy settings then we try to detect them later on
if IEProxyConfig.fAutoDetect then
begin
AutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT;
AutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or
WINHTTP_AUTO_DETECT_TYPE_DNS_A;
AutoDetectProxy := True;
end;
// if the Internet Explorer is configured to use the proxy
// auto-config script then we try to use it
if IEProxyConfig.lpszAutoConfigURL <> '' then
begin
AutoProxyOptions.dwFlags := AutoProxyOptions.dwFlags or
WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl := IEProxyConfig.lpszAutoConfigUrl;
AutoDetectProxy := True;
end;
// if IE don't have auto-detect or auto-config set, we are
// done here and we can fill the AProxyInfo with the IE settings
if not AutoDetectProxy then
begin
AProxyInfo.ProxyURL := IEProxyConfig.lpszProxy;
AProxyInfo.ProxyBypass := IEProxyConfig.lpszProxyBypass;
AProxyInfo.ProxyAutoDetected := False;
end;
end
else
begin
// if the Internet Explorer's proxy configuration is not
// available, then try to auto-detect it
AutoProxyOptions.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT;
AutoProxyOptions.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP or
WINHTTP_AUTO_DETECT_TYPE_DNS_A;
AutoDetectProxy := True;
end;
// if the IE proxy settings are not available or IE has
// configured auto-config script or auto-detect proxy settings
if AutoDetectProxy then
begin
// create a temporary WinHttp session to allow the WinHTTP
// auto-detect proxy settings if possible
Session := WinHttpOpen(nil, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
// if the WinHttp session has been created then try to
// get the proxy data for the specified URL else we assign
// the last error code to the function result
if Assigned(Session) then
try
// get the proxy data for the specified URL with the
// auto-proxy options specified, if succeed then we can
// fill the AProxyInfo with the retrieved settings else
// we assign the last error code to the function result
if WinHttpGetProxyForUrl(Session, LPCWSTR(AURL),
@AutoProxyOptions, WinHttpProxyInfo) then
begin
AProxyInfo.ProxyURL := WinHttpProxyInfo.lpszProxy;
AProxyInfo.ProxyBypass := WinHttpProxyInfo.lpszProxyBypass;
AProxyInfo.ProxyAutoDetected := True;
end
else
Result := GetLastError;
finally
WinHttpCloseHandle(Session);
end
else
Result := GetLastError;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Result: DWORD;
ProxyInfo: TProxyInfo;
begin
Result := GetProxyInfo('http://www.example.com', ProxyInfo);
case Result of
0:
ShowMessage(
'Proxy URL: ' + ProxyInfo.ProxyURL + sLineBreak +
'Proxy bypass: ' + ProxyInfo.ProxyBypass + sLineBreak +
'Proxy autodetected: ' + BoolToStr(ProxyInfo.ProxyAutoDetected, True));
12166: ShowMessage('Error in proxy auto-config script code');
12167: ShowMessage('Unable to download proxy auto-config script');
12180: ShowMessage('WPAD detection failed');
else
ShowMessage('Last error: ' + IntToStr(Result));
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown := True;
end;
end.
对于替代的 Delphi 代码,您可以检查例如this tip
.
下面是一个如何使用获得的代理设置设置TIdHTTP
的示例(实际上您只需解析获得的代理URL 并将其传递给ProxyServer
和ProxyPort
属性):
uses
IdGlobal;
procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
Result: DWORD;
ProxyInfo: TProxyInfo;
begin
Result := GetProxyInfo('http://www.example.com', ProxyInfo);
if Result <> 0 then
IdHTTP1.ProxyParams.Clear
else
begin
S := ProxyInfo.ProxyURL;
IdHTTP1.ProxyParams.ProxyServer := Fetch(S, ':');
IdHTTP1.ProxyParams.ProxyPort := StrToInt(S);
end;
end;
【讨论】:
“旧”delphi 代码是什么意思?还会支持Web Proxy Autodiscovery Protocol吗? @zigi70,Yahia 添加的链接注释很可能意味着代码示例已有 7 年历史。对于是否支持 WPAD 的问题,是的,但您可能会遇到诸如this
之类的问题。 InternetQueryOption
函数用于定位 Internet Explorer 最近检测到的代理配置脚本,因此如果您启用了 WPAD
并且您已连接,那么您可能会获得之前自动检测到的最新设置。
@TLama,我应该使用 InternetQueryOption 还是 WinHttpGetIEProxyConfigForCurrentUser?
@zigi70,现在我正在查看它(以前没有代理自动检测的经验),但似乎更多人更喜欢使用 WinHttpGetProxyForUrl
的解决方案,您可以在其中指定目标 URL ,因此代理服务器可能会为您提供正确的自动设置和WinHttpGetIEProxyConfigForCurrentUser
功能,如果之前失败(如this answer
推荐)。
@TLamaת 如果代理有用户名+密码会发生什么。如何检索此信息。看来我迷路了……【参考方案2】:
您也可以通过 Windows 注册表获取它:
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
Reg.RootKey := HKEY_CURRENT_USER;
Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Internet Settings',false);
Caption :=Reg.ReadString('ProxyServer');
Reg.Free;
end;
【讨论】:
以上是关于检测 IE 代理设置并与 TIdHTTP 一起使用的主要内容,如果未能解决你的问题,请参考以下文章