IE7 以降で HttpOpenRequest() API が エラーコード 12006 で失敗する件
プログラム上からインターネットに接続して直接ファイルをダウンロードしたい場合などに、InternetOpen/InternetConnect/HttpOpenRequest API を使って下記のようなコードを使用すると思うが、このコードは IE6 以前では問題なく動作するが、IE7 以降では失敗する。
HINTERNET hSession = ::InternetOpen( _T( "UserAgent" ), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
HINTERNET hConnect = ::InternetConnect( hSession, _T( "www.example.com" ), 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
HINTERNET hRequest = ::HttpOpenRequest( hConnect, _T( "GET" ), _T( "/~user/path/file.txt" ), NULL, _T( "Referrer" ), NULL, INTERNET_FLAG_DONT_CACHE, 0 );
if ( hRequest == NULL ) {
DWORD dwError = ::GetLastError();
if ( dwError == ERROR_INTERNET_UNRECOGNIZED_SCHEME /*12006*/ ) {
ATLTRACE( _T( "スキームが認識できないエラー\n" ) );
}
}
// (snip)
::InternetCloseHandle( hRequest );
::InternetCloseHandle( hConnect );
::InternetCloseHandle( hSession );
原因は、HttpOpenRequest() でリファラに「Referrer」と記述しているがこの形式が「スキーム:識別子」の形式になっていないことによるものらしい。これをたとえば「myscheme:Referrer」に変更することで上記コードは IE7 以降でも正常に動作する。
なぜ IE7 以降で動作しなくなったかは不明だが、これにはかなりハマったので記事にして残しておくことにした。
IE8 Beta2 で User-Agent が変更できない問題
今更ネタにするものでもないけど、去年の夏に IEβニュースグループに投稿した記事と同じ内容をここにも書いておく。
VC6/VC2003 で Trident コンポーネントを使ったプログラムを作成しているときの話。
プログラム上で User-Agent を変更して接続するために UrlMkSetSessionOption( URLMON_OPTION_USERAGENT ) API を使用しているが、IE8β2 では正常に動作しない。
下記のサンプルコードは IE4 以降の環境では正常に動作するが、IE8 では UrlMkSetSessionOption は正常終了(S_OK) を返すものの効果がない。
void ChangeUserAgentTest()
{
char lpaUserAgent[ 1024 ] = "test user-agent";
DWORD dwLength = lstrlenA( lpaUserAgent );
HRESULT hr = ::UrlMkSetSessionOption( URLMON_OPTION_USERAGENT, lpaUserAgent, dwLength, 0 );
CString strMsg;
strMsg.Format( _T( "UrlMkSetSessionOption: 0x%08x" ), hr );
::MessageBox( NULL, strMsg, _T( "[debug - 1]" ), MB_OK );
if ( hr == S_OK ) {
DWORD dwSize = 1023;
char lpaString[ 1024 ] = {0};
hr = ::ObtainUserAgentString( 0, lpaString, &dwSize );
strMsg.Format( _T( "ObtainUserAgentString: 0x%08x\n%s" ), hr, CString( lpaString ) );
::MessageBox( NULL, strMsg, _T( "[debug - 2]" ), MB_OK );
}
}
最初のメッセージは成功を返す。
---------------------------
[debug - 1]
---------------------------
UrlMkSetSessionOption: 0x00000000
---------------------------
OK
---------------------------
二番目ののメッセージも成功を返す。
---------------------------
[debug - 2]
---------------------------
ObtainUserAgentString: 0x00000000
test user-agent
---------------------------
OK
---------------------------
しかしながら、ウェブサイトにアクセスすると、サーバー変数は下記の値を返す:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0)
IE8 より前では下記の値を返す:
test user-agent
ひょっとしたら IE8 以降で User-Agent を変更するための手順が変更されたのか、とも思ったがバグの可能性が高い。
この API は、urlmon.dll に含まれているため、一般プログラマからは何もできなさげ。
正式版までに解決してくれていることを願うばかり。