2013-03-31 2 views
0

C++에서 WinHTTP를 사용하여 HTTP GET을 수행하려고하는데 상태 확인 콜백 함수에서 WINHTTP_CALLBACK_STATUS_NAME_RESOLVED를 얻은 후 이름을 확인한 후 어느 시점에서 충돌이 발생합니다. winhttp.dll에서 액세스 위반이 발생합니다. 호출 스택은 다음과 같습니다!!!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]() +
[email protected]를 (바이트 0x7a) + 0x2f 바이트
webio.dll! _WapCallDnsQueryCompletion @ 12() + 0x6d bytes webio.dll! _WaDnsResolutio nWorker @ 8() + 0x157 bytes [email protected]() + 0x7b bytes
ntdll.dll! TppWorkerThread @ 4() + 0x5a4 bytes
kernel32.dll! @ BaseThreadInitThunk @ 12() + 0x12 bytes
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를 올바르게 초기화하고 사용하고 있으며 모든 것이 오류없이 정상적으로 돌아 오는 것 같습니다.

가 0xc0000005 : 액세스 위반 위치를 여러 가지로 0x00000014

위치 변경, 읽기, 그래서 '콜백이 WINHTTP_CALLBACK_STATUS_RESOLVING_NAME에 처음으로, 두 번 호출되고, 다음 WINHTTP_CALLBACK_STATUS_NAME_RESOLVED로, 그 후에 나는 액세스 위반을 얻을 아마도 스레드 문제 일 수 있다고 생각하지만 문제가 될 수 있는지 잘 모르겠습니다. 어떤 아이디어? (저는 Windows 7 64-bit에서 실행 중입니다).

+0

어떤 코드 줄입니까? 어쩌면 스택에 손상된 것이 있습니까? – OldProgrammer

답변

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

컴파일러는 원래 함수와 필요한 함수 포인터 유형이 일치하지 않는다고 불평했습니다. 해당 캐스트로 컴파일러를 종료하여 문제를 해결했습니다. 그러나 실제로 문제가 해결되지는 않았습니다. 이제 실제 문제가 발생했습니다. 손상된 스택입니다. 진단하기가 매우 어렵습니다.

콜백 함수는 기본 __cdecl 호출 규칙이 아니라 __stdcall로 선언되어야합니다. Windows 헤더는 CALLBACK 매크로를 사용합니다. 수정 :

void CALLBACK HTTPAsyncCallback(/* etc*/) 

물론 해당 캐스트를 제거하십시오.

+0

고마워, 그게 정확히 뭐가 잘못 됐어.나는 WinHttpSetStatusCallback WinHttpSetStatusCallback에 이미 캐스트가 있었지만 콜백 선언을 표시하지 않은 Microsoft 설명서에서 복사 했으므로 컴파일러 오류를 본 적이 없습니다. 그들이 왜 그 문서에 그 캐스트를 넣을지 확신하지 못합니다. 감사합니다 :) –

+0

아마도 2 년 된이 있지만 이것은 방금 내가 가진 정확한 문제입니다. 감사! –

관련 문제