0

我正在尝试编写一个异步 Wininet 应用程序。在 INTERNET_STATUS_REQUEST_COMPLETE 的情况下,我在回调函数中读取数据,并且我也处理 ERROR_IO_PENDING 错误。但是在从 Internet 读取一些数据后,InternetReadFileEx 函数给了我 10035=WSAEWOULDBLOCK(无法立即完成非阻塞套接字操作)错误。在该错误之后,我再次调用 InternetReadFileEx,这一次它给了我 1008=ERROR_NO_TOKEN(尝试引用不存在的令牌。)错误。我认为我的设计不正确,因此我收到这些错误。

这是我的代码片段:

    case INTERNET_STATUS_REQUEST_COMPLETE:
    {
        BOOL bAllDone= FALSE;
        DWORD lastError;

        do
        {
            //Create INTERNET_BUFFERS
            char m_pbReadBuffer[4096];
            INTERNET_BUFFERS BuffersIn;
            ZeroMemory(&BuffersIn, sizeof(INTERNET_BUFFERS));
            BuffersIn.dwStructSize = sizeof(INTERNET_BUFFERS);
            BuffersIn.lpvBuffer = m_pbReadBuffer;
            BuffersIn.dwBufferLength = 4096;

            InternetReadFileEx(ReqContext->File, &BuffersIn, IRF_ASYNC, 1);

            //HERE I GOT THOSE 10035 and 1008 ERRORS
            lastError = GetLastError();

            if(lastError == 997) // handling ERROR_IO_PENDING 
                break;//break the while loop

            //append it to my ISTREAM
            (ReqContext->savedStream)->Write(BuffersIn.lpvBuffer, BuffersIn.dwBufferLength, NULL);

            if (BuffersIn.dwBufferLength == 0) 
                bAllDone = TRUE;

    }while(bAllDone == FALSE);

                //delete[] m_pbReadBuffer; 

    if(bAllDone == TRUE && lastError== 0)
    {
        //these are for passing the ISTREAM to the function which calls "InternetOpenUrl"
        LARGE_INTEGER loc;
        loc.HighPart = 0;
        loc.LowPart = 0;
        ReqContext->savedStream->Seek(loc, STREAM_SEEK_SET, NULL);
        ReqContext->savedCallback->OnUrlDownloaded(S_OK, ReqContext->savedStream); //Tell silverlight ISTREAM is ready
        ReqContext->savedStream->Release();
        ReqContext->savedCallback->Release();

        InternetCloseHandle(ReqContext->File);
        InternetSetStatusCallback(ReqContext->Connection, NULL);
        InternetCloseHandle(ReqContext->Connection);
        delete[] ReqContext;
        }
    }
    break;

谁能帮我纠正一下?谢谢大家帮忙...

4

1 回答 1

2

GetLastError()InternetReadFileEx()只有在(或任何其他 API,就此而言)实际上失败并出现错误时才有意义。否则,您将处理来自早期 API 调用的错误,从而使您的代码产生错误的错觉,即错误发生了,而实际上可能没有。您必须注意 API 返回值,但您目前忽略InternetReadFileEx().

更糟糕的是,您InternetReadFileEx()在异步模式下使用,但您使用的是INTERNET_STATUS_REQUEST_COMPLETE回调处理程序本地的接收缓冲区。如果因错误而InternetReadFileEx()失败ERROR_IO_PENDING,则在后台执行读取,并INTERNET_STATUS_REQUEST_COMPLETE在读取完成时触发。但是,当该错误发生时,您将中断循环(即使读取仍在进行中),并且该缓冲区将在读取完成之前超出范围。虽然读取仍在进行中,但接收缓冲区仍在堆栈上并且InternetReadFileEx()仍在写入它,但它可能会同时被重新用于其他事情,因为您的代码继续执行其他事情并且没有等待阅读完成。

你需要重新考虑你的方法。任何一个:

  1. 删除该IRF_ASYNC标志,因为这就是您的回调代码的其余部分所期望InternetReadFileEx()的行为方式。

  2. 重新编写代码以正确在异步模式下运行。动态分配接收缓冲区(或至少将其存储在异步读取期间仍在范围内的其他位置),IStream::Write()除非您确实有数据要写入(仅当InternetReadFileEx()立即返回 TRUE 或您获得INTERNET_STATUS_REQUEST_COMPLETE成功的事件时,否则不要调用)来自较早InternetReadFileEx()/ERROR_IO_PENDING调用的代码)等。

有大量在线示例和教程展示了如何InternetReadFileEx()在异步模式下使用。四处搜寻。

于 2013-06-20T17:04:16.473 回答