2013-03-31 2 views
0

Я пытаюсь выполнить HTTP GET с использованием WinHTTP в C++, но он сбой в какой-то момент после разрешения имени (после получения WINHTTP_CALLBACK_STATUS_NAME_RESOLVED в функции обратного вызова статуса). Я получаю нарушение доступа в winhttp.dll. CallStack это:!!Нарушение прав доступа в winhttp.dll

Winhttp.dll HTTP_USER_REQUEST :: _ IndicateSocketAddress() + 0x221ed байт
Winhttp.dll HTTP_USER_REQUEST :: OnDnsNameResolved() + 0x24 байт
Winhttp.dll WEBIO_REQUEST :: _ OnInformation() + 0x1c0c байты [email protected]() + 0x15a байты [email protected]() + 0x7A байты
[email protected]() + 0x2f байты
webio.dll! _WapCallDnsQueryCompletion @ 12() + 0x6d байты webio.dll! _WaDnsResolutio nWorker @ 8() + 0x157 bytes [email protected]() + 0x7b байты
ntdll.dll! TppWorkerThread @ 4() + 0x5a4 bytes
kernel32.dll! @ BaseThreadInitThunk @ 12() + 0x12 байтов
ntdll.dll! !
__RtlUserThreadStart @ 8() + 0x27 байт
ntdll.dll __ RtlUserThreadStart @ 8() + 0x1B байт

Соответствующий код:

enum OnlineState 
{ 
    OnlineState_Idle, 
    OnlineState_Registering 
}; 

static OnlineState g_OnlineState = OnlineState_Idle; 
HINTERNET g_Request = 0; 
HINTERNET g_Connection = 0; 
unsigned char g_HTTPBuffer[1024]; 

void HTTPRequestComplete() 
{ 
    if(g_Request != 0) 
    { 
     WinHttpCloseHandle(g_Request); 
     g_Request = 0; 
    } 
    if(g_Connection != 0) 
    { 
     WinHttpCloseHandle(g_Connection); 
     g_Connection = 0; 
    } 
    g_OnlineState = OnlineState_Idle; 
} 

void HTTPAsyncCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) 
{ 
    switch(dwInternetStatus) 
    { 
     case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: 
     { 
      // Get the response 
      if (!WinHttpReceiveResponse(g_Request, 0)) 
      { 
      // Failed to get the response 
       HTTPRequestComplete(); 
       return; 
      } 
     } 
     break; 

     case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: 
     { 
      DWORD statusCode = 0; 
      DWORD statusCodeSize = sizeof(DWORD); 

      if (!WinHttpQueryHeaders(g_Request, 
          WINHTTP_QUERY_STATUS_CODE |  WINHTTP_QUERY_FLAG_NUMBER, 
          WINHTTP_HEADER_NAME_BY_INDEX, 
          &statusCode, 
          &statusCodeSize, 
          WINHTTP_NO_HEADER_INDEX)) 
      { 
       // Failed to query headers 
       HTTPRequestComplete(); 
       return; 
      } 

      if (HTTP_STATUS_OK != statusCode) 
      { 
       // Error status 
       HTTPRequestComplete(); 
       return; 
      } 

      if (!WinHttpReadData(g_Request, 
          g_HTTPBuffer, 
          sizeof(g_HTTPBuffer), 
          0)) 
      { 
       // Error reading data 
       HTTPRequestComplete(); 
       return; 
      } 
     } 
     break; 

     case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: 
     { 
      if (dwStatusInformationLength > 0) 
      { 
       // Store the data 

       // Read the next data 
       if (!WinHttpReadData(g_Request, 
            g_HTTPBuffer, 
             sizeof(g_HTTPBuffer), 
            0)) 
       { 
        // Error 
       HTTPRequestComplete(); 
       return; 
      } 
     } 
     else 
     { 
      // Request completed OK 
      HTTPRequestComplete(); 
     } 
    } 
    break; 

    default: 
     break; 
    } 
} 

// Online functionality 
void Online_UpdateServer() 
{ 
    switch(g_OnlineState) 
    { 
    case OnlineState_Idle: 
     { 
      // Get our local ip address by connecting a local socket to a web address and reading the socket name 

      // Look up the address to connect to 
      addrinfo hints; 
      addrinfo* res = 0; 
      memset(&hints, 0, sizeof hints); 
      hints.ai_family = AF_UNSPEC; 
      hints.ai_socktype = SOCK_DGRAM; 
      getaddrinfo("www.google.com", "80", &hints, &res); 

      // Create the socket 
      int tempSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
      unsigned int localAddress = 0; 
      if (tempSocket >= 0) 
      { 
       // Connect the socket 
       connect(tempSocket, res->ai_addr, res->ai_addrlen); 

       // Get the socket name (our local ip address) 
       sockaddr_in localName; 
       memset(&localName, 0, sizeof(localName)); 
       int bufferSize = sizeof(localName); 
       if(getsockname(tempSocket, (sockaddr*)&localName, &bufferSize) == 0) 
       { 
        // Get the IP address 
        localAddress = localName.sin_addr.S_un.S_addr; 
       } 

       closesocket(tempSocket); 
      } 

      // Connect 
      g_Connection = WinHttpConnect(g_Internet, L"www.google.com", INTERNET_DEFAULT_PORT, 0); 

      // Open the request 
      std::wstringstream urlString; 
      urlString << L"/"; 
      std::wstring tempString = urlString.str(); 
      const wchar_t* wurlString = tempString.c_str(); 
      g_Request = WinHttpOpenRequest(g_Connection, 0, wurlString, 0, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); 

      // Install the status callback function. 
      if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(g_Request, (WINHTTP_STATUS_CALLBACK)HTTPAsyncCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL)) 
      { 
       OutputDebugString(L"Error"); 
      } 

      // Send the request 
      if(!WinHttpSendRequest(g_Request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) 
      { 
       OutputDebugString(L"Error"); 
      } 

      // Log that we're registering 
      g_OnlineState = OnlineState_Registering; 
     } 
     break; 

    case OnlineState_Registering: 
     { 
      // Don't do anything, as we're currently registering 
     } 
     break; 

    default: 
     break; 
    } 
} 

g_Internet инициализируется так:

// Initialise HTTP 
g_Internet = WinHttpOpen(L"Boomba", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); 

Насколько я могу судить, я инициализирую и использую WinHTTP правильно, и все, кажется, возвращается ОК без ошибок. Обратного вызова вызывается дважды, первый раз с WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, затем с WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, то после того, что я получаю нарушение прав доступа:

0xC0000005: Нарушение прав доступа чтения месте, 0x00000014

меняет свое местоположение, к различным вещам, так что я Я думаю, что это может быть проблема с потоками, но я не уверен, что может быть проблемой. Есть идеи? (Я работаю на 64-разрядной версии Windows 7).

+0

Какая строка кода? Может быть, что-то повреждено в стеке? – OldProgrammer

ответ

2
if (WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(
     g_Request, 
     (WINHTTP_STATUS_CALLBACK)HTTPAsyncCallback,  // <=== evil 
     WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 
     NULL)) 

Компилятор первоначально жаловался на несоответствие между вашей функцией и типом указателя функции, который требуется. Вы устранили проблему, закрыв компилятор с помощью этого ролика. Но это не решило проблему. Теперь вы купили себе проблему real, поврежденный стек. Очень трудно диагностировать.

Функция обратного вызова должна быть объявлена ​​как __stdcall, а не стандартное соглашение о вызове __cdecl. Заголовки Windows используют для этого макрос CALLBACK. Исправление:

void CALLBACK HTTPAsyncCallback(/* etc*/) 

И, конечно, удалите этот литой.

+0

Спасибо, это было именно то, что было не так.Я скопировал вызов в WinHttpSetStatusCallback из документации Microsoft, в которой уже был выбран листинг, но не показывал декларации обратного вызова, поэтому я никогда не видел ошибку компилятора. Не знаете, почему у них будет такой бросок в документации. Спасибо :) –

+0

это может быть 2 года, но это точная проблема, которую я только что имел. благодаря! –

Смежные вопросы