Общие функции (Windows Internet)
Различные протоколы Интернета (например, ftp и http) используют несколько одинаковых функций WinINet для обработки информации в Интернете. Эти общие функции выполняют свои задачи согласованно, независимо от конкретного протокола, к которому они применяются. Приложения могут использовать эти функции для создания функций общего назначения, которые обрабатывают задачи по разным протоколам (например, чтение файлов для FTP и HTTP).
Распространенные функции выполняют следующие задачи:
- Скачивание ресурсов из Интернета (InternetReadFile, InternetSetFilePointer, InternetFindNextFile и InternetQueryDataAvailable).
- Настройка асинхронных операций (InternetSetStatusCallback).
- Просмотр и изменение параметров (InternetSetOption и InternetQueryOption).
- Закрытие всех типов дескрипторов HINTERNET (InternetCloseHandle).
- Размещение и удаление блокировок ресурсов (InternetLockRequestFile и InternetUnlockRequestFile).
Использование общих функций
В следующей таблице перечислены распространенные функции, включенные в функции WinINet. Общие функции можно использовать в разных типах дескрипторов HINTERNET или во время различных типов сеансов.
Функция | Описание |
---|---|
InternetFindNextFile | Продолжает перечисление или поиск файлов. Требуется дескриптор, созданный функцией FtpFindFirstFile или InternetOpenUrl . |
InternetLockRequestFile | Позволяет пользователю заблокировать используемый файл. Для этой функции требуется дескриптор, возвращаемый функцией FtpOpenFile, HttpOpenRequest или InternetOpenUrl . |
InternetQueryDataAvailable | Извлекает объем доступных данных. Требуется дескриптор, созданный функцией FtpOpenFile или HttpOpenRequest . |
InternetQueryOption | Извлекает параметр internet. |
InternetReadFile | Считывает данные URL-адреса. Требуется дескриптор, созданный функцией InternetOpenUrl, FtpOpenFile или HttpOpenRequest . |
InternetSetFilePointer | Задает позицию для следующего чтения в файле. Требует дескриптора, созданного InternetOpenUrl (только для URL-адреса HTTP), или дескриптора, созданного HttpOpenRequest с помощью HTTP-команды GET. |
InternetSetOption | Задает параметр Интернета. |
InternetSetStatusCallback | Задает функцию обратного вызова, которая получает сведения о состоянии. Назначает функцию обратного вызова назначенному дескриптору HINTERNET и всем дескрипторам, производным от него. |
InternetUnlockRequestFile | Разблокирует файл, заблокированный с помощью функции InternetLockRequestFile . |
Чтение файлов, поиск следующего файла, управление параметрами и настройка асинхронных операций являются общими для функций, поддерживающих различные протоколы и типы дескрипторов HINTERNET .
Чтение файлов
Функция InternetReadFile используется для скачивания ресурсов из дескриптора HINTERNET , возвращаемого функцией InternetOpenUrl, FtpOpenFile или HttpOpenRequest .
InternetReadFile принимает переменную пустого указателя, содержащую адрес буфера, и указатель на переменную, содержащую длину буфера. Функция возвращает данные в буфере и объем данных, загруженных в буфер.
Функции WinINet предоставляют два метода загрузки всего ресурса:
- Функция InternetQueryDataAvailable .
- Возвращаемые значения Объекта InternetReadFile.
InternetQueryDataAvailable принимает дескриптор HINTERNET , созданный InternetOpenUrl, FtpOpenFile или HttpOpenRequest (после вызова HttpSendRequest для дескриптора), и возвращает количество доступных байтов. Приложение должно выделить буфер, равный количеству доступных байтов, плюс 1 для завершающего символа NULL , и использовать этот буфер с InternetReadFile. Этот метод не всегда работает, так как InternetQueryDataAvailable проверяет размер файла, указанного в заголовке, а не фактический файл. Сведения в файле заголовка могут быть устаревшими, или файл заголовка может отсутствовать, так как в настоящее время это не требуется по всем стандартам.
В следующем примере считывается содержимое ресурса, доступного дескриптору hResource и отображаемого в поле ввода, обозначенном intCtrlID.
int WINAPI Dumper(HWND hX, int intCtrlID, HINTERNET hResource)
{
LPTSTR lpszData; // buffer for the data
DWORD dwSize; // size of the data available
DWORD dwDownloaded; // size of the downloaded data
DWORD dwSizeSum=0; // size of the data in the text box
LPTSTR lpszHolding; // buffer to merge the text box
// data and buffer
// Set the cursor to an hourglass.
SetCursor(LoadCursor(NULL,IDC_WAIT));
// This loop handles reading the data.
do
{
// The call to InternetQueryDataAvailable determines the
// amount of data available to download.
if (!InternetQueryDataAvailable(hResource,&dwSize,0,0))
{
ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
SetCursor(LoadCursor(NULL,IDC_ARROW));
return FALSE;
}
else
{
// Allocate a buffer of the size returned by
// InternetQueryDataAvailable.
lpszData = new TCHAR[dwSize+1];
// Read the data from the HINTERNET handle.
if(!InternetReadFile(hResource,(LPVOID)lpszData,
dwSize,&dwDownloaded))
{
ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
delete[] lpszData;
break;
}
else
{
// Add a null terminator to the end of the
// data buffer.
lpszData[dwDownloaded]='\0';
// Allocate the holding buffer.
lpszHolding = new TCHAR[dwSizeSum + dwDownloaded + 1];
// Check if there has been any data written to
// the text box.
if (dwSizeSum != 0)
{
// Retrieve the data stored in the text
// box, if any.
GetDlgItemText(hX,intCtrlID,
(LPTSTR)lpszHolding,
dwSizeSum);
// Add a null terminator at the end of
// the text box data.
lpszHolding[dwSizeSum]='\0';
}
else
{
// Make the holding buffer an empty string.
lpszHolding[0]='\0';
}
size_t cchDest = dwSizeSum + dwDownloaded +
dwDownloaded + 1;
LPTSTR pszDestEnd;
size_t cchRemaining;
// Add the new data to the holding buffer.
HRESULT hr = StringCchCatEx(lpszHolding, cchDest,
lpszData, &pszDestEnd,
&cchRemaining,
STRSAFE_NO_TRUNCATION);
if(SUCCEEDED(hr))
{
// Write the holding buffer to the text box.
SetDlgItemText(hX,intCtrlID,(LPTSTR)lpszHolding);
// Delete the two buffers.
delete[] lpszHolding;
delete[] lpszData;
// Add the size of the downloaded data to
// the text box data size.
dwSizeSum = dwSizeSum + dwDownloaded + 1;
// Check the size of the remaining data.
// If it is zero, break.
if (dwDownloaded == 0)
{
break;
}
else
{
// Insert error handling code here.
}
}
}
}
}
while(TRUE);
// Close the HINTERNET handle.
InternetCloseHandle(hResource);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return TRUE;
}
InternetReadFile возвращает ноль байтов, прочитанных и успешно завершается после считывания всех доступных данных. Это позволяет приложению использовать InternetReadFile в цикле для загрузки данных и выхода, когда он возвращает ноль байтов, прочитанных и успешно завершается.
В следующем примере ресурс считывается из Интернета и отображается в поле ввода, обозначенном intCtrlID. Дескриптор HINTERNET hInternet был возвращен InternetOpenUrl, FtpOpenFile или HttpOpenRequest (после отправки HttpSendRequest).
int WINAPI Dump(HWND hX, int intCtrlID, HINTERNET hResource)
{
DWORD dwSize = 0;
LPTSTR lpszData;
LPTSTR lpszOutPut;
LPTSTR lpszHolding = TEXT("");
int nCounter = 1;
int nBufferSize = 0;
DWORD BigSize = 8000;
// Set the cursor to an hourglass.
SetCursor(LoadCursor(NULL,IDC_WAIT));
// Begin the loop that reads the data.
do
{
// Allocate the buffer.
lpszData =new TCHAR[BigSize+1];
// Read the data.
if(!InternetReadFile(hResource,
(LPVOID)lpszData,
BigSize,&dwSize))
{
ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
delete []lpszData;
break;
}
else
{
// Add a null terminator to the end of the buffer.
lpszData[dwSize]='\0';
// Check if all of the data has been read. This should
// never get called on the first time through the loop.
if (dwSize == 0)
{
// Write the final data to the text box.
SetDlgItemText(hX,intCtrlID,lpszHolding);
// Delete the existing buffers.
delete [] lpszData;
delete [] lpszHolding;
break;
}
// Determine the buffer size to hold the new data and
// the data already written to the text box (if any).
nBufferSize = (nCounter*BigSize)+1;
// Increment the number of buffers read.
nCounter++;
// Allocate the output buffer.
lpszOutPut = new TCHAR[nBufferSize];
// Make sure the buffer is not the initial buffer.
if(nBufferSize != int(BigSize+1))
{
// Copy the data in the holding buffer.
StringCchCopy(lpszOutPut,nBufferSize,lpszHolding);
// Add error handling code here.
// Concatenate the new buffer with the
// output buffer.
StringCchCat(lpszOutPut, nBufferSize, lpszData);
// Add error handling code here.
// Delete the holding buffer.
delete [] lpszHolding;
}
else
{
// Copy the data buffer.
StringCchCopy(lpszOutPut, nBufferSize, lpszData);
// Add error handling code here.
}
// Allocate a holding buffer.
lpszHolding = new TCHAR[nBufferSize];
// Copy the output buffer into the holding buffer.
memcpy(lpszHolding,lpszOutPut,nBufferSize);
// Delete the other buffers.
delete [] lpszData;
delete [] lpszOutPut;
}
}
while (TRUE);
// Close the HINTERNET handle.
InternetCloseHandle(hResource);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return TRUE;
}
Поиск следующего файла
Функция InternetFindNextFile используется для поиска следующего файла в поиске с помощью параметров поиска и дескриптора HINTERNET из FtpFindFirstFile или InternetOpenUrl.
Чтобы завершить поиск файла, продолжайте вызывать InternetFindNextFile с помощью дескриптора HINTERNET , возвращаемого ftpFindFirstFile, или InternetOpenUrl , пока функция не завершится сбоем с расширенным сообщением об ошибке ERROR_NO_MORE_FILES. Чтобы получить расширенные сведения об ошибке, вызовите функцию GetLastError .
В следующем примере содержимое каталога FTP отображается в списке, указанном lstDirectory. Дескриптор HINTERNET hConnect — это дескриптор, возвращаемый функцией InternetConnect после установки сеанса FTP.
bool WINAPI DisplayDir( HWND hX,
int lstDirectory,
HINTERNET hConnect,
DWORD dwFlag )
{
WIN32_FIND_DATA pDirInfo;
HINTERNET hDir;
TCHAR DirList[MAX_PATH];
// Set the cursor to an hourglass.
SetCursor(LoadCursor(NULL,IDC_WAIT));
// Reset the list box.
SendDlgItemMessage(hX, lstDirectory,LB_RESETCONTENT,0,0);
// Find the first file.
hDir = FtpFindFirstFile (hConnect, TEXT ("*.*"),
&pDirInfo, dwFlag, 0);
if (!hDir)
{
// Check if the error was because there were no files.
if (GetLastError() == ERROR_NO_MORE_FILES)
{
// Alert user.
MessageBox(hX, TEXT("There are no files here!!!"),
TEXT("Display Dir"), MB_OK);
// Close the HINTERNET handle.
InternetCloseHandle(hDir);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return TRUE;
}
else
{
// Call error handler.
ErrorOut (hX, GetLastError (), TEXT("FindFirst error: "));
// Close the HINTERNET handle.
InternetCloseHandle(hDir);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return FALSE;
}
}
else
{
// Write the file name to a string.
StringCchPrintf(DirList, MAX_PATH, pDirInfo.cFileName);
// Check the type of file.
if (pDirInfo.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
// Add <DIR> to indicate that this is
// a directory to the user.
StringCchCat(DirList, MAX_PATH, TEXT(" <DIR> "));
// Add error handling code here.
}
// Add the file name (or directory) to the list box.
SendDlgItemMessage(hX, lstDirectory, LB_ADDSTRING,
0, (LPARAM)DirList);
}
do
{
// Find the next file.
if (!InternetFindNextFile (hDir, &pDirInfo))
{
// Check if there are no more files left.
if ( GetLastError() == ERROR_NO_MORE_FILES )
{
// Close the HINTERNET handle.
InternetCloseHandle(hDir);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return TRUE;
}
else
{
// Handle the error.
ErrorOut (hX, GetLastError(),
TEXT("InternetFindNextFile"));
// Close the HINTERNET handle.
InternetCloseHandle(hDir);
// Set the cursor back to an arrow.
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return.
return FALSE;
}
}
else
{
// Write the file name to a string.
StringCchPrintf(DirList, MAX_PATH, pDirInfo.cFileName);
// Check the type of file.
if(pDirInfo.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
{
// Add <DIR> to indicate that this is a
// directory to the user.
StringCchCat(DirList, MAX_PATH, TEXT(" <DIR> "));
// Add error handling code here.
}
// Add the file name (or directory) to the list box.
SendDlgItemMessage(hX, lstDirectory, LB_ADDSTRING,
0, (LPARAM)DirList);
}
}
while ( TRUE);
}
Управление параметрами
InternetSetOption и InternetQueryOption используются для управления параметрами WinINet.
InternetSetOption принимает переменную, указывающую параметр для задания, буфер для хранения параметра и указатель, содержащий адрес переменной, содержащей длину буфера.
InternetQueryOption принимает переменную, указывающую извлекаемую опцию, буфер для хранения параметра и указатель, содержащий адрес переменной, содержащей длину буфера.
Настройка асинхронных операций
По умолчанию функции WinINet работают синхронно. Приложение может запросить асинхронную операцию, установив флаг INTERNET_FLAG_ASYNC в вызове функции InternetOpen . Все будущие вызовы к дескрипторам, производным от дескриптора, возвращаемого из InternetOpen , выполняются асинхронно.
Обоснование асинхронных и синхронных операций заключается в том, чтобы однопоточное приложение максимально эффективно использовать ЦП, не дожидаясь завершения сетевого ввода-вывода. Таким образом, в зависимости от запроса операция может выполняться синхронно или асинхронно. Приложение должно проверка код возврата. Если функция возвращает FALSE или NULL, а GetLastError возвращает ERROR_IO_PENDING, запрос выполняется асинхронно, а приложение вызывается с INTERNET_STATUS_REQUEST_COMPLETE после завершения функции.
Чтобы начать асинхронную работу, приложение должно установить флаг INTERNET_FLAG_ASYNC в вызове InternetOpen. Затем приложение должно зарегистрировать допустимую функцию обратного вызова с помощью InternetSetStatusCallback.
После регистрации функции обратного вызова для дескриптора все операции с этим дескриптором могут создавать признаки состояния при условии, что значение контекста, предоставленное при создании дескриптора, не равно нулю. Указание нулевого значения контекста приводит к синхронному завершению операции, несмотря на то, что INTERNET_FLAG_ASYNC была указана в InternetOpen.
Индикаторы состояния дают приложению отзывы о ходе выполнения сетевых операций, таких как разрешение имени узла, подключение к серверу и получение данных. Для дескриптора можно сделать три указания состояния специального назначения:
- INTERNET_STATUS_HANDLE_CLOSING является последним признаком состояния дескриптора.
- INTERNET_STATUS_HANDLE_CREATED указывает, когда дескриптор изначально создан.
- INTERNET_STATUS_REQUEST_COMPLETE указывает, что асинхронная операция завершена.
Приложение должно проверка структуру INTERNET_ASYNC_RESULT, чтобы определить, была ли операция успешной или неудачной после получения INTERNET_STATUS_REQUEST_COMPLETE указания.
В следующем примере показан пример функции обратного вызова и вызова InternetSetStatusCallback для регистрации функции в качестве функции обратного вызова.
void CALLBACK InternetCallback(
HINTERNET hInternet,
DWORD_PTR dwcontext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
)
{
_tprintf(TEXT("%0xd %0xp %0xd %0xp %0xd\n"),
hInternet,
dwcontext,
dwInternetStatus,
lpvStatusInformation,
dwStatusInformationLength);
};
INTERNET_STATUS_CALLBACK dwISC =
InternetSetStatusCallback(hInternet, InternetCallback);
Закрытие дескрипторов HINTERNET
Все дескрипторы HINTERNET можно закрыть с помощью функции InternetCloseHandle . Клиентские приложения должны закрыть все дескрипторы HINTERNET, производные от дескриптора HINTERNET , который они пытаются закрыть перед вызовом InternetCloseHandle для дескриптора.
В следующем примере показана иерархия дескрипторов.
HINTERNET hRootHandle, hOpenUrlHandle;
hRootHandle = InternetOpen( TEXT("Example"),
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL, 0);
hOpenUrlHandle = InternetOpenUrl(hRootHandle,
TEXT("https://www.server.com/default.htm"), NULL, 0,
INTERNET_FLAG_RAW_DATA,0);
// Close the handle created by InternetOpenUrl so that the
// InternetOpen handle can be closed.
InternetCloseHandle(hOpenUrlHandle);
// Close the handle created by InternetOpen.
InternetCloseHandle(hRootHandle);
Блокировка и разблокировка ресурсов
Функция InternetLockRequestFile позволяет приложению гарантировать, что кэшированный ресурс, связанный с переданным ему дескриптором HINTERNET , не исчезает из кэша. Если другая загрузка пытается зафиксировать ресурс с тем же URL-адресом, что и заблокированный файл, кэш избегает удаления файла путем безопасного удаления. После того как приложение вызовет функцию InternetUnlockRequestFile , кэш получает разрешение на удаление файла.
Если установлен флаг INTERNET_FLAG_NO_CACHE_WRITE или INTERNET_FLAG_DONT_CACHE , InternetLockRequestFile создает временный файл с расширением TMP, если дескриптор не подключен к ресурсу HTTPS. Если функция обращается к ресурсу HTTPS и INTERNET_FLAG_NO_CACHE_WRITE (или INTERNET_FLAG_DONT_CACHE), InternetLockRequestFile завершается ошибкой .
Примечание
WinINet не поддерживает реализации сервера. Кроме того, его не следует использовать из службы. Для серверных реализаций или служб используйте службы Microsoft Windows HTTP (WinHTTP).