Contents Index Topic Contents | ||
Previous Topic: Enabling Internet Functionality Next Topic: Handling Uniform Resource Locators |
Common Functions
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:
- Downloading resources from the Internet can be handled by the InternetReadFile, InternetSetFilePointer, InternetFindNextFile, and InternetQueryDataAvailable functions.
- Setting up asynchronous operations is handled by the InternetSetStatusCallback.
- Viewing and changing options is handled by the InternetSetOption and InternetQueryOption functions.
- Closing all types of HINTERNET handles is handled by the InternetCloseHandle function.
- Placing and removing locks on resources being used with InternetLockRequestFile and InternetUnlockRequestFile.
Using Common Functions
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.
Reading files
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:
- Using the InternetQueryDataAvailable function.
- Using the return values of InternetReadFile.
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; }Finding the next file
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); }Manipulating options
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.
Setting up asynchronous operations
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:
- INTERNET_STATUS_HANDLE_CLOSING is the last status indication that is made for a handle.
- INTERNET_STATUS_HANDLE_CREATED indicates when the handle is initially created.
- INTERNET_STATUS_REQUEST_COMPLETE indicates when an asynchronous operation completes.
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);Closing HINTERNET handles
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);Locking and unlocking resources
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.
Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.