Introduction
Chapter 13
Learning to Use
the Win32 Internet API Library
Introduction
The Win32 Internet API is designed to handle the
client side of the Internet connection. A familiar application that uses client-side
technology is your browser. Unlike the ISAPI Server API, the Internet API (also know as
WinInet) can be used in any normal application. The executable file does not have to be
placed in a special directory with special permissions. In this chapter, you will learn
the general functionality offered by this WinInet API and learn how to use the Microsoft
programming classes to use this WinInet API.
Overview
Using the Internet requires a connection from a
client (your browser, for example) to a server. The API supports a connection that can be
a request to a server that understands HTTP, FTP, or Gopher. While there are other kinds
of Internet connections, these three are currently the most widely used. Each kind of
connection has a different but similar use.
What is the File
Transfer Protocol (FTP)?
FTP is a File Transfer Protocol. It allows servers
to make files available to clients, and it lets the client give the server files. It
transfers files from one computer to another, regardless of the operating system on either
machine. This was important because operating systems that didn't know how to talk to each
other could use the FTP service to place or get files to each other. For example, a
student in Texas using a Macintosh computer could retrieve or put files on a UNIX machine
in California. FTP files are generally laid out in a tree structure, just like a directory
system. This allows the client to place or retrieve files from the appropriate location.
In the Windows NT and Windows 95 operating systems,
FTP commands are supported at the command prompt. The Microsoft Internet Explorer
(Microsoft's browser) support for FTP is built in the address box. It can be accessed by
typing FTP://ftp.server-name.
Figure 13.1how Microsoft
Internet Explorer displays an FTP site.
Figure 13.1 is an example of an FTP site. Notice the
name and explanation of the site. They appear to use HTML, but in fact it is Internet
Explorer doing the formatting. Look at how the files list the date and time of last
modification as well as the file size. The directories are also listed. When using FTP,
you have to know what file you are looking for and where to find it. There is no searching
capability.
The Gopher Protocol
Compared to FTP, Gopher offers a little more to the
client but also requires more of the server. FTP does not have any ability to jump from
one server to another, but Gopher and HTTP do have the ability to jump to other servers
using links. Gopher also offers the ability to annotate files and directories, and create
custom menus. However, it does not allow the client to place files on the server.
Gopher servers have a tag file. This tag file keeps
the name of the file the directory system uses: a "friendly" name that would be
useful to the client (the administrator's name, modification date, and type of file, such
as a text file or binary executable file). An example of a friendly name would be
The 1996 Acme Stock Report, where the file name is actually
1996stpt.txt. The client doesn't see the tag file, but information in the tag
file can be sent back to the client along with the file itself. The tag file has to be
constructed by an administrator of the Gopher site. The Microsoft Internet Information
Server uses the command line application GDSSET.EXE to make tag files for the Gopher
server it supports. A tag file would have to be built for each file retrievable by Gopher.
Gopher allows searches through the Wide Area
Information Search (WAIS) index searching. WAIS is a full-text information retrieval
system. In order for the file to be searchable, the server administrator has to create a
WAIS index.
The Microsoft Internet Explorer's (Microsoft's
browser) support for Gopher is built in the address box. It can be access by typing
Gopher://gopher.server-name.
Figure 13.2. This is how
Microsoft Internet Explorer displays a Gopher site.
Figure 13.2 is an example of a Gopher site. Notice
the name and explanation of the site. This page appears to use HTML, but in fact it is
Internet Explorer doing the formatting. This site offers directories and searches to
clients. The Gopher server differentiates between files, directories, and searches. This
particular Gopher site doesn't have any files at the root directory, but it does have
several directories and searches.
Figure 13.3. This is how a
Gopher site searches an index, as presented through Microsoft Internet Explorer.
Figure 13.4. This is a
Gopher site's search results, based on the search from Figure 13.3. The search results let
the client know where to go in the Gopher file system to find the file.
The Gopher search capabilities are not as advanced
as some of the searches that are now available through HTTP/HTML, but the Gopher
search was a good resource in its time.
HTTP and HTML
Both FTP and Gopher offer useful services, but they
lack of few qualities. Both are basically file systems with only files and searches to
offer. To see the information, the client must download the file to his computer and open
it with the correct application. HTTP and HTML offer the client the information without
having to open the file. Actually, the concept choosing files is replaced with the concept
of moving to other pages. At this point in the guide, you should know how to move between
pages in your browser.
HTTP servers offer much more to a client. While FTP
and Gopher are file server systems, HTTP can be a complete server system. It can offer
unlimited capabilities such as database access, true search engines, and calculations. The
list is only limited by your imagination. The HTTP server does its work and then sends the
client's browser a file to display the result of whatever work it was requested to do.
The HTTP servers work is far more versatile
than FTP and Gopher because it can act on the request. An example (one of many) is
the request for information, such as the Yellow Pages on the Web. The request goes from
your browser to the server. The server can filter the request for valid data or passwords.
If the request is invalid, the server returns an HTML page notifying you. If the request
is valid, the server can look through a file server, look through an email server, look
through a database, or do just about anything else.
FTP and Gopher in the
Future
The services offered by FTP and Gopher are quickly
being replaced by Web pages served up by HTTP and written in HTML. If you search for
Gopher or FTP pages, you are probably using a search engine behind an HTML form. Why would
someone keep these servers around? Converting an existing (and probably extensive) server
to HTML is not hard, but there are several costs involved. These costs can involve
hardware, software, labor, training, and administration of the new system. Many of these
systems reside in governments or schools, and the resources to update the systems are not
available.
HTML doesn't solve every problem either. The ability
for a client to place a file on a server (as FTP can do) is not allowed. The Microsoft
Internet Information Server comes with all three services.
How Does the WinInet API
Fit In?
The WinInet API is designed to allow applications
access to Internet (or intranet) information, without requiring detailed knowledge of how
the connection works (such as TCP/IP or sockets). The API makes reading a file from the
Internet as easy as reading a file from your hard drive. If you are familiar with other
Win32 APIs then the buffer and error handling of this API should look familiar. If you
want to have all the detailed information of the WinInet specification, you can find the
document at http://www.microsoft.com/intdev/sdk/docs/wininet/.
The difficulty with Internet technology is that it
changes very quickly. Who wants to learn a set of functions that will soon be obsolete?
The WinInet API is written to flexibly change the underlying technology and yet have a
consistent set of functions for programmers to use.
Microsoft has written a set of classes that
incorporate the WinInet API functionality into the Microsoft Foundation Class (MFC)
classes. The benefit of these classes is that they fit nicely into the MFC hierarchy of
classes, thereby giving the programmer more functionality than just what the WinInet API
functions can afford. If you are familiar with MFC, learning these new classes will be a
snap. In order to use these classes, you have to use the Microsoft Visual C++ version 4.2.
Prior versions of Visual C++ will not have these classes.
The API Functions
Before looking at the MFC classes, let's first take
a look at the functions in the WinInet API. The main functions a client should be
concerned with are connecting to the server, having the server do something, and closing
the connection to the server.
Please check to see if the hardware and software in
your operating system are correctly configured before you begin programming with this API.
Connecting to a Web site with your browser would be a good test of whether your machine's
hardware and software are working correctly. This API takes advantage of the software you
already have installed on your system. So instead of having to install the protocols and
software to use this API, the API assumes that you already have connectivity with these
three protocols.
While there are only three technologies supported by
the API, there are several functions that you need to accomplish regardless of which
protocol you use. The general functions are:
- InternetOpenis the first function you will need
to call. It initializes the WinInet API. Without this function call, the results could be
unpredictable.
- InternetOpenUrlmakes a connection to the server
and prepares for the information to be retrieved.
- InternetCrackUrlparses a URL string into
components such as server name, path in server, user name, password, and any parameters.
- InternetCreateUrlcreates a URL string from
components such as server name, path in server, user name, password, and any parameters.
- InternetCanonicalizeUrlconverts a URL string
into a safe form. This safe form can include replacing invalid characters,
converting characters to other characters, and encoding.
- InternetCombineUrlcombines the base and path of
a URL into a single string which will be made safe by canonicalizing the URL.
- InternetConnectbegins a session for any
protocol to make a connection. The session information can include server name, user name,
password, connection protocol (HTTP, FTP, Gopher). You do not need to open a session for
each request. A single session can handle all your requests. You need to balance the
session per request for your particular use.
- InternetQueryOptionreturns information about
your internet session such as user name, password, time out features, asynchronous
features, callback features, and other security features.
- InternetSetOptionsets information about your
internet session such as user name, password, time out features, asynchronous features,
callback features, and other security features.
- InternetErrorDlgdisplays message box for error
occurring from the HttpSendRequest error conditions. The dialog displays the error message
and gives the button options of OK, CANCEL or RETRY.
- InternetCloseHandleis used to terminate an
Internet handle and free any associated resources. If the handle is a parent of other
handles, this function can be used to close all the child handles of the parent. This
function closes the handle opened by InternetOpen.
- InternetReadFilereads a buffer of data.
InternetOpenUrl, FtpOpenFile, GopherOpenFile, and HttpOpenRequest will create the buffer.
Make sure your buffer size if large enough for requested information. If the requested
information is not available (i.e. this function is waiting on the server), the function
will not return until the information is available.
- InternetSetFilePointer moves the position of
the file pointer by a number of bytes. You can move the position relative to the file
pointers current position, the beginning of the file, or the end of the file.
- InternetWriteFilewrites a number of bytes to a
file and returns the number of bytes written. It is useful to know how many bytes were
actually written to a file if (for some reason), the function could not write all the
bytes.
- InternetFindNextFilefinds the next file where
the first file was found with either FtpFindFirstFile or GopherFindFirstFile.
- InternetSetStatusCallbacksets the function
address to call when there is status information. This function address is of a function
you write. This function would do something meaning with the status information, such as
let the user know what the status is.
- InternetConfirmZoneCrossinglets the user know
if he is moving from a secured web page to an unsecured web page.
- InternetTimeFromSystemTimeformats the date and
time from a specified HTTP format (as noted in the HTTP specification) to a string.
- InternetTimeToSystemTimeformats a string into a
specified HTTP format (as noted in the HTTP specification).
- InternetAttemptConnectlets the client attempt
to connect to the server before a file request is attempted. The request of connecting is
shorter than connecting and requesting a file.
Note
So what does URL stand for? URL stands for universal resource locator.
In terms of the Internet, that would be the server name, such as www.microsoft.com.
Note
SYSTEMTIME is a data structure that contains the following information: year, month, day
of week (where Sunday is 0), day of month, hour, minute, second, and millisecond.
To get to specific files or other information, you
will have to use the functions that coincide with your particular need. There are
functions specific to each of the three connections supported: HTTP, FTP, and Gopher.
The HTTP functions are
- HttpOpenRequestcreates a handle to an HTTP
server by setting the type of action (such as GET), the object of that action (file, ISAPI
filter, template, etc.), the object making the request (generally the web page), and the
type of data you can accept (such as text).
- HttpAddRequestHeadersadds or removes
information to the handle created by HttpOpenRequest. This information is in the form of
headers. In general, a web browser will send information about itself such as manufacturer
and version of product. Web servers can act on this information as well as log this
information.
- HttpSendRequestsends the request created in
HttpOpenRequest and HttpAddRequestHeaders to the server. This function also always you to
specify additional headers.
- HttpQueryInforeturns information about the sent
header (you created), returned header (server created) or the returned request (server
created). The last two pieces are probably more interesting. The header information is
important because it can tell you things like when was the file last modified, when the
file expires, what format type is the returned request, etc.
The FTP functions include the following:
- FtpFindFirstFilecan find either the first file
or the first directory on the FTP server starting at a specified path. You can only call
this function once per FTP session, any other calls will be a waste of your time. To find
more files or directories, you need to use the InternetFindNextFile function. The FTP
protocol can not guarantee correct file information such as create date and time, so it
returns the most accurate information based on available information.
- FtpGetFileretrieves a file from the FTP server
and puts it on your local system. You can control where the file goes, what the new file
name is, what the new file attributes are, and other conditions of the file transfer.
- FtpPutFilesends a file to the FTP server and
puts it in a specific directory that you choose. You must have appropriate permissions for
this function to succeed.
- FtpDeleteFiledeletes a file from the FTP
server. You must have appropriate permissions for this function to succeed.
- FtpRenameFilerenames a file on the FTP server.
You must have appropriate permissions for this function to succeed.
- FtpOpenFileopens a file on the FTP server for
reading or writing. You want to use this function if you need to control how the data is
sent to the server or read from the server. This function gives you a more granular
control over the process.
- FtpCreateDirectorycreates a directory on the
FTP server. You must have appropriate permissions to use this function.
- FtpRemoveDirectorydeletes a directory on the
FTP server. You must have appropriate permissions to use this function.
- FtpSetCurrentDirectorychanges the current
directory. You should find out where you are by using FtpGetCurrentDirectory.
- FtpGetCurrentDirectorygives you the name of the
current FTP server directory you are in.
The Gopher functions include the following:
- GopherFindFirstFile can find the first file
based on a Gopher locater, an indexed search, or the top level information in the Gopher
server. After the first call to GopherFindFirstFile, any other calls to find files should
use the InternetFindNextFile function.
- GopherOpenFilestarts reading a Gopher file.
- GopherCreateLocatorcreates a locator string.
Information necessary to create a locator string includes server name, friendly name of
file, and file name.
- GopherGetAttributereturns information about the
file on the Gopher server.
Notice that once you get the files enumerated, based
on your connection type, the rest of the enumeration is used with InternetFindNextFile.
Examples of function calls it would take to download
from an HTTP server include
- InternetOpen
- InternetConnect
- HTTPOpenRequest
- HTTPSendRequest
- InternetReadFile
- InternetCloseHandle
The MFC Classes and
WinInet
If a programmer wanted to write an application using
this API, a lot of programming would be required to handle non-WinInet aspects of the
application, such as the graphical user interface (GUI), any database connectivity, and
just about anything else the application needs to do. You could write a WinInet program
without MFC (or some other programming class library), but for rapid application
development (RAD), this is probably unrealistic. Knowledge of C++ class usage is mandatory
for using these classes.
The MFC classes that work with this functionality
are
- CInternetSessioncreates and initializes the
internet session you need, regardless of the protocol you are using.
- CInternetConnectionis the base class for all
three protocol connection types. This class manages the common functionality and low-level
details of the connection.
- CFtpConnectionis used to connect to an FTP
server. This class handles most of the directory and file tasks.
- CGopherConnectionis used to connect to a Gopher
server. This class handles the locator and attribute information.
- CHttpConnectionis used to connect to an HTTP
server. This class hanldes the intial request to the server.
- CInternetFileinherits from CStdioFile and is
the base class for CGopherFile and CHttpFile. This base class handles the file
manipulation for the Gopher and Http protocol.s
- CGopherFileis needed to handle Gopher files but
doesnt have very much functionality. Its only methods are the contructor and
Close().
- CHttpFileis needed to handle Http files. It
will send the request to the Http server, read the headers that the server sends back and
the html data stream that the server sends back.
- CFileFindis the base class for CGopherFindFile
and CFtpFindFile. It handles file searches and file information.
- CFtpFileFindfinds FTP files on an FTP server.
- CGopherFileFindfinds the Gopher files on the
Gopher server and returns information about information in the tag file.
- CGopherLocatorcreate the locator object to
access Gopher files.
- CInternetExceptionhandles Internet programming
exceptions.
Global functions for the WinInet in MFC include the
following:
- AfxParseURLtells you what kind of protocol
server, file, port and what type of protocol the URL will go to: HTTP, FTP or Gopher.
- AfxGetInternetHandleTypereturns the type of
HTTP, FTP or Gopher request handle you have such as finding a file versus connecting to a
server.
- AfxThrowInternetExceptionthrows a memory
exception, such as a call to memory allocation fails.
Programming with MFC
In order to follow the code snippets and exercises
in the rest of the chapter, you need to make sure that the Internet connectivity to HTTP
and FTP is working. You can use your browser to verify this. You also need to have
Microsoft Visual C++ version 4.2 or later installed. The help files and sample application
of Microsoft Visual C++ go into great detail about what these new classes do. Please see
these resources for additional information.
The First Example
Program
This first example program will connect to a HTTP
server and read the HTML file (default.asp). As it reads the file, the application will
print the information to a screen. This is not a sophisticated program, but you will
actually connect to a server and read a file. There are three types of operations you will
be doing. You will open a connection to the server, make a request of the server, and read
a file. As you go through this example, look for the differences between these three
pieces.
You will need to find a Web server that has a Web
page in the root directory to exchange for the names I use in this example. In the example
code, I chose a server I could get to at the time this chapter was written. The danger in
this is that the server might not be working now. Before you begin, you need to find a Web
server (any will do) that has the default.asp document. Some of the more advanced servers
don't have this file. As long as you know the name of a server and the name of a file in
the root directory of that server, you can exchange those names for the ones I use in the
code.
In order to start, let's create an application. Open
up Microsoft Visual C++, and make a new project workspace. Name the workspace HTTPexam.
Make sure the project is a console application. The reason it should be a console
application is because I don't want you to be confused by seeing any classes that are not
closely related to these WinInet classes. Because a console application doesn't use MFC by
default, you need to change the project so that it does use MFC. In your project, change
your project settings (Build Menu/Settings) to use MFC in a shared dll (General Tab/MFC
drop-down list). If you don't let the project know you need to use the MFC dll, when you
build, you will get linker errors regarding beginthread and endthread functions.
Note
A console application is a DOS-type application where there are no windows.
Create a header file httpex.h that looks like
Listing 13.1.
Listing 13.1. httpex.h (create a header file).
#include <afx.h> // header file for MFC
#include <afxinet.h> // header file for WinInet
#include <iostream.h> // header file for input/output stream
#include <stdlib.h> // header file for standard library functions
class CHttpExample : public CInternetSession
{
public:
CHttpExample(LPCTSTR pszAppName, int nMethod);
};
Create a code file httpex.cpp that looks like
Listing 13.2.
Listing 13.2. httpex.cpp (write bare
application).
#include "httpex.h" // header file for Project
// CHttpExample class implementation
void main()
{
// variables
// running code implementation
}
Make sure httpex.cpp has been added to the project
files, and update project dependencies. The CHttpExample class's only base class is
CInternetSession. The derived class you made (CHttpExample) only has one method. You don't
need anything more in your header file to make a connection and to retrieve information
from a server.
Now let's add the implementation code that is
associated with the function defined in the header file. Add Listing 13.3 to httpex.cpp
after the line //CHttpExample class implementation.
Listing 13.3. httpex.cpp (add class
implementation code).
CHttpExample::CHttpExample(LPCTSTR pszAppName, int nMethod)
: CInternetSession(pszAppName, 1, nMethod)
{
}
There is no code in the constructor for your
CHttpExample class because the base class does everything you need. All you have to do is
pass this information to it when you declare a variable of CHttpExample type.
At this point, the project should build with no
errors or warnings. If it does have errors or warnings, now is a good time to fix your
project settings and debug your code. However, the main function is still empty, so the
program will do nothing. Let's add some useful code to make the program do something.
You need to declare a few variables that you want to
work with. The first and most obvious is to instantiate your class by having a variable of
CHttpExample type. The second variable you need is for your connection type and will be of
type CHttpConnection. The third variable you need will help you read the file and will
need to be of type CHttpFile. You also need to add a few character strings to handle the
server name, filename, header information you send, header information you request, and
the text of the file in which you are interested. The last variables will hold the status
of functions you are executing. Add Listing 13.4 below the line with // variables on it.
Listing 13.4. httpex.cpp (declare variables).
CHttpExample session(_T("Http Example"), INTERNET_OPEN_TYPE_PRECONFIG);
CHttpConnection* pServer=NULL;
CHttpFile* pFile=NULL;
CString serverName(_T("dinaf2"));
CString fileName(_T("/default.asp"));
CString headerInfo(_T("Accept: text/*\r\nUser-Agent: HTTP Example\r\n"));
CString newLocation;
CString returnedFileText;
DWORD dwReturnCode;
BOOL fSuccess;
Tip
You may be asking what the _T("string") syntax does. By using the _T
macro, I can compile my code as Unicode, MultiByteCharacterSet, or ANSI (single-byte
character set) without having to change the way I have my hard-coded strings. The CString
class handles how the string is kept based on which type of string I am interested in. In
order to compile your code in a particular setting, make sure you have one of the
following if defined in your project settings: _UNICODE, _MBCS, or _SBCS. If you plan to
have your code used outside the English language, this is important.
The way you declared the session variable will pass
the information from the CHttpExample class to the CInternetSession class. A CString can
be either initialized when it is declared or later. Both methods are used here. The two
variables pServer and pFile will be initialized in the code. Also notice that the server
does not have to be prefixed with the http://. If you did prefix the name, a connection
would not be established.
The second parameter to the constructor for your
session variable is the type of Internet access you want. This has nothing to do with the
server you are trying to get to. This parameter tells the software how to configure our
machine's side of the connection. You have three choices here. I chose the one that will
work with my machine. If you are not running on a Windows NT or Windows 95 operating
system, you will have to choose the flag that is best for you. The three flags are
- INTERNET_OPEN_TYPE_PRECONFIGmeans the access
information is preconfigured in your operating system's registry. (This is a safe choice
for WinNT and Win95.)
- INTERNET_OPEN_TYPE_DIRECTmeans direct access to
the Internet.
- INTERNET_OPEN_TYPE_PROXYmeans access through a
proxy or gateway. For corporate situations, this might be what you need.
If you do not know what type of access you have, you
will need to contact your system administrator or Internet service provider (ISP).
Now let's write some code to get you connected. Add
Listing 13.5 to your main function just below the // running code implementation line.
Listing 13.5. httpex.cpp (add connection and
request code).
pServer = session.GetHttpConnection(serverName);
pFile = pServer->OpenRequest(CHttpConnection::
HTTP_VERB_GET,
fileName,NULL,1,NULL,NULL,INTERNET_
FLAG_EXISTING_CONNECT);
// connection to server
pFile->Close();
if(pFile)
delete pFile;
pServer->Close();
if(pServer)
delete pServer;
session.Close();
Let's look at each line of code. The first line of
code initializes your connection to the name of the HTTP server and returns a pointer to a
CHttpConnection object. But what if the server had some sort of security? The code didn't
pass a username or password, so a secured connection would fail. The function parameters
for GetHttpConnection are (serverName,portNumber,userName,password). But because I'm using
the default system registry, I don't need to set the port number. The function definition
defaults this to INTERNET_INVALID_PORT_NUMBER. The username and password also default to
NULL so if I don't need them, I don't need to pass them as parameters. If a connection to
the server could not be established, the pServer pointer would be null. It is a good idea
to check that the pointer is not null before continuing; however, I don't do that here.
Any a real-world program, you would want to check the pointer before proceeding. This will
save you from possible exceptions in your code.
The second line of code requests the file
default.asp from the server. The first parameter CHttpExample::HTTP_VERB_GET tells the
server what kind of request you are making of it. If you pass this parameter as NULL, the
HTTP_VERB_GET is used. The other choices correspond with normal requests that can be made
to a Web server:
- HTTP_VERB_POST = 0
- HTTP_VERB_GET = 1
- HTTP_VERB_HEAD = 2
- HTTP_VERB_PUT = 3
- HTTP_VERB_LINK = 4
- HTTP_VERB_DELETE = 5
- HTTP_VERB_UNLINK = 6
The object or filename you are interested in is the
second parameter. The rest of the parameters take default values, but to let you know what
they are I included them in the function call. The other parameters handle issues such as
what type of file you can accept (text-only is an example), what the URL address of the
object is (if the object is not in the Web's root directory), and how you want to handle
the file returned (don't cache, make it secure with encryption, and so on).
The last few lines of code close the connection to
the server and gracefully close down your CInternetSession object. You should be able to
build and run the code. The application at this point connects to the server, requests the
file, and then closes down. In order to look at the file, you need to add more code.
Insert Listing 13.6 just below the line //connection to server.
Listing 13.6. httpex.cpp (add file handling
code).
if(fSuccess = pFile->AddRequestHeaders(headerInfo))
{
if(fSuccess = pFile->SendRequest())
{
if(fSuccess = pFile->QueryInfoStatusCode(dwReturnCode))
{
if(dwReturnCode==200)
{
if(fSuccess = pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_
[cc:icc]CRLF,newLocation))
{
if(newLocation != _T(""))
cout << _T("Header Info: ") << newLocation
[cc:icc]<< endl << endl;
}
pFile->SetReadBufferSize(2000);
while(pFile->ReadString(returnedFileText))
cout << returnedFileText;
}
}
}
}
You have now written the entire application to read
an HTML file and write it to the screen. Let's look at the code from Listing 13.6 in
detail.
The first line adds information to the header you
send to the server. You would use this if you wanted control over the exact request sent
to the server. Our CString variable headerInfo tells the server you accept text
information, and it tells the server the name of the application making the request. If
the function fails, it returns a 0 into fSuccess. You need to check every function that
returns a success code before continuing.
The second line sends the request. The function is
empty because you have already set the filename and location. However, if you were
executing a CGI script or ISAPI filter on the server, this is the function you would pass
the information to. This information could include the name of the script and parameters
to that script.
The next line returns information on how well our
request was satisfied. This is important because if there was a problem, you would need to
find out why. The return code dwReturnCode will be a number representing that success or
failure. In the code, I only check for 200 (the request was fulfilled without any errors)
because that means my request was satisfied. The return codes are broken down in Table
13.1.
Table 13.1 Return codes.
Return Code |
Meaning |
200 |
Request completed. |
201 |
Object created, reason = new URI. |
202 |
Asynchronous completion. |
203 |
Partial completion. |
204 |
No information to return. |
300 |
Server couldn't decide what to return.
|
301 |
Object permanently moved. |
302 |
Object temporarily moved. |
303 |
Redirection w/ new access method. |
304 |
If-modified-since was not modified. |
400 |
Invalid syntax. |
401 |
Access denied. |
402 |
Payment required. |
403 |
Request forbidden. |
404 |
Object not found. |
405 |
Method is not allowed. |
406 |
No response acceptable to client
found. |
407 |
Proxy authentication required. |
408 |
Server timed out waiting for request. |
409 |
User should resubmit with more
information. |
410 |
The resource is no longer available. |
411 |
Couldn't authorize client. |
500 |
Internal server error. |
501 |
Required not supported. |
502 |
Error response received from gateway. |
503 |
Temporarily overloaded. |
504 |
Request timed out waiting for gateway
to respond. |
The next line of code in Listing 13.6 uses the
QueryInfo method from the CHttpFile class. This method retrieves information from the
header that was returned from the server. The server can supply you with different kinds
of information that may be useful to a client application. The complete list is
- HTTP_QUERY_MIME_VERSION
- HTTP_QUERY_CONTENT_TYPE
- HTTP_QUERY_CONTENT_TRANSFER_ENCODING
- HTTP_QUERY_CONTENT_ID
- HTTP_QUERY_CONTENT_DESCRIPTION
- HTTP_QUERY_CONTENT_LENGTH
- HTTP_QUERY_ALLOWED_METHODS
- HTTP_QUERY_PUBLIC_METHODS
- HTTP_QUERY_DATE
- HTTP_QUERY_EXPIRES
- HTTP_QUERY_LAST_MODIFIED
- HTTP_QUERY_MESSAGE_ID
- HTTP_QUERY_URI
- HTTP_QUERY_DERIVED_FROM
- HTTP_QUERY_LANGUAGE
- HTTP_QUERY_COST
- HTTP_QUERY_WWW_LINK
- HTTP_QUERY_PRAGMA
- HTTP_QUERY_VERSION
- HTTP_QUERY_STATUS_CODE
- HTTP_QUERY_STATUS_TEXT
- HTTP_QUERY_RAW_HEADERS
- HTTP_QUERY_RAW_HEADERS_CRLF
The last two methods of code to discuss are the
SetReadBufferSize and ReadString. The SetReadBufferSize lets MFC know how large a buffer
of information you want each time you look at the file. ReadString reads the number of
bytes you specified in SetReadBufferSize.
Tip
The default for the buffer, if you choose not to call SetReadBufferSize, is 4096 bytes. Do
not depend on CStrings to manage the size of your buffer. I suggest that you always set
your buffer size.
The buffer size is in bytes. If your character type is larger than 1 byte, remember to
increase the size of the buffer to accommodate the character size. Consider an example of
a UNICODE character. Assuming the UNICODE character is two bytes, and that our string is
2000 characters, the math would be (2 * 2000 = total buffer size needed).
In this example the program connected to a server,
read a file and header information returned from the server, and printed to the screen.
Figure 13.5 is a screen shot of this application. Notice the header information and then
the body of the HTML. The HTML isn't formatted because the ReadString method doesn't know
or care about formatting.
Figure 13.5. The HTTP
example application output.
It seems like there is a lot of work put into this
example, but the code has so few lines. The MFC class inheritance provides the power
behind the code. Let's take a closer look.
CInternetSession
The program only used three functions from the
CInternetSession class in the HTTP example: the constructor, GetHttpConnection, and Close.
This class is flexible enough to handle all three connection types, set any options, and
handle any call backs. CInternetSession inherits from the MFC's CObject class. The CObject
class has nothing to do with the Internet, but it does have the methods necessary for
memory allocation, debugging, and serialization including new, delete, and the equals
operator (=). These are basic functions, but they are helpful here because you don't have
to write them yourself.
CInternetConnection and
the Connection Classes
CInternetConnection is the base class for
CHttpConnection, CFtpConnection, and CGopherConnection. It provides methods to get the
server name, server context number, and session object. The CHttpConnection class doesn't
do much more. It only has two methods: a constructor and OpenRequest. The same is true for
the CGopherConnection class. These classes don't need many functions because most of the
work is done on the server.
Why would a programmer write an application for HTTP
or Gopher when they probably already have a Web browser or Gopher reader? There are a
variety of reasons, only limited by your needs. The interesting capabilities of these
classes are not getting a file to display the information as a browser would. However, if
that is what you want to do, go for it. Imagine you are a Web site administrator and you
need to check all the links on your pages to see if those pages, images, audio files, and
so on are working. You could write a program to anaylize the links on each page. You could
do this by finding the reference to the file and then attempting to retrieve that file. If
you can't get the file, neither can your browser. Another example is that many Web sites
want the current information on their Web pages to be attractive. It would be easy to
write a program that lists all files that have not been modified in the last 30 days.
These applications can be anywhere, not necessarily on the Web server.
The CFtpConnection Class
Although the classes for HTTP and Gopher do not have
many methods, the CFtpConnection class does because the client has more control and
choices about what he does on the server when he uses FTP. He can create or delete files
and directories. This is a powerful class because it allows greater flexibility that can
be controlled.
Imagine you know you will need every file and
subdirectory underneath the \computer-club directory. With a browser such as Microsoft
Internet Explorer, you would just have to click on each subdirectory and pull down each
file. Wouldn't it be nice if you could start one program and then go onto more interesting
things? When the program is finished, the files would appear on your hard drive just as
they appeared on the server. This would save you the time and the trouble of having to do
it yourself. Your program could even check to see if you had enough space on your hard
drive before bringing down each file.
The FTP Sample
Application
This sample application will connect to an FTP
server, read all the files and directories in the root, and get a file named Welcome.txt.
The output of the application should look something like Figure 13.6.
Figure 13.6. The FTP sample
application output. The URL of the location is included.
As with the previous example, you will need to find
an FTP server and a file you want to retrieve from that server. If you have permissions to
write to that server, try to put a file on the server instead of getting a file.
In order to start, first create an application. We
need to create the application in the same manner as the previous example. Open up
Microsoft Visual C++, and make a new project workspace. Name the workspace FTPexam. Make
sure the project is a console application. The reason it is a console application is that
I don't want you to be confused by seeing any classes that are not closely related to
these WinInet classes. Because a console application doesn't use MFC by default, you need
to change the project so that it does use MFC. In your project, change your project
settings (Build Menu/Settings) to use MFC in a shared dll (General Tab/MFC drop-down
list). If you don't let the project know you need to use the MFC dll, when you build, you
will get linker errors regarding beginthread and endthread functions.
Because you have already written one application,
enter all the code for the second application. The general flow of the application should
make sense to you.
Create a header file ftpex.h that looks like Listing
13.7
Listing 13.7. ftpex.h (create header file).
#include <afx.h> // header file for MFC
#include <afxinet.h> // header file for WinInet
#include <iostream.h> // header file for input/output stream
#include <stdlib.h> // header file for standard library functions
class CFtpExample : public CInternetSession
{
public:
CFtpExample(LPCTSTR pszAppName, int nMethod);
};
Create a code file ftpex.cpp that looks like Listing 13.8.
Listing 13.8. ftpex.cpp (write the entire application).
#include "ftpex.h" // header file for Project
// CFtpExample class implementation
CFtpExample::CFtpExample(LPCTSTR pszAppName, int nMethod)
: CInternetSession(pszAppName, 1, nMethod)
{
}
void main()
{
// variables
CFtpExample session(_T("Ftp Example"), INTERNET_OPEN_TYPE_PRECONFIG);
CFtpConnection* pServer=NULL;
CString serverName(_T("dinaf2"));
CString fileName;
CString subdirectoryName;
CString currentDirectory;
BOOL fSuccess;
// running code implementation
pServer = session.GetFtpConnection(serverName);
if(fSuccess = pServer->GetCurrentDirectoryAsURL(currentDirectory))
{
cout << _T("Connected to ") << currentDirectory << endl
<< endl;
CFtpFileFind ftpFind(pServer);
if(fSuccess = ftpFind.FindFile(_T("/*")))
{
while(fSuccess)
{
fSuccess = ftpFind.FindNextFile();
if(ftpFind.IsDirectory())
{
fileName = ftpFind.GetFileName();
cout << _T("directory: ") << fileName << endl;
}
else
{
fileName = ftpFind.GetFileName();
if(fileName==_T("Welcome.txt"))
{
if(fSuccess = pServer->GetFile(fileName,fileName,TRUE,
FILE_ATTRIBUTE_NORMAL,FTP_TRANSFER_TYPE_ASCII))
cout << _T(" retrieved") << endl;
else
cout << endl;
}
else
cout << endl;
}
}
ftpFind.Close();
}
else
{
ftpFind.Close();
}
}
pServer->Close();
if(pServer)
delete pServer;
session.Close();
}
The connection code is very similar to the HTTP
example's connection code. The major differences between this example and the previous one
are the use of CFtpFindFile and the methods used from CFtpConnection.
The CFtpConnection class has quite a few functions
for manipulating where the client is and what the client is doing on the server. The
methods of CFTPConnection are
- CFtpConnectionis the class constructor. All
general initialization of class members happens here.
- SetCurrentDirectorysets the current directory
for this connection.
- GetCurrentDirectorygets the current directory
for this connection.
- GetCurrentDirectoryAsURLgets the current
directory in relation to the root of server, and includes the server's name.
- RemoveDirectoryremoves the directory from the
server.
- CreateDirectorycreates the directory on the
server.
- Renamerenames a file on the server.
- Removeremoves a file on the server.
- PutFileputs the file on the server.
- GetFilegets the file from the server.
- OpenFileopens the file.
- Closecloses the connection to the server.
Also notice that instead of using CInternetFile (as
in the CHTTP example), you used the CFtpFindFile class. Its members are
- CFtpFileFindis the class constructor. Any
intialization of class members happens here.
- FindFilefinds a file on the FTP server.
- FindNextFileFinds the next file.
- GetFileURLGets the URL of a file, including the
path.
What about some of the functions we used to
manipulate the file that are not in the preceding class method list for CFtpFindFile, such
as IsDir? Because CFtpFindFile inherits from CFileFind, the codes get all the
functionality of this base class. The class is used by the Gopher and FTP connection
types. It gives the code some neat such as is the file really a directory or is the file
marked with the read-only attribute, when was the last time the file was accessed, and how
big is the file. These are just a few of our choices; the rest of the methods of CFileFind
I'll leave for you to discover.
Notice that the GetFile function's first two
parameters in Listing 13.8 were both fileName. The first variable defines the name of the
file I want to retrieve and the second variable defines the file on the local hard drive I
want. The fourth and fifth parameters are flags. The fourth parameter is what attributes
we want the file to have on our hard drive. Your choices are
- FILE_ATTRIBUTE_ARCHIVE
- FILE_ATTRIBUTE_COMPRESSED
- FILE_ATTRIBUTE_DIRECTORY
- FILE_ATTRIBUTE_NORMAL
- FILE_ATTRIBUTE_HIDDEN
- FILE_ATTRIBUTE_READONLY
- FILE_ATTRIBUTE_SYSTEM
- FILE_ATTRIBUTE_TEMPORARY
The fifth parameter specifies the condition of the
transfer of the file. Your choices are text or binary:
- FTP_TRANSFER_TYPE_ASCII
- FTP_TRANSFER_TYPE_BINARY
Tip
Use the FTP_TRANSFER_TYPE_BINARY when you want the file to be of the same type as it is
stored on the server. This is also the default choice if you don't specify a type.
Tip
If you just want to read a file from an FTP server, you can use the CInternetFile::Read
along with the CFtpConnection::OpenFile functions.
Listing 13. 9 displays the httpex.cpp file in its
entirety.
Listing 13.9. The HTTP example (entire httpex.cpp
file).
#include "httpex.h" // header file for Project
// CHttpExample class implementation
CHttpExample::CHttpExample(LPCTSTR pszAppName, int nMethod)
: CInternetSession(pszAppName, 1, nMethod)
{
}
void main()
{
// variables
CHttpExample session(_T("Http Example"), INTERNET_OPEN_TYPE_PRECONFIG);
CHttpConnection* pServer=NULL;
CHttpFile* pFile=NULL;
CString serverName(_T("dinaf2"));
CString fileName(_T("/default.asp"));
CString headerInfo(_T("Accept: text/*\r\nUser-Agent:
HTTP Example\r\n"));
CString newLocation;
CString returnedFileText;
DWORD dwReturnCode;
BOOL fSuccess;
// running code implementation
pServer = session.GetHttpConnection(serverName);
pFile = pServer->OpenRequest(CHttpConnection::
HTTP_VERB_GET,
fileName,NULL,1,NULL,NULL,INTERNET_FLAG
_EXISTING_CONNECT);
if(fSuccess = pFile->AddRequestHeaders(headerInfo))
{
if(fSuccess = pFile->SendRequest())
{
if(fSuccess = pFile->QueryInfoStatusCode(dwReturnCode))
{
if(dwReturnCode==200)
{
if(fSuccess = pFile->QueryInfo(HTTP_QUERY_RAW_
HEADERS_CRLF,newLocation))
{
if(newLocation != _T(""))
cout << _T("Header Info: ") << newLocation << endl <<
endl;
}
pFile->SetReadBufferSize(2000);
while(pFile->ReadString(returnedFileText))
cout << returnedFileText;
}
}
}
}
// connection to server
pFile->Close();
if(pFile)
delete pFile;
pServer->Close();
if(pServer)
delete pServer;
session.Close();
}
Summary
In this chapter you learned about the Win32 Internet
API and the MFC classes corresponding to this API. These functions allow the client to
make a connection to a server. With these MFC classes, a programmer can make a connection
to a server and manipulate files. The neat feature of these classes is that a programmer
doesn't have to understand TCP/IP programming or any other low level functionality because
they abstract and manipulate this work for you.
The HTTP classes help you get files from a Web
server. The FTP classes let you do all the file and directory manipulation that an FTP
server will allow. The Gopher classes cover a little of the other two classes.
Q&A
- Q Where do you download the Win32 API?
- A Download from http://www.microsoft.com/intdev/sdk/docs/wininet/
- Q What version of Microsoft Visual C++ do you need
to use these cool classes?
- A Use version 4.2, which is only available
through subscription.
- Q What is the base class for connecting to a
server?
- A CInternetSession
- Q What is the base class for the three connection
types?
- A CInternetConnection
- Q What class do you need to read an HTML file?
- A CHttpFile
- Q What classes do you need to read an FTP or a
Gopher file?
- A CFtpFileFind and CGopherFileFind,
respectively
Workshop
In your own browser, try to connect to an FTP site.
You may have to change the options of your browser. Also try to connect to the FTP site
through any commands supported by your operating system. Once you are connected, try
downloading a file. If you have a Web server, configure it for FTP, connect to it, and put
a file in its directory. Next, try to connect to a Gopher site. You may have to change the
options of your browser. Also try to connect to the Gopher site through any commands
supported by your operating system. Once you are connected, try downloading a file. If you
have a Web server, configure it for Gopher, connect to it, and get a file from its
directory. Try to use a search engine. Attempt to create a WAIS search on your Web server
(if you have one).
Quiz
- Why will a normal console application not link with
MFC, even if you have the proper #include?
- What methods do I need to connect to a server?
- Why do I have to check the return value from
CFtpConnection::GetCurrentDirectory()?
- What is the class I should use to handle an
exception?
- What is the _T macro used for?
|