by Rob McGregor
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.
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 |
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.
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.
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.
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.
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 |
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.
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!)
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.
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.
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.
Function | Description |
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. |
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 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.
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.
Function | Description |
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 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 |
The Gopher functions provide a standard interface to the Gopher
specification. Table 17.3 lists the WinInet Gopher functions.
Function | Description |
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. |
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.
The WinInet HTTP functions for the Web control the transmission
and content of HTTP requests. Table 17.4 describes the WinInet
HTTP Web functions.
Function | Description |
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. |
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 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 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 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.
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:
Value | Meaning |
INTERNET_FLAG_OFFLINE | Satisfy 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_ASYNC | Future 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. |
Value | Meaning |
INTERNET_OPEN_TYPE_DIRECT | Resolve all host names locally. |
INTERNET_OPEN_TYPE_PROXY | Pass 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_PRECONFIG | The 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 |
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: :
Value | Description |
INTERNET_INVALID_PORT_NUMBER | The function uses the default port for the specified service. |
INTERNET_DEFAULT_FTP_PORT | Use the default port for FTP servers (port 21). |
INTERNET_DEFAULT_GOPHER_PORT | Use the default port for Gopher servers (port 70). |
INTERNET_DEFAULT_HTTP_PORT | Use the default port for HTTP servers (port 80). |
INTERNET_DEFAULT_HTTPS_PORT | Use 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);
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 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:
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 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);
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:
Flag | Meaning |
HTTP_QUERY_CUSTOM | If 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_COALESCE | Combine 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_SYSTEMTIME | For 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_NUMBER | For 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);
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 |
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: