
The different Internet protocols (such as FTP, HTTP, and Gopher) use several of the same Win32 Internet functions to handle information on the Internet. These common functions handle their tasks in a consistent manner, regardless of the particular protocol to which they are being applied. Applications can use these functions to create general-purpose functions that handle tasks across the different protocols (such as reading files for FTP, HTTP, and Gopher protocols).
The common functions handle the following tasks:
The following table lists the common functions included in the Win32 Internet functions. The common functions can be used on different types of HINTERNET handles or can be used during different types of sessions.
| Function | Description |
| InternetFindNextFile | Continues file enumeration or search. Requires a handle created by the FtpFindFirstFile, GopherFindFirstFile, or InternetOpenUrl function. |
| InternetLockRequestFile | Allows the user to place a lock on the file that is being used. This function requires a handle returned by the FtpOpenFile, GopherOpenFile, HttpOpenRequest, or InternetOpenUrl function. |
| InternetQueryDataAvailable | Queries the amount of data available. Requires a handle created by the FtpOpenFile, GopherOpenFile, or HttpOpenRequest function. |
| InternetQueryOption | Queries the setting of an Internet option. |
| InternetReadFile | Reads URL data. Requires a handle created by the InternetOpenUrl, FtpOpenFile, GopherOpenFile, or HttpOpenRequest function. |
| InternetSetFilePointer | Sets the position for the next read in a file. Requires a handle created by InternetOpenUrl (on an HTTP URL only) or a handle created by HttpOpenRequest using the GET method. |
| InternetSetOption | Sets an Internet option. |
| InternetSetStatusCallback | Sets a callback function that is called with status information. Assigns a callback function to the designated HINTERNET handle and all handles derived from it. |
| InternetUnlockRequestFile | Unlocks a file that was locked using the InternetLockRequestFile function. |
Reading files, finding the next file, manipulating options, and setting up asynchronous operations are common to various protocols and HINTERNET handle types.
The InternetReadFile function is used to download resources from an HINTERNET handle returned by the InternetOpenUrl, FtpOpenFile, GopherOpenFile, or HttpOpenRequest function.
InternetReadFile accepts a void pointer variable that contains the address of a buffer and a pointer to a double-word (DWORD) variable that contains the length of the buffer. It returns the data in the buffer and the amount of data downloaded into the buffer.
The Win32 Internet functions provide two techniques to download an entire resource:
InternetQueryDataAvailable takes the HINTERNET handle created by InternetOpenUrl, FtpOpenFile, GopherOpenFile, or HttpOpenRequest (after HttpSendRequest has been called on the handle) and returns the number of bytes available. The application should allocate a buffer equal to the number of bytes available +1 for the NULL terminator, and use that buffer with InternetReadFile. This method does not always work because InternetQueryDataAvailable is checking the file size listed in the header and not the actual file. The information in the header file could be outdated or the header file could be missing, since it is not currently required under all standards.
The following example reads the contents of the resource accessed by the hResource handle and displayed in the edit box indicated by intCtrlID.
int WINAPI Dumper(HWND hX, int intCtrlID, HINTERNET hResource)
{
LPSTR 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 textbox
LPSTR lpszHolding; // buffer to merge the textbox 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(),"InternetReadFile");
SetCursor(LoadCursor(NULL,IDC_ARROW));
return FALSE;
}
else
{
// Allocates a buffer of the size returned by InternetQueryDataAvailable
lpszData = new char[dwSize+1];
// Reads the data from the HINTERNET handle.
if(!InternetReadFile(hResource,(LPVOID)lpszData,dwSize,&dwDownloaded))
{
ErrorOut(hX,GetLastError(),"InternetReadFile");
delete[] lpszData;
break;
}
else
{
// Adds a null terminator to the end of the data buffer
lpszData[dwDownloaded]='\0';
// Allocates the holding buffer
lpszHolding = new char[dwSizeSum + dwDownloaded + 1];
// Checks if there has been any data written to the textbox
if (dwSizeSum != 0)
{
// Retrieves the data stored in the textbox if any
GetDlgItemText(hX,intCtrlID,(LPSTR)lpszHolding,dwSizeSum);
// Adds a null terminator at the end of the textbox data
lpszHolding[dwSizeSum]='\0';
}
else
{
// Make the holding buffer an empty string.
lpszHolding[0]='\0';
}
// Adds the new data to the holding buffer
strcat(lpszHolding,lpszData);
// Writes the holding buffer to the textbox
SetDlgItemText(hX,intCtrlID,(LPSTR)lpszHolding);
// Delete the two buffers
delete[] lpszHolding;
delete[] lpszData;
// Add the size of the downloaded data to the textbox data size
dwSizeSum = dwSizeSum + dwDownloaded + 1;
// Check the size of the remaining data. If it is zero, break.
if (dwDownloaded == 0)
break;
}
}
}
while(TRUE);
// Close the HINTERNET handle
InternetCloseHandle(hResource);
// Set the cursor back to an arrow
SetCursor(LoadCursor(NULL,IDC_ARROW));
// Return
return TRUE;
}
InternetReadFile returns zero bytes read and completes successfully when all available data has been read. This allows an application to use InternetReadFile in a loop to download the data and exit when it returns zero bytes read and completes successfully.
The following example reads the resource from the Internet and displays the resource in the edit box indicated by intCtrlID. The HINTERNET handle, hResource, has been returned by InternetOpenUrl, FtpOpenFile, GopherOpenFile, or HttpOpenRequest (after being sent by HttpSendRequest).
int WINAPI Dump(HWND hX, int intCtrlID, HINTERNET hResource)
{
DWORD dwSize = 0;
LPSTR lpszData;
LPSTR lpszOutPut;
LPSTR lpszHolding;
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 char[BigSize+1];
// Read the data
if(!InternetReadFile(hResource,(LPVOID)lpszData,BigSize,&dwSize))
{
ErrorOut(hX,GetLastError(),"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 textbox
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 textbox (if any).
nBufferSize = (nCounter*BigSize)+1;
// Increment the number of buffers read
nCounter++;
// Allocate the output buffer
lpszOutPut = new char[nBufferSize];
// Make sure the buffer is not the initial buffer
if(nBufferSize != int(BigSize+1))
{
// Copy the data in the holding buffer
strcpy(lpszOutPut,lpszHolding);
// Concatenate the new buffer with the output buffer
strcat(lpszOutPut,lpszData);
// Delete the holding buffer
delete [] lpszHolding;
}
else
{
// Copy the data buffer
strcpy(lpszOutPut, lpszData);
}
// Allocate a holding buffer
lpszHolding = new char[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;
}
The InternetFindNextFile function is used to find the next file in a file search, using the search parameters and HINTERNET handle from either FtpFindFirstFile, GopherFindFirstFile, or InternetOpenUrl.
To complete a file search, continue to call InternetFindNextFile using the HINTERNET handle returned by FtpFindFirstFile, GopherFindFirstFile, or InternetOpenUrl until the function fails with the extended error message ERROR_NO_MORE_FILES. To get the extended error information, call the GetLastError function.
The following example displays the contents of an FTP directory in the list box, IDC_FTPList. The HINTERNET handle, hSecondary, is a handle returned by the InternetConnect function after it establishes an FTP session.
bool WINAPI DisplayDir(HWND hX, int lstDirectory, HINTERNET hConnect,
DWORD dwFlag)
{
WIN32_FIND_DATA pDirInfo;
HINTERNET hDir;
char 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
if ( !(hDir = FtpFindFirstFile (hConnect, TEXT ("*.*"), &pDirInfo,
dwFlag, 0) ))
{
// Check if the error was because there were no files
if (GetLastError() == ERROR_NO_MORE_FILES)
{
// Alert user
MessageBox(hX,"There are no files here!!!","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 (), "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 filename to a string
sprintf(DirList, 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
strcat(DirList," <DIR> ");
}
// Add the filename (or directory) to the listbox
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(), "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 filename to a string
sprintf(DirList, 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
strcat(DirList," <DIR> ");
}
// Add the filename (or directory) to the listbox
SendDlgItemMessage(hX,lstDirectory,LB_ADDSTRING,0,(LPARAM)DirList);
}
}
while ( TRUE);
}
InternetSetOption and InternetQueryOption are used to manipulate the Win32 Internet API options.
InternetSetOption accepts a double-word value that indicates the option to set, a buffer to hold the option setting, and a pointer that contains the address of the variable containing the length of the buffer.
InternetQueryOption accepts a double-word value that indicates the option to query, a buffer to hold the option setting, and a pointer that contains the address of the variable containing the length of the buffer.
By default, the Win32 Internet functions operate synchronously. An application can request asynchronous operation by setting the INTERNET_FLAG_ASYNC flag in the call to the InternetOpen function. All future calls made against handles derived from the handle returned from InternetOpen will be made asynchronously.
The rationale for asynchronous versus synchronous operation is to allow a single-threaded application to maximize its utilization of the CPU without having to wait for network I/O to complete. Therefore, depending on the request, the operation might complete synchronously or asynchronously. The application should check the return code. If a function returns FALSE or NULL, and GetLastError returns ERROR_IO_PENDING, the request has been made asynchronously, and the application will be called back with INTERNET_STATUS_REQUEST_COMPLETE when the function has completed.
For an application to be able to make requests asynchronously, it must set the INTERNET_FLAG_ASYNC flag in the call to InternetOpen, it must register a valid callback function, and it must supply a nonzero context value.
To begin asynchronous operation, the application must set the INTERNET_FLAG_ASYNC flag in its call to InternetOpen. It must then register a valid callback function, using InternetSetStatusCallback.
After a callback function is registered for a handle, all operations on that handle can generate status indications, provided that the context value that was supplied when the handle was created was not zero. Providing a zero context value forces an operation to complete synchronously, even though INTERNET_FLAG_ASYNC was specified in InternetOpen.
Status indications are mainly intended to give the application feedback about the operation's progress and are mainly concerned with network operations, such as resolving a host name, connecting to a server, and receiving data. Three special-purpose status indications can be made for a handle:
The application must check the INTERNET_ASYNC_RESULT structure to determine whether the operation succeeded or failed after receiving an INTERNET_STATUS_REQUEST_COMPLETE indication.
The following sample shows an example of a callback function and a call to InternetSetStatusCallback to register the function as the callback function.
void
CALLBACK
CInternet::InternetCallback(
HINTERNET hInternet,
DWORD dwcontext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
)
{
// Insert code here.
};
INTERNET_STATUS_CALLBACK dwISC;
dwISC = InternetSetStatusCallback( hInternet,
(INTERNET_STATUS_CALLBACK) InternetCallback);
All HINTERNET handles can be closed by using the InternetCloseHandle function. Client applications must close all HINTERNET handles derrived from the HINTERNET handle to be closed before calling InternetCloseHandle. For more information about HINTERNET handles and the handle hierarchy, see Appendix A: HINTERNET Handles.
The following example illustrates the handle hierarchy for the Win32 Internet functions.
HINTERNET hRootHandle, hOpenUrlHandle;
hRootHandle = InternetOpen("Example", INTERNET_OPEN_TYPE_DIRECT, NULL,
NULL, 0);
hOpenUrlHandle = InternetOpenUrl(hRootHandle,
"http://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);
The InternetLockRequestFile function allows an application to ensure that the cached resource associated with the HINTERNET handle passed to it will not disappear from the cache. If another download tries to commit a resource that has the same URL as the locked file, the cache avoids removing the file by doing a safe delete. After the application calls the InternetUnlockRequestFile function, the cache is given permission to delete the file.
If the INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_DONT_CACHE flag has been set, InternetLockRequestFile creates a temporary file with the extension TMP, unless the handle is connected to an HTTPS resource. If the function is accessing an HTTPS resource and INTERNET_FLAG_NO_CACHE_WRITE (or INTERNET_FLAG_DONT_CACHE) has been set, InternetLockRequestFile fails.
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.