INTERNET_ASYNC_RESULT* result = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
INTERNET_STATUS_REQUEST_COMPLETE: hInternet = 0x00cc000c, result->dwResult = 0x00000001,result->dwError = 0x00000000
INTERNET_STATUS_REQUEST_COMPLETE: hInternet = 0x00cc000c, result->dwResult = 0x00000001,result->dwError = 0x00000949
WinInet: асинхронные вызовы
Проблем 2 штуки:
1. Сообщение INTERNET_STATUS_REQUEST_COMPLETE приходит на каждый пакет данных (хотя должно приходить один раз после их получения, MSDN (c)), причём возвращаемые параметры:
Код:
т.е. result->dwResult содержит не хендлер, а неизвестно что :( (если посылать запрос с помощью InternetOpenUrl, то в result->dwResult действительно хендлер, но нужен POST-запрос, InternetOpenUrl не подходит)
2. Иногда считывается только "хвост" ответа - видимо, только последний пакет.
Отправка запроса:
Код:
internetOpenHandle = ::InternetOpen( RequestHeaderUserAgent,
INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, INTERNET_FLAG_ASYNC );
CUnicodeString requestString = buildRequest(); // Параметры запроса
hConnect = InternetConnect( internetOpenHandle, hostName,
hostPort, 0, 0, INTERNET_SERVICE_HTTP, 0, 0 );
hHttpRequest = HttpOpenRequest( hConnect, L"POST", urlPath,
0, 0, 0,
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD,
(DWORD_PTR)this );
if( hHttpRequest != 0 ) {
// callback от WinInet
assertLastError( ::InternetSetStatusCallback( hHttpRequest, InternetStatusCallback )
!= INTERNET_INVALID_STATUS_CALLBACK );
// Отправляем запрос
if( !::HttpSendRequest( hHttpRequest, 0, 0,
(void*)requestString.Ptr(), requestString.Length()*sizeof(wchar_t) ) ) {
// ошибка ERROR_IO_PENDING означает "в процессе дозвона до сервера"
// (нормальное состояние)
if( GetLastError() != ERROR_IO_PENDING ) {
int err = GetLastError();
::InternetCloseHandle( hHttpRequest );
::InternetCloseHandle( hConnect );
SetLastError( err );
assertLastError( false );
}
}
} else {
::InternetCloseHandle( hConnect );
assert( false );
}
INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, INTERNET_FLAG_ASYNC );
CUnicodeString requestString = buildRequest(); // Параметры запроса
hConnect = InternetConnect( internetOpenHandle, hostName,
hostPort, 0, 0, INTERNET_SERVICE_HTTP, 0, 0 );
hHttpRequest = HttpOpenRequest( hConnect, L"POST", urlPath,
0, 0, 0,
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD,
(DWORD_PTR)this );
if( hHttpRequest != 0 ) {
// callback от WinInet
assertLastError( ::InternetSetStatusCallback( hHttpRequest, InternetStatusCallback )
!= INTERNET_INVALID_STATUS_CALLBACK );
// Отправляем запрос
if( !::HttpSendRequest( hHttpRequest, 0, 0,
(void*)requestString.Ptr(), requestString.Length()*sizeof(wchar_t) ) ) {
// ошибка ERROR_IO_PENDING означает "в процессе дозвона до сервера"
// (нормальное состояние)
if( GetLastError() != ERROR_IO_PENDING ) {
int err = GetLastError();
::InternetCloseHandle( hHttpRequest );
::InternetCloseHandle( hConnect );
SetLastError( err );
assertLastError( false );
}
}
} else {
::InternetCloseHandle( hConnect );
assert( false );
}
Читает сообщение код (взято из примера от MS):
Код:
CString page;
DWORD bytesRead;
static const int maxAttempts = 100;
do {
// Ждём данные
DWORD available;
int attempts = 0; // количество попыток перебороть ERROR_IO_PENDING
while( !::InternetQueryDataAvailable( responseHandle, &available, 0, 0 ) ) {
if( GetLastError() != ERROR_IO_PENDING || attempts > maxAttempts) {
assertLastError( false );
}
attempts++;
Sleep( 1 );
}
// Получили данные, считываем
CString buffer;
char *bf = buffer.GetBuffer( available + 1 );
while( !::InternetReadFile( responseHandle, bf, available, &bytesRead ) ) {
if( GetLastError() != ERROR_IO_PENDING || attempts > maxAttempts ) {
assertLastError( false );
}
attempts++;
Sleep( 1 ); // min пауза
}
// Сохраняем полученные данные
buffer.ReleaseBuffer( bytesRead );
page += buffer;
} while( bytesRead > 0 );
closeWinInetHandles();
DWORD bytesRead;
static const int maxAttempts = 100;
do {
// Ждём данные
DWORD available;
int attempts = 0; // количество попыток перебороть ERROR_IO_PENDING
while( !::InternetQueryDataAvailable( responseHandle, &available, 0, 0 ) ) {
if( GetLastError() != ERROR_IO_PENDING || attempts > maxAttempts) {
assertLastError( false );
}
attempts++;
Sleep( 1 );
}
// Получили данные, считываем
CString buffer;
char *bf = buffer.GetBuffer( available + 1 );
while( !::InternetReadFile( responseHandle, bf, available, &bytesRead ) ) {
if( GetLastError() != ERROR_IO_PENDING || attempts > maxAttempts ) {
assertLastError( false );
}
attempts++;
Sleep( 1 ); // min пауза
}
// Сохраняем полученные данные
buffer.ReleaseBuffer( bytesRead );
page += buffer;
} while( bytesRead > 0 );
closeWinInetHandles();
кто-нибудь искользовал WinInet в асинхронном режиме?
Как посылать сообщения? HttpSendRequest vs HttpSendRequestEx? Асинхронность упоминается только относительно второй, но работает (похоже) и первая... или я не прав и не стоит её использовать? Тогда как искользовать HttpSendRequestEx??