IEのProxy設定を取得する その2

前回の記事を書いてから良く考えて見直してみると、Proxyの例外を無視してます。
それに、「設定を自動的に検出する」とか「自動構成スクリプトを使用する」にチェックが入ってると機能しないんじゃないかと。
そこで、その辺りも加味してProxyを取得する関数をここを参考に作ってみました。
HOSTが例外に該当するかのチェックに正規表現使って確認してるんですが、こういうのの定石みたいな方法あるんですかね?ネットで調べて見たらPathMatchSpecを使ってチェックしてるソースもあったんですけど、それもどうなのか判断つきませんでした。

unit ProxyUtils;

interface

uses
  Windows, WinInet, IdURI, StrUtils, RegularExpressions, Classes, SysUtils;

type
 // winhttp.h から必要な定義をコピー
  PWINHTTP_CURRENT_USER_IE_PROXY_CONFIG = ^TWINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
  TWINHTTP_CURRENT_USER_IE_PROXY_CONFIG = record
    fAutoDetect: BOOL;
    lpszAutoConfigUrl: LPWSTR;
    lpszProxy: LPWSTR;
    lpszProxyBypass: LPWSTR;
  end;
  PWINHTTP_AUTOPROXY_OPTIONS = ^TWINHTTP_AUTOPROXY_OPTIONS;
  TWINHTTP_AUTOPROXY_OPTIONS = record
    dwFlags: DWORD;
    dwAutoDetectFlags: DWORD;
    lpszAutoConfigUrl: LPCWSTR;
    lpvReserved: LPVOID;
    dwReserved: DWORD;
    fAutoLogonIfChallenged: BOOL;
  end;
  PWINHTTP_PROXY_INFO = ^TWINHTTP_PROXY_INFO;
  TWINHTTP_PROXY_INFO = record
    dwAccessType: DWORD;       // see WINHTTP_ACCESS_* types below
    lpszProxy: LPWSTR;         // proxy server list
    lpszProxyBypass: LPWSTR;   // proxy bypass list
  end;

const
// WinHttpOpen dwAccessType values (also for WINHTTP_PROXY_INFO::dwAccessType)
  WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0;
  WINHTTP_ACCESS_TYPE_NO_PROXY = 1;
  WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3;

// WinHttpOpen prettifiers for optional parameters
  WINHTTP_NO_PROXY_NAME = Nil;
  WINHTTP_NO_PROXY_BYPASS = Nil;

  WINHTTP_AUTOPROXY_AUTO_DETECT = $00000001;
  WINHTTP_AUTOPROXY_CONFIG_URL = $00000002;
  WINHTTP_AUTOPROXY_RUN_INPROCESS = $00010000;
  WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY = $00020000;
//
// Flags for dwAutoDetectFlags
//
  WINHTTP_AUTO_DETECT_TYPE_DHCP = $00000001;
  WINHTTP_AUTO_DETECT_TYPE_DNS_A = $00000002;

  function WinHttpOpen(pszAgentW: LPCWSTR; dwAccessType: DWORD;
    pszProxyW: LPCWSTR; pszProxyBypassW: LPCWSTR; dwFlags: DWORD): HINTERNET; stdcall; external 'Winhttp.dll';
  function WinHttpCloseHandle(hInternet: HINTERNET): Boolean; stdcall; external 'Winhttp.dll';
  function WinHttpGetProxyForUrl(hSession: HINTERNET; lpcwszUrl: LPCWSTR;
    pAutoProxyOptions: PWINHTTP_AUTOPROXY_OPTIONS; var pProxyInfo: TWINHTTP_PROXY_INFO): Boolean; stdcall; external 'Winhttp.dll';
  function WinHttpGetIEProxyConfigForCurrentUser(var pProxyConfig: TWINHTTP_CURRENT_USER_IE_PROXY_CONFIG): Boolean; stdcall; external 'Winhttp.dll';

  {
    URLにアクセス先のURLを渡すと、ProxyServer、ProxyPortに値が返ってくるはず
  }
  function GetProxy(const URL: String; var ProxyServer: String; var ProxyPort: Integer): Boolean;


implementation

function GetProxy(const URL: String; var ProxyServer: String;
  var ProxyPort: Integer): Boolean;
var
  ProxyConfig: TWINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
  AutoProxyConfig: TWINHTTP_AUTOPROXY_OPTIONS;
  ProxyInfo: TWINHTTP_PROXY_INFO;

  ClnPos: Integer;
  hSession: HINTERNET;

  Proxy: String;
  ProxyBypass: String;

  Strs: TStrings;
  Idx: Integer;
  URI: TIdURI;
  Pattern: String;
begin
  ZeroMemory(@ProxyConfig, SizeOf(TWINHTTP_CURRENT_USER_IE_PROXY_CONFIG));
  WinHttpGetIEProxyConfigForCurrentUser(ProxyConfig);
  Proxy := '';

  if ProxyConfig.fAutoDetect Or Assigned(ProxyConfig.lpszAutoConfigUrl) then
  begin
    // 「設定を自動的に検出する」「自動構成スクリプトを使用する」の場合
    hSession := WinHttpOpen(Nil, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
      , WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if Assigned(hSession) then
    begin
      ZeroMemory(@AutoProxyConfig, SizeOf(TWINHTTP_AUTOPROXY_OPTIONS));
      if ProxyConfig.fAutoDetect then
      begin
      //「設定を自動的に検出する」の場合
        AutoProxyConfig.dwFlags := WINHTTP_AUTOPROXY_AUTO_DETECT;
        AutoProxyConfig.dwAutoDetectFlags := WINHTTP_AUTO_DETECT_TYPE_DHCP Or
          WINHTTP_AUTO_DETECT_TYPE_DNS_A;
      end else begin
      //「自動構成スクリプトを使用する」の場合
        AutoProxyConfig.dwFlags := WINHTTP_AUTOPROXY_CONFIG_URL;
        AutoProxyConfig.lpszAutoConfigUrl := ProxyConfig.lpszAutoConfigUrl;
      end;
      WinHttpGetProxyForUrl(hSession, PChar(URL), @AutoProxyConfig, ProxyInfo);

      if Assigned(ProxyInfo.lpszProxy) then
      begin
        Proxy := ProxyInfo.lpszProxy;
        GlobalFree(Cardinal(ProxyInfo.lpszProxy));
      end;
      if Assigned(ProxyInfo.lpszProxyBypass) then
      begin
        // 例外設定がある場合
        ProxyBypass := ProxyInfo.lpszProxyBypass;
        GlobalFree(Cardinal(ProxyInfo.lpszProxyBypass));
      end;
      WinHttpCloseHandle(hSession);
    end;
  end else if Assigned(ProxyConfig.lpszProxy) then
  begin
    Proxy := ProxyConfig.lpszProxy;
    if Assigned(ProxyConfig.lpszProxyBypass) then
    begin
      // 例外設定がある場合
      ProxyBypass := ProxyConfig.lpszProxyBypass;
    end;
  end;

  if Proxy <> '' then
  begin
    ClnPos := Pos(':', Proxy);
    if ClnPos > 0 then
    begin
      ProxyServer := LeftStr(Proxy, ClnPos - 1);
      ProxyPort := StrToIntDef(RightStr(Proxy, Length(Proxy) - ClnPos), 0);
    end;
    if ProxyBypass <> '' then
    begin
      URI := TIdURI.Create(URL);
      Strs := TStringList.Create;
      Strs.Delimiter := ';';
      Strs.DelimitedText := ProxyBypass;

      // 例外設定がある場合
      // URLのHOSTが該当するか確認
      for Idx := 0 to Strs.Count - 1 do
      begin
        Pattern := Strs.Strings[Idx];
        Pattern := StringReplace(Pattern, '.', '\.', [rfReplaceAll]);
        Pattern := StringReplace(Pattern, '*', '.*', [rfReplaceAll]);

        if TRegEx.IsMatch(URI.Host, Pattern) then
        begin
          ProxyServer := '';
          ProxyPort := 0;
          break;
        end;
      end;
      FreeAndNil(URI);
    end;
  end else begin
    ProxyServer := '';
    ProxyPort := 0;
  end;

  Result := (ProxyServer <> '');

  if Assigned(ProxyConfig.lpszAutoConfigUrl) then
    GlobalFree(Cardinal(ProxyConfig.lpszAutoConfigUrl));
  if Assigned(ProxyConfig.lpszProxy) then
    GlobalFree(Cardinal(ProxyConfig.lpszProxy));
  if Assigned(ProxyConfig.lpszProxyBypass) then
    GlobalFree(Cardinal(ProxyConfig.lpszProxyBypass));
end;

end.