Common FunctionsCommon Functions*
*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:

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:

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:

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.


Up Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.