Chapter 17

Using the Win32 Internet (WinInet) API

by Rob McGregor


CONTENTS

This chapter introduces Microsoft's WinInet API functions. It shows how you can use these functions to create your own Internet-enabled applications based on File Transfer Protocol (FTP), gopher, and HyperText Transfer Protocol (HTTP), and how the functions can be used to leverage a program in an internetworked environment.

Overview

You've already been introduced to the Internet, but this chapter introduces some exciting and highly useful new material. The new WinInet API functions provide easy access to common Internet protocols and provide a high-level API that provides a fast and direct path to making Internet-enabled applications.

NOTE
The Win32 Internet API functions described and used in this chapter are based on the beta 1 version of the WININET.DLL, which houses the API. The specifications for the WinInet API are subject to further revision by Microsoft before being moved into the Win32 API at some point in the future, but they are the most current as of this writing

Introducing the WinInet API

The WinInet API functions are built on the Windows Sockets protocol and fall rather neatly into four categories of functions. Although these are supported by MFC now (currently MFC 4.2), it is important to understand the underlying technology. Microsoft has promised that future versions of MFC will continue to wrap these functions into useful classes in typical MFC fashion and simplify the programming even more.

The four WinInet API function categories are as follows:

The WinInet API functions are exported from a redistributable dynamic link library called the WININET.DLL. This DLL currently can be redistributed with Win32 applications, and in future releases of Windows this functionality will be incorporated directly into all Microsoft operating systems.

Advantages of Using the WinInet API

The WinInet API functions give applications access to the Internet and provide several advantages to the Win32 application programmer. These advantages stem mainly from the high-level interface provided, which hides many of the gory details and the complexity inherent in programming Internet applications. Let's look at some of these advantages.

TCP/IP and Windows Sockets

Use of the WinInet API all but eliminates the need for a low-level understanding of TCP/IP and Windows Sockets. The API converts these Internet protocols into task-oriented functions that use the familiar Win32 API function style. You don't need to write WinSock code directly. In fact, you don't even need to be familiar with the TCP/IP protocol. The WinInet functions transparently execute WinSock functions for you.

A Friendly Interface

Use of the WinInet API also all but eliminates the need for a low-level knowledge of common Internet protocols such as File Transfer Protocol (FTP) and HyperText Transfer Protocol (HTTP). The concepts behind these protocols are fairly simple, but their actual implementations can be quite complex. The WinInet functions encapsulate the problems inherent in Internet programming and provide a common solution with consistent behavior across applications.

An Up-To-Date API and a Safe Bet

The underlying technology for the Internet is rapidly changing and evolving, and the WinInet API provides a standardized means of programming Internet applications. Because WinInet functions hide the actual implementations of specific protocols within a well structured, well conceived API, you can be assured that your tested WinInet code will work even when specifications change.

The API will remain fairly constant, providing you with a secure code base for your applications that is guaranteed to remain up-to-date. Microsoft programmers will simply update the internal implementation of the WININET.DLL to keep pace with evolving technology.

NOTE
The WinInet API and WININET.DLL are (as of this writing) included in the ActiveX SDK. Download the latest version of the ActiveX SDK from the Web to get the latest version of the WinInet API and WININET.DLL. You'll find this on the Web at the following URL
http://www.microsoft.com/msdownload/activex.htm

A Familiar Programming Interface

The WinInet API functions were designed to feel familiar to experienced Windows programmers. The functions have a familiar look and feel, and most return information in a familiar format. WinInet return values also are easily used in standard Win32 functions. Also, the WinInet API provides its functions in both ANSI and Unicode versions for total compatibility and to facilitate Unicode-only applications.

Multithreaded Application Support

The WinInet API functions are fully multithread safe. You can make simultaneous calls to WinInet functions from multiple threads without worrying about synchronization problems or deadlock. This is possible because the WinInet functions amazingly handle all multithread synchronization internally. (Now that's user-friendly!)

Persistent Data-Caching Support

The WinInet API functions provide persistent caching for all of the Internet protocols. What this means for you is that your application development can focus on the data itself, rather than on managing the data-cache.

Let's take a quick look at the four Win32 Internet API function groups to see what specific services the API offers for Win32 programmers.

Handles and Functions

The WinInet API functions utilize special Internet handles, and there are several different types of these that are used by the various API functions. Although they might all use the HINTERNET moniker on the surface, there are actually 13 different subtypes of Internet handles, and these are shown in Listing 17.1.


Listing 17.1. The 13 HINTERNET types defined in WININET.H.

//

// handle types

//



#define INTERNET_HANDLE_TYPE_INTERNET          

#define INTERNET_HANDLE_TYPE_CONNECT_FTP       

#define INTERNET_HANDLE_TYPE_CONNECT_GOPHER    

#define INTERNET_HANDLE_TYPE_CONNECT_HTTP      

#define INTERNET_HANDLE_TYPE_FTP_FIND          

#define INTERNET_HANDLE_TYPE_FTP_FIND_HTML     

#define INTERNET_HANDLE_TYPE_FTP_FILE          

#define INTERNET_HANDLE_TYPE_FTP_FILE_HTML     

#define INTERNET_HANDLE_TYPE_GOPHER_FIND       

#define INTERNET_HANDLE_TYPE_GOPHER_FIND_HTML  

#define INTERNET_HANDLE_TYPE_GOPHER_FILE       

#define INTERNET_HANDLE_TYPE_GOPHER_FILE_HTML  

#define INTERNET_HANDLE_TYPE_HTTP_REQUEST      


CAUTION
Each of the WinInet functions uses or returns one of these handle types. Although they all appear in code as an HINTERNET, these types are not interchangeable. You must be sure to call WinInet functions in the proper order to ensure that the HINTERNET returned from a function is the proper type to use in a subsequent function call

As I mentioned earlier, there are four main categories of WinInet functions. Let's look at each group of functions to see what services WinInet actually provides.

General-Purpose Internet Functions

The general-purpose WinInet functions apply to all protocols, including HTTP, FTP, and Gopher, and they perform basic Internet file manipulations. The WinInet functions use special Internet handles (HINTERNETs) that aren't compatible with standard Windows system handles but are mandatory for working with the WinInet API functions. The general-purpose WinInet functions are listed in Table 17.1.

Table 17.1. General-purpose WinInet functions.

FunctionDescription
InternetCanonicalizeUrl()Converts a URL to a canonical (conventional) form.
InternetCloseHandle()Closes any Internet handle that an application has opened.
InternetCombineUrl()Combines a base and relative URL into a single URL. The resultant URL will be canonical.
InternetConfirmZoneCrossing() Checks for changes between secure and non-secure URLs.
InternetConnect()Opens an FTP, Gopher, or HTTP session for a given site.
InternetCrackUrl()Cracks a URL into its component parts.
InternetCreateUrl()Creates a URL from its component parts.
InternetErrorDlg()Displays a dialog box that explains why an error occurred.
InternetFindNextFile()Continues a file search started as a result of a previous call to FtpFindFirstFile() or GopherFindFirstFile().
InternetGetLastResponseInfo() Gets error text from the last WinInet function that failed.
InternetOpen()Initializes an application's use of the Win32 Internet functions.
InternetOpenUrl()Begins reading an FTP, Gopher, or HTTP URL.
InternetQueryDataAvailable()Queries the amount of data available.
InternetQueryOption()Queries an Internet option on the specified handle.
InternetReadFile()Reads data from a handle opened by the InternetOpenUrl(), FtpOpenFile(), GopherOpenFile(), or HttpOpenRequest() functions.
InternetSetFilePointer()Sets a file position for InternetReadFile().
InternetSetOption()Sets an Internet option on the specified handle.
InternetSetOptionEx()Sets an Internet option on the specified handle.
InternetSetStatusCallback()Sets up a callback function that WinInet functions can call as progress is made during an operation.
InternetStatusCallback()This is a placeholder for the application-defined status callback.
InternetTimeFromSystemTime()Formats a date and time according to the specified Request For Comment (RFC) format.
InternetWriteFile()Writes data to an open Internet file.

What Is File Transfer Protocol (FTP)?

The File Transfer Protocol (FTP) is the underlying set of specifications that supports Internet file transfer. This is an extremely important service that allows files from one Internet host to copy files to and from any other Internet host.

FTP uses a client/server model that allows the client to send commands to the server (or host), which responds by carrying out the specified command. FTP enables you to upload files to the server and download files to your local machine. If you have the proper access to the server, FTP also enables you to create, browse, and delete files and directories on the server. This is powerful stuff!

Anonymous FTP

Anonymous FTP enables you to log on to a system using the user ID anonymous and use your e-mail address or name as a password. This facility gives you access to any publicly offered files and directories on an incredible number of host machines throughout the world. You can use FTP to browse authorized directories and upload or download files from any number of host machines that are set up to use anonymous FTP.

Using FTP, free of charge, you can download programs that do almost anything, and you can download information about nearly any topic right from the Net. FTP is a powerful facility that acts very much like the glue that holds the Internet together.

WinInet FTP Functions

The FTP functions deal with FTP file and directory manipulation and navigation, and they provide a standard interface to the FTP specification. Table 17.2 lists the WinInet FTP functions.

Table 17.2. WinInet FTP functions.

FunctionDescription
FtpCreateDirectory()Creates a new directory on the FTP server.
FtpDeleteFile()Deletes a file stored on the FTP server.
FtpFindFirstFile()Begins searching the current directory of the given FTP session.
FtpGetCurrentDirectory()Retrieves the current directory for the specified FTP session.
FtpGetFile()Retrieves a file from the FTP server and stores it under the specified filename, creating a new local file in the process.
FtpOpenFile()Initiates access to a remote file for writing or reading.
FtpPutFile()Stores a file on the FTP server.
FtpRemoveDirectory()Removes the specified directory on the FTP server.
FtpRenameFile()Renames a file stored on the FTP server.
FtpSetCurrentDirectory()Changes to a different working directory on the FTP server.

The Gopher

The Gopher is a client/server system that enables you to find resources anywhere on the Internet and retrieve the resources without even needing to know where they are coming from. This is an incredibly useful tool! There are thousands of Gopher servers on the Internet, storing all sorts of information. The Gopher provides transparent connection services, using other Internet protocols if necessary, to quickly and easily get the information you need.

NOTE
The original Gopher specification was developed at the University of Minnesota in 1991, and the Gopher got its name for two reasons: first, because it would "go-fer" information on the Net; and second, because Minnesota is nicknamed the Gopher state

WinInet Gopher Functions

The Gopher functions provide a standard interface to the Gopher specification. Table 17.3 lists the WinInet Gopher functions.

Table 17.3. WinInet Gopher functions.

FunctionDescription
GopherAttributeEnumerator()Defines a callback function that processes attribute information from a Gopher server. This callback function is installed by a call to the GopherGetAttribute() function.
GopherCreateLocator()Creates a Gopher or Gopher+ locator string from its component parts.
GopherFindFirstFile()Uses a Gopher locator and some search criteria to create a session with the server and locate the requested documents, binary files, index servers, or directory trees.
GopherGetAttribute()Allows an application to retrieve specific attribute information from the server.
GopherGetLocatorType()Parses a Gopher locator and determines its attributes.
GopherOpenFile()Begins reading a Gopher data file from a Gopher server.

HyperText Transfer Protocol (HTTP)

When you access data on the World Wide Web, you'll notice that the address you use to access a Web site looks something like this:


http://www.microsoft.com

This is the main Web site for Microsoft Corporation, and this address is known as a Universal Resource Locator (URL). The first part of the URL describes the type of resource being accessed, and the second part is the actual Internet address for the resource. In the previous example, the first part of the URL is http, which (of course) specifies the HyperText Transfer Protocol. As you might already know, the hypertext format used for HTTP is a scripting format called HyperText Markup Language (HTML). Web documents are created using HTML and are transferred by HTTP.

WinInet HTTP Functions

The WinInet HTTP functions for the Web control the transmission and content of HTTP requests. Table 17.4 describes the WinInet HTTP Web functions.

Table 17.4. WinInet HTTP Web functions.

FunctionDescription
HttpAddRequestHeaders()Adds one or more HTTP request headers to the HTTP request handle.
HttpOpenRequest()Opens an HTTP request handle.
HttpQueryInfo()Queries for information about an HTTP request.
HttpSendRequest()Sends the specified request to the HTTP server.

Sample Program: RAWHTML.EXE

Now that you've seen the WinInet functions, turn your attention to a sample program that demonstrates the basic usage of the WININET.DLL for HTTP data transfer. This simple sample shows how you can use this powerful library of functions to create Internet-enabled applications for Win32.

NOTE
RAWHTML.EXE, along with all of its source files, can be found in the SOURCE\CHAP17\RAWHTML folder on this book's companion CD-ROM

The RAWHTML program simply takes a URL input by a user and requests HTML data from the URL-specified server. The data returned via the WinInet functions then is displayed as raw HTML in a multiple-line edit control. Figure 17.1 shows the RAWHTML program in action.

Figure 17.1 : The RAWHTML program displaying a raw HTML source script.

RAWHTML is a dialog-based application that contains three classes: CRawHtmlApp, CRawHtmlDlg, and CAboutDlg. The CRawHtmlDlg class contains the meat of the application's functionality, while the CRawHtmlApp class contains only the minimum necessary code to get the application running. CAboutDlg is simply a trivial About box class.

The CRawHtmlApp Class

The CRawHtmlApp application class interface declares only two methods, and the implementation is basic at best. The application class is declared in the file RAWHTML.H, and it looks like this:


///////////////////////////////////////////////////////////////////

// CRawHtmlApp - Application class



class CRawHtmlApp : public CWinApp

{

public:

   CRawHtmlApp();



protected:

   virtual BOOL InitInstance();

};

The implementation for this class is found in the file RAWHTML.CPP, and it's only slightly more complex than the declaration, as you can see in Listing 17.2. By now, code such as this should be second nature and self-explanatory to you.


Listing 17.2. The CRawHtmlApp class implementation in the file RAWHTML.CPP.

///////////////////////////////////////////////////////////////////

// Module  : RAWHTML.CPP

//

// Purpose : The application class for the RAWHTML program.

///////////////////////////////////////////////////////////////////



#include "stdafx.h"

#include "RawHtml.h"

#include "HtmlDlg.h"



///////////////////////////////////////////////////////////////////

// CRawHtmlApp construction



CRawHtmlApp::CRawHtmlApp()

{

}



///////////////////////////////////////////////////////////////////

// CRawHtmlApp initialization



BOOL CRawHtmlApp::InitInstance()

{

   // Allocate and display main dialog window

   CRawHtmlDlg dlg;

   m_pMainWnd = &dlg;

   dlg.DoModal();



   // Return FALSE so that we exit the application

   return FALSE;

}



///////////////////////////////////////////////////////////////////

// The CRawHtmlApp object



CRawHtmlApp MyApp;



///////////////////////////////////////////////////////////////////


The real point of interest for this application is the dialog class that performs the Internet data transfer via HTTP. Let's have a look.

The CRawHtmlDlg Dialog Class Header (HTMLDLG.H)

The CRawHtmlDlg dialog class header declares four controls as data members, along with several methods. The complete class declaration is given in Listing 17.3.


Listing 17.3. The CRawHtmlDlg dialog class header: HTMLDLG.H.

///////////////////////////////////////////////////////////////////

// Module  : HTMLDLG.H

//

// Purpose : The main dialog box interface for the RAWHTML program.



//////////////////////////////////////////////////////////////////

// CRawHtmlDlg dialog



class CRawHtmlDlg : public CDialog

{

public:

   CRawHtmlDlg(CWnd* pParent = NULL);   // standard constructor



   // Dialog Data

   enum { IDD = IDD_RAWHTML_DIALOG };



   CButton   m_btnClose;

   CButton   m_btnGo;

   CEdit      m_editUrl;

   CEdit    m_editHtml;



protected:

   // DDX/DDV support

   virtual void DoDataExchange(CDataExchange* pDX);



protected:

   HICON    m_hIcon;

   CString  m_strServer;

   CString  m_strPath;



   void ParseURL(CString& strUrl);

   void DisplayRawHtml(char* lpszBuffer);



   // Message map methods

   virtual BOOL OnInitDialog();

   afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

   afx_msg void OnBtnGoClicked();



   DECLARE_MESSAGE_MAP()

};



//////////////////////////////////////////////////////////////////


The CRawHtmlDlg Dialog Class Implementation (HTMLDLG.CPP)

The file HTMLDLG.CPP provides the implementation of the CRawHtmlDlg class, and most of the code should look familiar to you because similar code has been used in several other sample applications elsewhere in this book. The complete HTMLDLG.CPP code is given in Listing 17.4.


Listing 17.4. The CRawHtmlDlg class implementation.

///////////////////////////////////////////////////////////////////

// Module  : HTMLDLG.CPP

//

// Purpose : The main dialog class for the RAWHTML program.

///////////////////////////////////////////////////////////////////



#include "stdafx.h"

#include "RawHtml.h"

#include "HtmlDlg.h"



///////////////////////////////////////////////////////////////////

// CAboutDlg dialog used for App About



class CAboutDlg : public CDialog

{

public:

   CAboutDlg();

   enum { IDD = IDD_ABOUTBOX };



protected:

   // DDX/DDV support

   virtual void DoDataExchange(CDataExchange* pDX);

};



CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

}



void CAboutDlg::DoDataExchange(CDataExchange* pDX)

   { CDialog::DoDataExchange(pDX); }



///////////////////////////////////////////////////////////////////

// CRawHtmlDlg::CRawHtmlDlg() - Constructor



CRawHtmlDlg::CRawHtmlDlg(CWnd* pParent)

   : CDialog(CRawHtmlDlg::IDD, pParent)

{

   m_strServer = "";

   m_strPath   = "";



   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}



void CRawHtmlDlg::DoDataExchange(CDataExchange* pDX)

{

   CDialog::DoDataExchange(pDX);



   DDX_Control(pDX, IDCANCEL, m_btnClose);

   DDX_Control(pDX, IDOK, m_btnGo);

   DDX_Control(pDX, IDC_EDIT_URL, m_editUrl);

   DDX_Control(pDX, IDC_EDIT_HTML, m_editHtml);

}



///////////////////////////////////////////////////////////////////

// CRawHtmlDlg Message map



BEGIN_MESSAGE_MAP(CRawHtmlDlg, CDialog)

   ON_WM_SYSCOMMAND()

   ON_BN_CLICKED(IDOK, OnBtnGoClicked)

END_MESSAGE_MAP()



///////////////////////////////////////////////////////////////////

// CRawHtmlDlg::OnInitDialog()



BOOL CRawHtmlDlg::OnInitDialog()

{

   CDialog::OnInitDialog();



   //

   // Add "About..." menu item to system menu. IDM_ABOUTBOX must

   // be in the system command range...

   //



   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

   ASSERT(IDM_ABOUTBOX < 0xF000);



   CMenu* pSysMenu = GetSystemMenu(FALSE);

   CString strAboutMenu;

   strAboutMenu.LoadString(IDS_ABOUTBOX);

   if (!strAboutMenu.IsEmpty())

   {

      pSysMenu->AppendMenu(MF_SEPARATOR);

      pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

   }



   // Set the icon for the dialog

   SetIcon(m_hIcon, FALSE);      // Set small icon

   SetIcon(m_hIcon, TRUE);       // Set big icon



// Set the default URL

   m_editUrl.SetWindowText(

      "http://www.microsoft.com/msdownload/activex.htm");

   m_editUrl.SetFocus();



   return FALSE;  // m_editUrl has the focus!

}



//////////////////////////////////////////////////////////////////

// CRawHtmlDlg::OnSysCommand()



void CRawHtmlDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

   if ((nID & 0xFFF0) == IDM_ABOUTBOX)

   {

      CAboutDlg dlgAbout;

      dlgAbout.DoModal();

   }

   else

   {

      CDialog::OnSysCommand(nID, lParam);

   }

}



//////////////////////////////////////////////////////////////////

// CRawHtmlDlg::OnBtnGoClicked()



void CRawHtmlDlg::OnBtnGoClicked()

{

   // Get the current URL

   CString strUrl;

   m_editUrl.GetWindowText(strUrl);



   // See if the URL looks valid

   if (strUrl.IsEmpty() || strUrl.Left(7) != "http://")

   {

      ::MessageBeep(MB_ICONASTERISK);

      AfxMessageBox("Sorry, http address required...",

         MB_OK | MB_ICONINFORMATION);

      return;

   }



   // Parse the URL to get server name and file path (if any)

   ParseURL(strUrl);



   // Initialize the Internet DLL

   HINTERNET hSession = ::InternetOpen("Raw HTML Reader",

      PRE_CONFIG_INTERNET_ACCESS, "",

      INTERNET_INVALID_PORT_NUMBER, 0);



   // See if the session handle is valid

   if (hSession == NULL)

   {

      ::MessageBeep(MB_ICONEXCLAMATION);

      AfxMessageBox("Internet session initialization failed!",

         MB_OK | MB_ICONEXCLAMATION);

      return;

   }



   // Initialize HTTP session

   HINTERNET hConnect = ::InternetConnect(hSession, m_strServer,

      INTERNET_INVALID_PORT_NUMBER, "", "",

      INTERNET_SERVICE_HTTP, 0, 0);



   // See if connection handle is valid

   if (hConnect == NULL)

   {

      ::MessageBeep(MB_ICONEXCLAMATION);

      AfxMessageBox("Internet connection failed!",

         MB_OK | MB_ICONEXCLAMATION);



      // Close session handle

      VERIFY(::InternetCloseHandle(hSession));

      return;

   }



   // Open an HTTP request handle

   HINTERNET hHttpFile = ::HttpOpenRequest(hConnect, "GET",

      m_strPath, HTTP_VERSION, NULL, 0,

      INTERNET_FLAG_DONT_CACHE, 0);



   // See if HTTP request handle is valid

   if (hHttpFile == NULL)

   {

      ::MessageBeep(MB_ICONEXCLAMATION);

      AfxMessageBox("HTTP request failed!",

         MB_OK | MB_ICONEXCLAMATION);



      // Close session handles

      VERIFY(::InternetCloseHandle(hConnect));

      VERIFY(::InternetCloseHandle(hSession));

      return;

   }



   // Disable the user interface sending & processing request

   m_editUrl.EnableWindow(FALSE);

   m_btnGo.EnableWindow(FALSE);

   m_btnClose.EnableWindow(FALSE);



   // Display wait cursor

   CWaitCursor wait;



   // Send the request

   BOOL bSendRequest = ::HttpSendRequest(hHttpFile, NULL, 0, 0, 0);



   if (bSendRequest)

   {

      // Get the size of the requested file

      char achQueryBuf[16];

      DWORD dwFileSize;

      DWORD dwQueryBufLen = sizeof(achQueryBuf);



      BOOL bQuery = ::HttpQueryInfo(hHttpFile,

         HTTP_QUERY_CONTENT_LENGTH, achQueryBuf,

         &dwQueryBufLen, NULL);



      if (bQuery)

      {

         // The query succeeded, specify memory needed for file

         dwFileSize = (DWORD)atol(achQueryBuf);

      }

      else

      {

         // The query failed, so guess at a max file size

         dwFileSize = 10 * 1024;

      }



      // Allocate a buffer for the file data

      char* lpszBuf = new char[dwFileSize + 1];



      // Read the file

      DWORD dwBytesRead;

      BOOL bRead = ::InternetReadFile(hHttpFile, lpszBuf,

         dwFileSize + 1, &dwBytesRead);



      // Display the raw HTML

      DisplayRawHtml(lpszBuf);



      // Clean up buffer

      delete lpszBuf;



      // Close all open Internet handles

      VERIFY(::InternetCloseHandle(hHttpFile));

      VERIFY(::InternetCloseHandle(hConnect));

      VERIFY(::InternetCloseHandle(hSession));

   }



   // Enable the user interface

   m_btnGo.EnableWindow(TRUE);

   m_btnClose.EnableWindow(TRUE);

   m_editUrl.EnableWindow(TRUE);

}



//////////////////////////////////////////////////////////////////

// CRawHtmlDlg::ParseURL()

// Parses the URL to get the server and file names (if any)



void CRawHtmlDlg::ParseURL(CString& strUrl)

{

   if (strUrl.IsEmpty())

      return;



   // Strip off "http://"

   CString strTemp = strUrl.Mid(7) ;



   // Check for a path after the host name

   int nSlash = strTemp.Find("/");



   if (nSlash != -1)  // There's a path specified, so grab it

   {

      m_strServer = strTemp.Left(nSlash);

      m_strPath   = strTemp.Mid(nSlash);

   }

   else

      m_strServer = strTemp;

}



//////////////////////////////////////////////////////////////////

// CRawHtmlDlg::DisplayRawHtml()



void CRawHtmlDlg::DisplayRawHtml(char* lpszBuffer)

{

   m_editHtml.SetWindowText((LPCTSTR)lpszBuffer);

}



//////////////////////////////////////////////////////////////////


In the RAWHTML program, the actual Internet-specific code is located in the CRawHtmlDlg::OnBtnGoClicked() method, and the first order of business is initializing the Win32 Internet DLL.

Initializing a WinInet Session

To give an application Internet access via the WININET.DLL, for any of the supported protocols, you must first initialize the DLL by calling the InternetOpen() function. This causes the DLL to initialize internal data structures and prepare for future calls from the application. If the function call succeeds, it returns a valid HINTERNET that's used in subsequent function calls. The function has the following prototype:


HINTERNET InternetOpen(

   IN LPCTSTR  lpszAgent,

   IN DWORD    dwAccessType,

   IN LPCTSTR  lpszProxyName OPTIONAL,

   IN LPCSTR   lpszProxyBypass OPTIONAL,

   IN DWORD    dwFlags

);

The parameters used by this function are as follows:

Table 17.5. Flags used for the InternetOpen() dwFlags parameter.

ValueMeaning
INTERNET_FLAG_OFFLINESatisfy download operations on this handle through the persistent cache only. If the item does not exist in the cache, the function returns an appropriate error code.
INTERNET_FLAG_ASYNCFuture operations on this handle might fail with ERROR_IO_PENDING. A status callback will be made with INTERNET_STATUS_REQUEST_COMPLETE. This callback will be on a thread other than the one for the original request. A status callback routine must be registered or the functions will be completed synchronously.

Table 17.6. Internet access-type values used by InternetOpen().

ValueMeaning
INTERNET_OPEN_TYPE_DIRECTResolve all host names locally.
INTERNET_OPEN_TYPE_PROXYPass requests to the proxy unless a proxy bypass list is supplied and the name to be resolved bypasses the proxy. In this case, the function proceeds as for INTERNET_OPEN_TYPE_DIRECT.
INTERNET_OPEN_TYPE_PRECONFIGThe proxy or direct configuration is retrieved from the registry.

In the RAWHTML program, you initialize the WININET.DLL by calling InternetOpen() as follows:


// Initialize the Internet DLL

HINTERNET hSession = ::InternetOpen("Raw HTML Reader",

   PRE_CONFIG_INTERNET_ACCESS, "",

   INTERNET_INVALID_PORT_NUMBER, 0);

NOTE
When your Internet session is over, be sure to call the InternetCloseHandle() function with the handle returned from InternetOpen() as a parameter. This ensures that any resources allocated by InternetOpen() are freed

Getting a Protocol Handle

When the Internet DLL is initialized and ready for action, you can call other WinInet functions. To get connected to an Internet server, RAWHTML initializes an HTTP session by using the following code:


// Initialize HTTP session

HINTERNET hConnect = ::InternetConnect(hSession, m_strServer,

   INTERNET_INVALID_PORT_NUMBER, "", "",

   INTERNET_SERVICE_HTTP, 0, 0);

The second parameter, m_strServer, is a class data member that represents the name of the server you want to contact to get data. In this case, the server is www.microsoft.com, as specified in the CRawHtmlDlg::OnInitDialog() method by the following code:


// Set the default URL

m_editUrl.SetWindowText(

   "http://www.microsoft.com/msdownload/activex.htm");

The default URL is parsed into server and path components with the simple CRawHtmlDlg::ParseURL() method (refer to Listing 17.4).

The InternetConnect() function takes the HINTERNET returned from the previous call to InternetOpen() as its first parameter. The InternetConnect() function uses the following prototype:


HINTERNET InternetConnect(

   IN HINTERNET hInternetSession,

   IN LPCTSTR   lpszServerName,

   IN INTERNET_ PORT nServerPort,

   IN LPCTSTR   lpszUsername OPTIONAL,

   IN LPCTSTR   lpszPassword OPTIONAL,

   IN DWORD     dwService,

   IN DWORD     dwFlags,

   IN DWORD     dwContext

);

The parameters used for this function are as follows: :

Table 17.7. The values predefined for the nServerPort parameter.

ValueDescription
INTERNET_INVALID_PORT_NUMBERThe function uses the default port for the specified service.
INTERNET_DEFAULT_FTP_PORTUse the default port for FTP servers (port 21).
INTERNET_DEFAULT_GOPHER_PORTUse the default port for Gopher servers (port 70).
INTERNET_DEFAULT_HTTP_PORTUse the default port for HTTP servers (port 80).
INTERNET_DEFAULT_HTTPS_PORTUse the default port for HTTPS servers (port 443).

The InternetConnect() function is required before communicating with any Internet service, and RAWHTML calls the function like this in the OnBtnGoClick() method:


// Initialize HTTP session

HINTERNET hConnect = ::InternetConnect(hSession, m_strServer,

   INTERNET_INVALID_PORT_NUMBER, "", "",

   INTERNET_SERVICE_HTTP, 0, 0);

Opening the Desired File

After a connection to the Internet server is established, you can call the HttpOpenRequest() and HttpSendRequest() functions. These functions work together to open a file-in this case, the file stored in the m_strPath class data member.

The HttpOpenRequest() Function

The HttpOpenRequest() function sends the request parameters to the Internet service and returns a request handle. The prototype for this function is as follows:


HINTERNET HttpOpenRequest(

    IN HINTERNET hHttpSession,

    IN LPCTSTR lpszVerb,

    IN LPCTSTR lpszObjectName,

    IN LPCTSTR lpszVersion,

    IN LPCTSTR lpszReferer OPTIONAL,

    IN LPCTSTR FAR * lpszAcceptTypes OPTIONAL,

    IN DWORD dwFlags,

    IN DWORD dwContext

);

The parameters for this function are as follows:

Table 17.8. The Internet flag values used for the dwFlags parameter.

Value Meaning
INTERNET_FLAG_RELOAD Get the data from the wire even if it is locally cached.
INTERNET_FLAG_DONT_CACHE Do not cache the data, either locally or in any gateways.
INTERNET_FLAG_RAW_DATA Return raw data (WIN32_FIND_DATA structures for FTP, and GOPHER_FIND_DATA structures for Gopher).
INTERNET_FLAG_SECURE Request secure transactions on the wire with Secure Sockets Layer or PCT. This flag applies to HTTP requests only.
INTERNET_FLAG_EXISTING_CONNECT If possible, reuse the existing connections to the server for new requests instead of creating a new session for each request.

The RAWHTML program calls the HttpOpenRequest() function as follows:


// Open an HTTP request handle

HINTERNET hHttpFile = ::HttpOpenRequest(hConnect, "GET",

   m_strPath, HTTP_VERSION, NULL, 0,

   INTERNET_FLAG_DONT_CACHE, 0);

The HttpSendRequest() Function

The HttpSendRequest() function sends the request parameters to the Internet service and returns a request handle. The prototype for this function is as follows:


BOOL HttpSendRequest(

   IN HINTERNET hHttpRequest,

   IN LPCTSTR   lpszHeaders OPTIONAL,

   IN DWORD     dwHeadersLength,

   IN LPVOID    lpOptional OPTIONAL,

   DWORD        dwOptionalLength

);

Here are the parameters for this function:

The RAWHTML program calls the HttpSendRequest() function using all default values, as follows:


BOOL bSendRequest = ::HttpSendRequest(hHttpFile, NULL, 0, 0, 0);

Querying for Information

To get the size, in bytes, of the file you want to read, call the HttpQueryInfo() function (with a HTTP_QUERY_CONTENT_LENGTH flag to specify that you're looking for the file size). The prototype for this function is as follows:


BOOL HttpQueryInfo(

   IN HINTERNET hHttpRequest,

   IN DWORD dwInfoLevel,

   IN LPVOID lpvBuffer OPTIONAL,

   IN LPWORD lpvBufferLength,

   IN OUT LPWORD lpdwIndex OPTIONAL,

);

Here are the parameters for the function:

Table 17.9. Possible query flags for the dwInfoLevel parameter.

FlagMeaning
HTTP_QUERY_CUSTOMIf this query level is specified, lpvBuffer contains an ASCIIZ header name. This header name is searched for and its value is returned in lpvBuffer on output.
HTTP_QUERY_FLAG_COALESCECombine the values from several headers of the same name into the output buffer.
HTTP_QUERY_FLAG_REQUEST_HEADERS Typically, response headers are queried, but an application can also query request headers by using this flag.
HTTP_QUERY_FLAG_SYSTEMTIMEFor those headers whose value is a date/time string, such as "Last-Modified-Time", specifying this flag returns the header-value as a standard Win32 SYSTEMTIME structure, which does not require the application to parse the data.
HTTP_QUERY_FLAG_NUMBERFor headers whose value is a number, such as the status code, specifying this flag returns the data as a 32-bit number.

The RAWHTML program calls the HttpQueryInfo() function like this:


BOOL bQuery = ::HttpQueryInfo(hHttpFile,

   HTTP_QUERY_CONTENT_LENGTH, achQueryBuf,

   &dwQueryBufLen, NULL);

Reading the File Data

To actually read the file, now that you've made it this far, you must call the InternetReadFile() function, which has the following prototype:


BOOL InternetReadFile(

   IN HINTERNET  hFile,

   IN LPVOID     lpBuffer,

   IN DWORD      dwNumberOfBytesToRead,

   OUT LPDWORD   lpNumberOfBytesRead

);

The parameters for this function are as follows: :

The RAWHTML program uses the following code to read the file data:


// Allocate a buffer for the file data

char* lpszBuf = new char[dwFileSize + 1];



// Read the file

DWORD dwBytesRead;

BOOL bRead = ::InternetReadFile(hHttpFile, lpszBuf,

   dwFileSize + 1, &dwBytesRead);

The code is displayed in the m_editHtml edit control with a simple call to SetWindowText(), as follows:


m_editHtml.SetWindowText((LPCTSTR)lpszBuffer);

NOTE
To keep the code short and as simple as possible, error checking for this sample program is minimal. In a real-world application, you would certainly want to provide much better error trapping

Summary

The Win32 Internet functions bring the tools needed to create professional quality Internet access applications well within the reach of most Windows programmers. By providing an insulating layer over the underlying WinSock API, the WinInet API makes Internet programming much easier than ever before!

Here are some points to remember: