Нарушение прав доступа в winhttp.dll

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

winhttp.dll! HTTP_USER_REQUEST :: _ IndicateSocketAddress () + 0x221байт
winhttp.dll! HTTP_USER_REQUEST :: OnDnsNameResolved () + 0x24 байта
winhttp.dll! WEBIO_REQUEST :: _ OnInformation () + 0x1c0c байт
webio.dll!_WaIndicateHttpRequestInformation@16 () + 0x15a байт
webio.dll!_WaHttpInformationConnection@16 () + 0x7a байт
webio.dll!_WapTcpDnsQueryCompletionRoutine@12 () + 0x2f байт
webio.dll!_WapCallDnsQueryCompletion@12 () + 0x6d байт
webio.dll!_WaDnsResolutionWorker@8 () + 0x157 байт
ntdll.dll!_TppSimplepExecuteCallback@8 () + 0x7b байт
ntdll.dll!TppWorkerThread @ 4 () + 0x5a4 байта
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

Решение

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

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

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

 void CALLBACK HTTPAsyncCallback(/* etc*/)

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]