Funções comuns (Internet do Windows)
Os diferentes protocolos de Internet (como ftp e http) usam várias das mesmas funções WinINet para lidar com informações na Internet. Essas funções comuns lidam com suas tarefas de maneira consistente, independentemente do protocolo específico ao qual estão sendo aplicadas. Os aplicativos podem usar essas funções para criar funções de uso geral que lidam com tarefas entre os diferentes protocolos (como ler arquivos para ftp e http).
As funções comuns lidam com as seguintes tarefas:
- Baixando recursos da Internet (InternetReadFile, InternetSetFilePointer, InternetFindNextFile e InternetQueryDataAvailable).
- Configurando operações assíncronas (InternetSetStatusCallback).
- Exibindo e alterando opções (InternetSetOption e InternetQueryOption).
- Fechando todos os tipos de identificadores HINTERNET (InternetCloseHandle).
- Colocar e remover bloqueios em recursos (InternetLockRequestFile e InternetUnlockRequestFile).
Usando funções comuns
A tabela a seguir lista as funções comuns incluídas nas funções WinINet. As funções comuns podem ser usadas em diferentes tipos de identificadores HINTERNET ou podem ser usadas durante diferentes tipos de sessões.
Função | Descrição |
---|---|
InternetFindNextFile | Continua a enumeração ou pesquisa de arquivos. Requer um identificador criado pela função FtpFindFirstFile ou InternetOpenUrl . |
InternetLockRequestFile | Permite que o usuário coloque um bloqueio no arquivo que está sendo usado. Essa função requer um identificador retornado pela função FtpOpenFile, HttpOpenRequest ou InternetOpenUrl . |
InternetQueryDataAvailable | Recupera a quantidade de dados disponíveis. Requer um identificador criado pela função FtpOpenFile ou HttpOpenRequest . |
InternetQueryOption | Recupera a configuração de uma opção da Internet. |
InternetReadFile | Lê dados de URL. Requer um identificador criado pela função InternetOpenUrl, FtpOpenFile ou HttpOpenRequest . |
InternetSetFilePointer | Define a posição para a próxima leitura em um arquivo. Requer um identificador criado por InternetOpenUrl (somente em uma URL HTTP) ou um identificador criado por HttpOpenRequest usando o verbo HTTP GET. |
InternetSetOption | Define uma opção de Internet. |
InternetSetStatusCallback | Define uma função de retorno de chamada que recebe status informações. Atribui uma função de retorno de chamada ao identificador HINTERNET designado e a todos os identificadores derivados dela. |
InternetUnlockRequestFile | Desbloqueia um arquivo que foi bloqueado usando a função InternetLockRequestFile . |
Ler arquivos, localizar o próximo arquivo, manipular opções e configurar operações assíncronas são comuns às funções que dão suporte a vários protocolos e tipos de identificador HINTERNET .
Lendo arquivos
A função InternetReadFile é usada para baixar recursos de um identificador HINTERNET retornado pela função InternetOpenUrl, FtpOpenFile ou HttpOpenRequest .
InternetReadFile aceita uma variável de ponteiro void que contém o endereço de um buffer e um ponteiro para uma variável que contém o comprimento do buffer. A função retorna os dados no buffer e a quantidade de dados baixados no buffer.
As funções WinINet fornecem duas técnicas para baixar um recurso inteiro:
- A função InternetQueryDataAvailable .
- Os valores retornados de InternetReadFile.
InternetQueryDataAvailable usa o identificador HINTERNET criado por InternetOpenUrl, FtpOpenFile ou HttpOpenRequest (depois que HttpSendRequest foi chamado no identificador) e retorna o número de bytes disponíveis. O aplicativo deve alocar um buffer igual ao número de bytes disponíveis, mais 1 para o caractere nulo de terminação e usar esse buffer com InternetReadFile. Esse método nem sempre funciona porque InternetQueryDataAvailable está verificando o tamanho do arquivo listado no cabeçalho e não o arquivo real. As informações no arquivo de cabeçalho podem estar desatualizadas ou o arquivo de cabeçalho pode estar ausente, pois não é necessário atualmente em todos os padrões.
O exemplo a seguir lê o conteúdo do recurso acessado pelo identificador hResource e exibido na caixa de edição indicada por 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 retorna zero bytes lidos e concluídos com êxito quando todos os dados disponíveis foram lidos. Isso permite que um aplicativo use InternetReadFile em um loop para baixar os dados e sair quando ele retorna zero bytes lidos e concluídos com êxito.
O exemplo a seguir lê o recurso da Internet e exibe o recurso na caixa de edição indicada por intCtrlID. O identificador HINTERNET , hInternet, foi retornado por InternetOpenUrl, FtpOpenFile ou HttpOpenRequest (após ser enviado por 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;
}
Localizando o próximo arquivo
A função InternetFindNextFile é usada para localizar o próximo arquivo em uma pesquisa de arquivo, usando os parâmetros de pesquisa e o identificador HINTERNET de FtpFindFirstFile ou InternetOpenUrl.
Para concluir uma pesquisa de arquivo, continue a chamar InternetFindNextFile usando o identificador HINTERNET retornado por FtpFindFirstFile ou InternetOpenUrl até que a função falhe com a mensagem de erro estendida ERROR_NO_MORE_FILES. Para obter as informações de erro estendidas, chame a função GetLastError .
O exemplo a seguir exibe o conteúdo de um diretório FTP na caixa de listagem indicada por lstDirectory. O identificador HINTERNET , hConnect, é um identificador retornado pela função InternetConnect depois de estabelecer uma sessão 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);
}
Manipulando opções
InternetSetOption e InternetQueryOption são usados para manipular as opções do WinINet.
InternetSetOption aceita uma variável que indica a opção a ser definida, um buffer para manter a configuração de opção e um ponteiro que contém o endereço da variável que contém o comprimento do buffer.
InternetQueryOption aceita uma variável que indica a opção de recuperação, um buffer para manter a configuração de opção e um ponteiro que contém o endereço da variável que contém o comprimento do buffer.
Configurando operações assíncronas
Por padrão, as funções WinINet operam de forma síncrona. Um aplicativo pode solicitar uma operação assíncrona definindo o sinalizador INTERNET_FLAG_ASYNC na chamada para a função InternetOpen . Todas as chamadas futuras feitas em relação a identificadores derivados do identificador retornado de InternetOpen são feitas de forma assíncrona.
A lógica para a operação assíncrona versus síncrona é permitir que um aplicativo de thread único maximize sua utilização da CPU sem precisar aguardar a conclusão da E/S de rede. Portanto, dependendo da solicitação, a operação pode ser concluída de forma síncrona ou assíncrona. O aplicativo deve marcar o código de retorno. Se uma função retornar FALSE ou NULL e GetLastError retornar ERROR_IO_PENDING, a solicitação será feita de forma assíncrona e o aplicativo será chamado novamente com INTERNET_STATUS_REQUEST_COMPLETE quando a função for concluída.
Para iniciar a operação assíncrona, o aplicativo deve definir o sinalizador INTERNET_FLAG_ASYNC em sua chamada para InternetOpen. Em seguida, o aplicativo deve registrar uma função de retorno de chamada válida usando InternetSetStatusCallback.
Depois que uma função de retorno de chamada é registrada para um identificador, todas as operações nesse identificador podem gerar status indicações, desde que o valor de contexto fornecido quando o identificador foi criado não fosse zero. Fornecer um valor de contexto zero força uma operação a ser concluída de forma síncrona, mesmo que INTERNET_FLAG_ASYNC tenha sido especificado em InternetOpen.
As indicações de status fornecem comentários ao aplicativo sobre o progresso das operações de rede, como resolver um nome de host, conectar-se a um servidor e receber dados. Três indicações de status de finalidade especial podem ser feitas para um identificador:
- INTERNET_STATUS_HANDLE_CLOSING é a última indicação status feita para um identificador.
- INTERNET_STATUS_HANDLE_CREATED indica quando o identificador é criado inicialmente.
- INTERNET_STATUS_REQUEST_COMPLETE indica que uma operação assíncrona foi concluída.
O aplicativo deve marcar a estrutura INTERNET_ASYNC_RESULT para determinar se a operação foi bem-sucedida ou falhou depois de receber uma indicação de INTERNET_STATUS_REQUEST_COMPLETE.
O exemplo a seguir mostra um exemplo de uma função de retorno de chamada e uma chamada para InternetSetStatusCallback para registrar a função como a função de retorno de chamada.
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);
Fechando identificadores HINTERNET
Todos os identificadores HINTERNET podem ser fechados usando a função InternetCloseHandle . Os aplicativos cliente devem fechar todos os identificadores HINTERNET derivados do identificador HINTERNET que estão tentando fechar antes de chamar InternetCloseHandle no identificador.
O exemplo a seguir ilustra a hierarquia de identificadores.
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);
Bloqueio e desbloqueio de recursos
A função InternetLockRequestFile permite que um aplicativo garanta que o recurso armazenado em cache associado ao identificador HINTERNET passado para ele não desapareça do cache. Se outro download tentar confirmar um recurso que tenha a mesma URL que o arquivo bloqueado, o cache evitará remover o arquivo fazendo uma exclusão segura. Depois que o aplicativo chama a função InternetUnlockRequestFile , o cache recebe permissão para excluir o arquivo.
Se o sinalizador INTERNET_FLAG_NO_CACHE_WRITE ou INTERNET_FLAG_DONT_CACHE tiver sido definido, InternetLockRequestFile criará um arquivo temporário com a extensão TMP, a menos que o identificador esteja conectado a um recurso https. Se a função acessar um recurso https e INTERNET_FLAG_NO_CACHE_WRITE (ou INTERNET_FLAG_DONT_CACHE) tiver sido definido, InternetLockRequestFile falhará.
Observação
O WinINet não dá suporte a implementações de servidor. Além disso, ele não deve ser usado de um serviço. Para implementações de servidor ou serviços, use Os Serviços HTTP do Microsoft Windows (WinHTTP).