Вопрос

I am trying to write an Asyncronous Wininet application. I read the data in my callback function in case of INTERNET_STATUS_REQUEST_COMPLETE and I handle the ERROR_IO_PENDING errors as well. But after some data read from internet, InternetReadFileEx function gives me 10035=WSAEWOULDBLOCK (A non-blocking socket operation could not be completed immediately) error. After that error I call InternetReadFileEx again and this time it gives me 1008=ERROR_NO_TOKEN (An attempt was made to reference a token that does not exist.) error. I think my design is not correct, and I receive these error because of that.

Here is a snippet of my code:

    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;

Can anyone give me a hand to correct that? Thanks everyone helping...

Это было полезно?

Решение

GetLastError() is only meaningful if InternetReadFileEx() (or any other API, for that matter) actually fails with an error. Otherwise, you will be processing an error from an earlier API call, giving your code a false illusion that an error happened when it really may not have. You MUST pay attention to API return values, but you are currently ignoring the return value of InternetReadFileEx().

Worse than that, though, you are using InternetReadFileEx() in async mode but you are using a receiving buffer that is local to the INTERNET_STATUS_REQUEST_COMPLETE callback handler. If InternetReadFileEx() fails with an ERROR_IO_PENDING error, the read is performed in the background and INTERNET_STATUS_REQUEST_COMPLETE will be triggered when the read is complete. However, when that error occurs, you are breaking your loop (even though the read is still in progress) and that buffer will go out of scope before the read is finished. While the reading is still in progress, the receiving buffer is still on the stack and InternetReadFileEx() is still writing to it, but it may get re-used for other things at the same time because your code moved on to do other things and did not wait for the read to finish.

You need to re-think your approach. Either:

  1. remove the IRF_ASYNC flag, since that is how the rest of your callback code is expecting InternetReadFileEx() to behave.

  2. re-write the code to operate in async mode correctly. Dynamically allocate the receive buffer (or at least store it somewhere else that remains in scope during the async reading), don't call IStream::Write() unless you actually have data to write (only when InternetReadFileEx() returned TRUE right away, or you get an INTERNET_STATUS_REQUEST_COMPLETE event with a success code from an earlier InternetReadFileEx()/ERROR_IO_PENDING call), etc.

There are plenty of online examples and tutorials that show how to use InternetReadFileEx() in async mode. Search around.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top