WinINet アプリケーションを WinHTTP に移植する

Microsoft Windows HTTP Services (WinHTTP) は、HTTP クライアント スタックへのアクセスを必要とする中間層およびバックエンド サーバー アプリケーションを対象としています。 Microsoft Windows インターネット (WinINet) は、クライアント アプリケーション用の HTTP クライアント スタックと、ファイル転送プロトコル (FTP)、SOCKSv4、および Gopher プロトコルへのアクセスを提供します。 この概要は、WinINet アプリケーションを WinHTTP に移植することが有益かどうかを判断するのに役立ちます。 また、特定の変換要件についても説明します。

WinINet アプリケーションを移植する前に考慮すべき事項

アプリケーションで次のメリットが得られる場合は、WinINet アプリケーションを WinHTTP に移植することを検討してください。

  • サーバーセーフな HTTP クライアント スタック。
  • スタックの使用量を最小限に抑えました。
  • サーバー アプリケーションのスケーラビリティ。
  • プラットフォーム関連の API に対する依存関係が少なくなります。
  • スレッドの偽装のサポート。
  • サービスに優しい HTTP スタック。
  • スクリプト可能な WinHttpRequest オブジェクトへのアクセス。

次の 1 つ以上をサポートする必要がある場合は、WinINet アプリケーションを WinHTTP に移植することを検討しないでください。

  • HTTP スタックからの FTP または Gopher プロトコル。
  • SOCKS プロキシと通信するための SOCKSv4 プロトコルのサポート。
  • 自動ダイヤルアップ サービス。

アプリケーションを WinHTTP に移植する場合は、次のセクションで変換プロセスについて説明します。

WinINet と WinHTTP の両方のサンプル アプリケーションの場合は、WinINet の AsyncDemo サンプルと WinHTTP の AsyncDemo サンプルを比較します。

WinINet 関数と同等の WinHTTP

次の表に、HTTP クライアント スタックに関連する WinINet 関数と WinHTTP の同等関数を示します。

一覧にない WinINet 関数がアプリケーションに必要な場合は、アプリケーションを WinHTTP に移植しないでください。

WinINet 関数 WinHTTP と同等 注目すべき変更
HttpAddRequestHeaders WinHttpAddRequestHeaders [なし] :
HttpEndRequest WinHttpReceiveResponse コンテキスト値は 、WinHttpSendRequest または WinHttpSetOption で設定されます。 要求オプションは WinHttpOpenRequest で設定されます。 WinHttpReceiveResponse は、要求の送信後に呼び出す必要があります。
HttpOpenRequest WinHttpOpenRequest コンテキスト値は 、WinHttpSendRequest または WinHttpSetOption で設定されます。
HttpQueryInfo WinHttpQueryHeaders [なし] :
HttpSendRequest WinHttpSendRequest コンテキスト値は WinHttpSendRequest で設定できます。
HttpSendRequestEx WinHttpSendRequest バッファーを指定できません。
InternetCanonicalizeUrl 同等の機能がありません WinHttpOpenRequest に URL が標準形式で配置されるようになりました。
InternetCheckConnection 同等の機能がありません WinHTTP では実装されていません。
InternetCloseHandle WinHttpCloseHandle WinHTTP で親ハンドルを閉じると、子ハンドルは再帰的に閉じません。
InternetCombineUrl 同等の機能がありません URL は 、WinHttpCreateUrl 関数を使用して組み立てることができます。
InternetConfirmZoneCrossing 同等の機能がありません WinHTTP では実装されていません。
InternetConnect WinHttpConnect コンテキスト値は 、WinHttpSendRequest または WinHttpSetOption で設定されます。 要求オプションは WinHttpOpenRequest で設定されます。 ユーザー資格情報は WinHttpSetCredentials で設定されます。
InternetCrackUrl WinHttpCrackUrl ICU_ESCAPE フラグとは逆の動作: InternetCrackUrl の場合、このフラグはエスケープ シーケンス (%xx) を文字に変換しますが、 WinHttpCrackUrl では、HTTP 要求からエスケープする必要がある文字をエスケープ シーケンスに変換します。
InternetCreateUrl WinHttpCreateUrl [なし] :
InternetErrorDlg 同等の機能がありません WinHTTP はサーバー側アプリケーションを対象としているため、ユーザー インターフェイスは実装されません。
InternetGetCookie 同等の機能がありません WinHTTP はセッション間でデータを保持せず、WinINet Cookie にアクセスできません。
InternetOpen WinHttpOpen [なし] :
InternetOpenUrl WinHttpConnectWinHttpOpenRequestWinHttpSendRequestWinHttpReceiveResponse この機能は、一覧表示されている WinHTTP 関数で使用できます。
InternetQueryDataAvailable WinHttpQueryDataAvailable 予約済みパラメーターはありません。
InternetQueryOption WinHttpQueryOption WinHTTP には、WinINet とは異なるオプション セットが用意されています。 WinHTTP で提供されるオプションの詳細については、 オプション フラグを参照してください。
InternetReadFile WinHttpReadData [なし] :
InternetReadFileEx WinHttpReadData 構造体ではなく、バッファーはポインターでアドレス指定されたメモリの領域です。
InternetSetOption WinHttpSetOption [なし] :
InternetSetStatusCallback WinHttpSetStatusCallback 詳細については、このトピックの「非同期要求の異なる処理」を参照してください。
InternetTimeFromSystemTime WinHttpTimeFromSystemTime [なし] :
InternetTimeToSystemTime WinHttpTimeToSystemTime [なし] :
InternetWriteFile WinHttpWriteData [なし] :

 

非同期要求の異なる処理

WinINet と WinHTTP では、一部の関数で非同期要求を同期的または非同期的に完了できることに注意してください。 アプリケーションは、どちらの状況にも対応する必要があります。 WinINet と WinHTTP がこれらの非同期関数を処理する方法には大きな違いがあります。

Wininet

  • 同期完了: 可能性のある非同期 WinINet 関数呼び出しが同期的に完了した場合、関数の OUT パラメーターは操作の結果を返します。 エラーが発生した場合は、WinINet 関数呼び出しの後に GetLastError を呼び出してエラー コードを取得します。

  • 非同期完了: 非同期関数呼び出しが非同期的に完了した場合、操作の結果とエラーにコールバック関数からアクセスできます。 コールバック関数は、最初の関数呼び出しを行ったスレッドではなく、ワーカー スレッドで実行されます。

つまり、アプリケーションは、関数呼び出しの直後とコールバック関数の両方の 2 つの場所でこのような操作の結果を処理するロジックを複製する必要があります。

WinHTTP では、操作が同期的に完了したか非同期的に完了したかに関係なく完了通知を受け取るコールバック関数でのみ操作ロジックを実装できるようにすることで、このモデルが簡略化されます。 非同期操作が有効になっている場合、WinHTTP 関数の OUT パラメーターは意味のあるデータを返せず、 NULL に設定する必要があります。

アプリケーションの観点から見た WinHTTP の非同期完了と同期完了の唯一の大きな違いは、コールバック関数が実行される場所です。

WinHTTP

  • 同期完了: 操作が同期的に完了すると、元の関数呼び出しと同じスレッドで実行されるコールバック関数で結果が返されます。

  • 非同期完了: 操作が非同期に完了すると、ワーカー スレッドで実行されるコールバック関数で結果が返されます。

ほとんどのエラーはコールバック関数内で完全に処理することもできますが、GetLastError を呼び出して取得したERROR_INVALID_PARAMETERやその他の同様のエラーが原因で、関数が FALSE を返すように WinHTTP アプリケーションを準備する必要があります。

複数の非同期操作を同時に実行できる WinINet とは異なり、WinHTTP は要求ハンドルごとに 1 つの保留中の非同期操作のポリシーを適用します。 1 つの操作が保留中で、別の WinHTTP 関数が呼び出されると、2 つ目の関数は失敗し、 GetLastError はERROR_INVALID_OPERATIONを返します。

WinHTTP では、操作が同期的に完了したか非同期的に完了したかに関係なく完了通知を受け取るコールバック関数でのみ操作ロジックを実装できるようにすることで、このモデルが簡略化されます。 非同期操作が有効になっている場合、WinHTTP 関数の OUT パラメーターは意味のあるデータを返せず、 NULL に設定する必要があります。

WinHTTP コールバック通知の違い

状態コールバック関数は、通知フラグを介して操作の状態に関する更新を受け取ります。 WinHTTP では、WinHttpSetStatusCallback 関数の dwNotificationFlags パラメーターを使用して通知が選択されます。 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS フラグを使用して、すべての状態更新について通知を受け取ります。

特定の操作が完了したことを示す通知は、完了通知と呼ばれるか、完了と呼ばれます。 WinINet では、コールバック関数が完了を受け取るたびに、 lpvStatusInformation パラメーターに INTERNET_ASYNC_RESULT 構造体が含まれます。 WinHTTP では、この構造体はすべての完了で使用できるわけではありません。 WINHTTP_STATUS_CALLBACK の参照ページを確認することが重要です。このページには、通知に関する情報と、それぞれに必要なデータの種類が含まれています。

WinHTTP では、1 つの完了 (WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) は、操作が失敗したことを示します。 その他すべての完了は、正常な操作を示します。

WinINet と WinHTTP はどちらも、ユーザー定義のコンテキスト値を使用して、メイン スレッドからステータス コールバック関数に情報を渡します。これはワーカー スレッドで実行できます。 WinINet では、状態コールバック関数で使用されるコンテキスト値は、複数の関数のいずれかを呼び出すことによって設定されます。 WinHTTP では、コンテキスト値は WinHttpSendRequest または WinHttpSetOption でのみ設定されます。 このため、WinHTTP では、コンテキスト値が設定される前に通知が発生する可能性があります。 コンテキスト値が設定される前にコールバック関数が通知を受信する場合は、コールバック関数の dwContext パラメーターで NULL を受け取るアプリケーションを準備する必要があります。

認証の違い

WinINet では、ユーザー資格情報は、次のコード例に示すようなコードを使用して InternetSetOption 関数を呼び出すことによって設定されます。

// Use the WinINet InternetSetOption function to set the 
// user credentials to the user name contained in strUsername 
// and the password to the contents of strPassword.
       
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_USERNAME, 
                   strUsername, strlen(strUsername) + 1 );

InternetSetOption( hRequest, INTERNET_OPTION_PROXY_PASSWORD, 
                   strPassword, strlen(strPassword) + 1 );

互換性のために、 WinHttpSetOption 関数を使用して WinHTTP でも同様にユーザー資格情報を設定できますが、セキュリティの脆弱性が発生する可能性があるため、これはお勧めしません。

代わりに、アプリケーションが WinHTTP で 401 状態コードを受け取ったときに、まず WinHttpQueryAuthSchemes を使用して認証スキームを識別し、次に WinHttpSetCredentials を使用して資格情報を設定することをお勧めします。 これを行う方法を次のコード例に示します。

DWORD dwSupportedSchemes;
DWORD dwPrefered;
DWORD dwTarget;

// Obtain the supported and first schemes.
WinHttpQueryAuthSchemes( hRequest, &dwSupportedSchemes, &dwPrefered, &dwTarget );

// Set the credentials before resending the request.
WinHttpSetCredentials( hRequest, dwTarget, dwPrefered, strUsername, strPassword, NULL );

WinHTTP の InternetErrorDlg に相当するものがないため、ユーザー インターフェイスを介して資格情報を取得するアプリケーションは、独自のインターフェイスを提供する必要があります。

WinINet とは異なり、WinHTTP はパスワードをキャッシュしません。 要求ごとに有効なユーザー資格情報を指定する必要があります。

WinHTTP では、WinINet でサポートされる分散パスワード認証 (DPA) スキームはサポートされていません。 ただし、WinHTTP は Microsoft Passport 1.4 をサポートしています。 WinHTTP で Passport 認証を使用する方法の詳細については、「 WinHTTP での Passport 認証」を参照してください。

WinHTTP は、自動ログオン ポリシーを決定するために Internet Explorer の設定に依存しません。 代わりに、自動ログオン ポリシーは WinHttpSetOption で設定されます。 自動ログオン ポリシーなど、WinHTTP での認証の詳細については、「 WinHTTP での認証」を参照してください。

セキュリティで保護された HTTP トランザクションの違い

WinINet では、HttpOpenRequest または InternetConnect を使用してセキュリティで保護されたセッションを開始しますが、WinHTTP では、WINHTTP_FLAG_SECURE フラグを使用して WinHttpOpenRequest を呼び出す必要があります。

セキュリティで保護された HTTP トランザクションでは、サーバー証明書を使用して、クライアントに対するサーバーの認証を行うことができます。 WinINet では、サーバー証明書にエラーが含まれている場合、 HttpSendRequest は失敗し、証明書エラーの詳細を提供します。

WinHttp では、サーバー証明書エラーはバージョンに従って次のように処理されます。

  • WinHttp 5.1 以降では、サーバー証明書が失敗した場合やエラーが含まれている場合、 WinHttpSendRequest の呼び出しによってコールバック関数の WINHTTP_CALLBACK_STATUS_SECURE_FAILURE が報告されます。 WinHttpSendRequest によって生成されたエラーが無視された場合、後続の WinHttpReceiveResponse の呼び出しは、ERROR_WINHTTP_OPERATION_CANCELLED エラーで失敗します。
  • WinHTTP 5.0 では、サーバー証明書のエラーでは、既定では要求が失敗しません。 代わりに、 WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 通知を使用してコールバック関数でエラーが報告されます。

以前のプラットフォームでは、WinINet はプライベート コミュニケーション テクノロジ (PCT) や Fortezza プロトコルをサポートしましたが、Windows XP ではサポートされていません。

WinHTTP は、どのプラットフォームでも PCT および Fortezza プロトコルをサポートせず、代わりに Secure Sockets Layer (SSL) 2.0、SSL 3.0、またはトランスポート層セキュリティ (TLS) 1.0 に依存します。