0

WinInet の InternetReadFile (C++)に問題があります。
まれに、関数が失敗し、GetLastError が前述のエラー0x8007007aを返します(ErrorLookup によると、「システム コールに渡されたデータ領域が小さすぎます」に対応します)。

これに関していくつか質問があります。

  1. まれにこれが発生するのに、他のケースでは問題なく動作するのはなぜですか (もちろん、常に同じ ~15MB の zip ファイルをダウンロードすることについて話しているのです)。
  2. これは、API 呼び出しに渡されるバッファ サイズに本当に関連していますか? この呼び出しには、1024 バイトの const バッファー サイズを使用しています。より大きなバッファ サイズを使用する必要がありますか? もしそうなら、どうすれば「正しい」バッファサイズを知ることができますか?
  3. このエラーが発生した場合、実行時に回復するにはどうすればよいですか?

コード スニペットの追加 (いくつかの初期化コードが必要なため、これはそのままでは機能しないことに注意してください):

#define HTTP_RESPONSE_BUFFER_SIZE 1024
std::vector<char> responseBuffer;
DWORD dwResponseBytesRead = 0;

do
{
    const size_t oldBufferSize = responseBuffer.size();
    responseBuffer.resize(oldBufferSize + HTTP_RESPONSE_BUFFER_SIZE);

    // Now we read again to the last place we stopped
    // writing in the previous iteration.
    dwResponseBytesRead = 0;
    BOOL bInternetReadFile = ::InternetReadFile(hOpenRequest, // hFile. Retrieved from a previous call to ::HttpOpenRequest
        (LPVOID)&responseBuffer[oldBufferSize], // lpBuffer.
        HTTP_RESPONSE_BUFFER_SIZE, // dwNumberOfBytesToRead.
        &dwResponseBytesRead); // lpdwNumberOfBytesRead.

    if(!bInternetReadFile)
    {
        // Do clean up and exit.
        DWORD dwErr = ::GetLastError(); // This, in some cases, will return: 0x7a 
        HRESULT hr = HRESULT_FROM_WIN32(dwErr); // This, in some cases, will return: 0x8007007a
        return;
    }

    // Adjust the buffer according to the actual number of bytes read.
    responseBuffer.resize(oldBufferSize + dwResponseBytesRead);
}
while(dwResponseBytesRead != 0);
4

1 に答える 1

3

これは、InternetReadFile の文書化されたエラーです。

WinINet は、一度に 1 行ずつ HTML を lpBuffer バッファーに書き込もうとします。アプリケーションのバッファが小さすぎて、生成された HTML の少なくとも 1 行に収まらない場合、より大きなバッファが必要であることを示すエラー コード ERROR_INSUFFICIENT_BUFFER がアプリケーションに返されます。

そのため、バッファ サイズを大きくしてこのエラーを処理する必要があります。必要に応じて、サイズを 2 倍にします。

問題のいくつかの矛盾があります。1 つの HTML ファイルを読んでいることは明らかではありません。15MB は過剰に思えます。もう 1 つは、このエラーがよく繰り返されることです。しかし、最も厄介なのはエラー コード値です。これは、COM コンポーネントが返す種類のエラー コードである HRESULT にラップされます。GetLastError() から返される Windows エラー コードは、0x8007007a ではなく 0x7a だけです。

エラーチェックが正しいことを確認してください。InternetReadFile() が FALSE を返した場合にのみ、GetLastError() を呼び出してください。それがチェックアウトされた場合 (常にスニペットを投稿してください)、このエラーが実際にはアップストリームで生成されていることを考慮してください。おそらく、ファイアウォールまたは不安定なマルウェア対策です。

于 2013-08-15T08:44:41.430 に答える