Funciones comunes (Windows Internet)
Los distintos protocolos de Internet (como ftp y http) usan varias de las mismas funciones de WinINet para controlar la información en Internet. Estas funciones comunes controlan sus tareas de forma coherente, independientemente del protocolo concreto al que se aplican. Las aplicaciones pueden usar estas funciones para crear funciones de uso general que controlan las tareas en los distintos protocolos (como leer archivos para ftp y http).
Las funciones comunes controlan las siguientes tareas:
- Descargar recursos desde Internet (InternetReadFile, InternetSetFilePointer, InternetFindNextFile y InternetQueryDataAvailable).
- Configuración de operaciones asincrónicas (InternetSetStatusCallback).
- Ver y cambiar opciones (InternetSetOption e InternetQueryOption).
- Cierre de todos los tipos de identificadores HINTERNET (InternetCloseHandle).
- Colocación y eliminación de bloqueos en recursos (InternetLockRequestFile e InternetUnlockRequestFile).
Uso de funciones comunes
En la tabla siguiente se enumeran las funciones comunes incluidas en las funciones winINet. Las funciones comunes se pueden usar en diferentes tipos de identificadores HINTERNET o se pueden usar durante diferentes tipos de sesiones.
Función | Descripción |
---|---|
InternetFindNextFile | Continúa la enumeración de archivos o la búsqueda. Requiere un identificador creado por la función FtpFindFirstFile o InternetOpenUrl . |
InternetLockRequestFile | Permite al usuario colocar un bloqueo en el archivo que se está usando. Esta función requiere un identificador devuelto por la función FtpOpenFile, HttpOpenRequest o InternetOpenUrl . |
InternetQueryDataAvailable | Recupera la cantidad de datos disponibles. Requiere un identificador creado por la función FtpOpenFile o HttpOpenRequest . |
InternetQueryOption | Recupera la configuración de una opción de Internet. |
InternetReadFile | Lee los datos de dirección URL. Requiere un identificador creado por la función InternetOpenUrl, FtpOpenFile o HttpOpenRequest . |
InternetSetFilePointer | Establece la posición de la siguiente lectura en un archivo. Requiere un identificador creado por InternetOpenUrl (solo en una dirección URL HTTP) o un identificador creado por HttpOpenRequest mediante el verbo HTTP GET. |
InternetSetOption | Establece una opción de Internet. |
InternetSetStatusCallback | Establece una función de devolución de llamada que recibe información de estado. Asigna una función de devolución de llamada al identificador HINTERNET designado y todos los identificadores derivados de ella. |
InternetUnlockRequestFile | Desbloquea un archivo bloqueado mediante la función InternetLockRequestFile . |
Leer archivos, buscar el siguiente archivo, manipular opciones y configurar operaciones asincrónicas son comunes a las funciones que admiten varios protocolos y tipos de identificador HINTERNET .
Leer archivos
La función InternetReadFile se usa para descargar recursos de un identificador HINTERNET devuelto por la función InternetOpenUrl, FtpOpenFile o HttpOpenRequest .
InternetReadFile acepta una variable de puntero void que contiene la dirección de un búfer y un puntero a una variable que contiene la longitud del búfer. La función devuelve los datos del búfer y la cantidad de datos descargados en el búfer.
Las funciones winINet proporcionan dos técnicas para descargar un recurso completo:
- Función InternetQueryDataAvailable .
- Valores devueltos de InternetReadFile.
InternetQueryDataAvailable toma el identificador HINTERNET creado por InternetOpenUrl, FtpOpenFile o HttpOpenRequest (después de llamar a HttpSendRequest en el identificador) y devuelve el número de bytes disponibles. La aplicación debe asignar un búfer igual al número de bytes disponibles, más 1 para el carácter nulo de terminación y usar ese búfer con InternetReadFile. Este método no siempre funciona porque InternetQueryDataAvailable comprueba el tamaño del archivo que aparece en el encabezado y no el archivo real. La información del archivo de encabezado podría estar obsoleta o podría faltar el archivo de encabezado, ya que actualmente no es necesaria en todos los estándares.
En el ejemplo siguiente se lee el contenido del recurso al que accede el identificador hResource y se muestra en el cuadro de edición indicado 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 devuelve cero bytes leídos y se completa correctamente cuando se han leído todos los datos disponibles. Esto permite que una aplicación use InternetReadFile en un bucle para descargar los datos y salir cuando devuelve cero bytes leídos y se completa correctamente.
En el ejemplo siguiente se lee el recurso de Internet y se muestra el recurso en el cuadro de edición indicado por intCtrlID. El identificador HINTERNET , hInternet, lo devolvió InternetOpenUrl, FtpOpenFile o HttpOpenRequest (después de 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;
}
Buscar el siguiente archivo
La función InternetFindNextFile se usa para buscar el siguiente archivo en una búsqueda de archivos, mediante los parámetros de búsqueda y el identificador HINTERNET de FtpFindFirstFile o InternetOpenUrl.
Para completar una búsqueda de archivos, continúe llamando a InternetFindNextFile mediante el identificador HINTERNET devuelto por FtpFindFirstFile o InternetOpenUrl hasta que se produzca un error en la función con el mensaje de error extendido ERROR_NO_MORE_FILES. Para obtener la información de error extendida, llame a la función GetLastError .
En el ejemplo siguiente se muestra el contenido de un directorio FTP en el cuadro de lista indicado por lstDirectory. El identificador HINTERNET , hConnect, es un identificador devuelto por la función InternetConnect después de establecer una sesión 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);
}
Manipular opciones
InternetSetOption e InternetQueryOption se usan para manipular las opciones de WinINet.
InternetSetOption acepta una variable que indica la opción que se va a establecer, un búfer que contiene la configuración de opción y un puntero que contiene la dirección de la variable que contiene la longitud del búfer.
InternetQueryOption acepta una variable que indica la opción de recuperar, un búfer para contener la configuración de opción y un puntero que contiene la dirección de la variable que contiene la longitud del búfer.
Configuración de operaciones asincrónicas
De forma predeterminada, las funciones de WinINet funcionan de forma sincrónica. Una aplicación puede solicitar una operación asincrónica estableciendo la marca INTERNET_FLAG_ASYNC en la llamada a la función InternetOpen . Todas las llamadas futuras realizadas en identificadores derivados del identificador devuelto por InternetOpen se realizan de forma asincrónica.
La justificación de la operación asincrónica frente a sincrónica es permitir que una aplicación de un solo subproceso maximice su uso de la CPU sin tener que esperar a que se complete la E/S de red. Por lo tanto, dependiendo de la solicitud, la operación puede completarse de forma sincrónica o asincrónica. La aplicación debe comprobar el código de retorno. Si una función devuelve FALSE o NULL y GetLastError devuelve ERROR_IO_PENDING, la solicitud se ha realizado de forma asincrónica y la aplicación se llama de nuevo con INTERNET_STATUS_REQUEST_COMPLETE cuando se ha completado la función.
Para iniciar la operación asincrónica, la aplicación debe establecer la marca INTERNET_FLAG_ASYNC en su llamada a InternetOpen. A continuación, la aplicación debe registrar una función de devolución de llamada válida mediante InternetSetStatusCallback.
Después de registrar una función de devolución de llamada para un identificador, todas las operaciones de ese identificador pueden generar indicaciones de estado, siempre que el valor de contexto que se proporcionó cuando se creó el identificador no fuera cero. Proporcionar un valor de contexto cero obliga a una operación a completarse sincrónicamente, aunque INTERNET_FLAG_ASYNC se especificó en InternetOpen.
Las indicaciones de estado proporcionan a la aplicación comentarios sobre el progreso de las operaciones de red, como resolver un nombre de host, conectarse a un servidor y recibir datos. Se pueden realizar tres indicaciones de estado de propósito especial para un identificador:
- INTERNET_STATUS_HANDLE_CLOSING es la última indicación de estado que se realiza para un identificador.
- INTERNET_STATUS_HANDLE_CREATED indica cuándo se crea inicialmente el identificador.
- INTERNET_STATUS_REQUEST_COMPLETE indica que se ha completado una operación asincrónica.
La aplicación debe comprobar la estructura de INTERNET_ASYNC_RESULT para determinar si la operación se realizó correctamente o no después de recibir una indicación de INTERNET_STATUS_REQUEST_COMPLETE.
En el ejemplo siguiente se muestra un ejemplo de una función de devolución de llamada y una llamada a InternetSetStatusCallback para registrar la función como la función de devolución de llamada.
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);
Cierre de identificadores HINTERNET
Todos los identificadores HINTERNET se pueden cerrar mediante la función InternetCloseHandle . Las aplicaciones cliente deben cerrar todos los identificadores HINTERNET derivados del identificador HINTERNET que están intentando cerrar antes de llamar a InternetCloseHandle en el identificador.
En el ejemplo siguiente se muestra la jerarquía 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);
Bloqueo y desbloqueo de recursos
La función InternetLockRequestFile permite a una aplicación asegurarse de que el recurso almacenado en caché asociado al identificador HINTERNET que se le pasa no desaparece de la memoria caché. Si otra descarga intenta confirmar un recurso que tiene la misma dirección URL que el archivo bloqueado, la memoria caché evita quitar el archivo realizando una eliminación segura. Una vez que la aplicación llama a la función InternetUnlockRequestFile , la memoria caché tiene permiso para eliminar el archivo.
Si se ha establecido la marca INTERNET_FLAG_NO_CACHE_WRITE o INTERNET_FLAG_DONT_CACHE , InternetLockRequestFile crea un archivo temporal con la extensión TMP, a menos que el identificador esté conectado a un recurso https. Si la función tiene acceso a un recurso https y INTERNET_FLAG_NO_CACHE_WRITE (o INTERNET_FLAG_DONT_CACHE) se ha establecido, Se produce un error en InternetLockRequestFile .
Nota
WinINet no admite implementaciones de servidor. Además, no se debe usar desde un servicio. En el caso de las implementaciones de servidor o los servicios, use los servicios HTTP de Microsoft Windows (WinHTTP).