Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

General Internet Functions

Many functions in the WinInet API are used for any sort of Internet connection, such as beginning a session, enabling asynchronous I/O, and manipulating URLs. Here, you will take a look at these general functions before moving on to the protocol-specific elements of the WinInet API.

Beginning a WinInet Session

Before using most of the WinInet functions, you must open a new session with a call to InternetOpen(), which initializes the WinInet library and returns a session handle that will be the root of the handle hierarchy for the rest of your operations within that session. The following is the prototype for InternetOpen():

HINTERNET InternetOpen(LPCTSTR lpszAgent, DWORD dwAccessType,
    LPCTSTR lpszProxyName, LPCSTR lpszProxyBypass, DWORD dwFlags);

InternetOpen() enables you to specify how this session will use a proxy server. The dwAccessType parameter may specify INTERNET_OPEN_TYPE_DIRECT to resolve all addresses locally, INTERNET_OPEN_TYPE_PROXY to send requests to the proxy server, or INTERNET_OPEN_TYPE_PRECONFIG to retrieve proxy configuration information from the Registry. In cases where you are using a proxy server, its name is passed in lpszProxyName, although this can be NULL to read proxy information from the Registry.

You also can specify a list of addresses that will be resolved locally in the lpszProxyBypass string. Requests for any address contained in this string will not be forwarded to the proxy server but will be resolved locally.

You may specify the INTERNET_FLAG_OFFLINE flag in dwFlags to specify that all download requests for this session be handled by the persistent cache. If a requested file is not in the cache, operations to access it will fail.

You also may specify the INTERNET_FLAG_ASYNC flag to enable asynchronous operations for this session handle, as well as any handles derived from it.

The INTERNET_FLAG_FROM_CACHE flag returns all requested items from the cache alone. If the item is not found in the cache, an error such as ERROR_FILE_NOT_FOUND (or whatever is most appropriate) is returned. The function InternetOpen uses this flag.

When you are finished with a session, you should close the session handle with a call to InternetCloseHandle(). This also closes any handles that have been derived from the session handle.

Setting Handle Options

If you want to use certain options for all the Internet handles that you will be using in this session, it is easiest to set the options on the session handle. Any handles that are derived from the session handle, such as connection handles created by InternetConnect(), will inherit the options from the session handle. In addition, you could set options for a connection handle, which will be inherited by any handles derived from that connection handle. Note however, that only new handles derived from the modified handle will inherit the new settings. Handles that already have been created will maintain their current settings.

You set specific option settings for an Internet handle with a call to the InternetSetOption() function:

BOOL InternetSetOption(HINTERNET hInternet, DWORD dwOption,
    LPVOID lpBuffer, DWORD dwBufferLength);

The handle to be modified is passed in hInternet. The buffer passed by lpBuffer, and its length passed in dwBufferLength, are used to pass in data for the specific option that is to be set. You specify the option to set by the value dwOption, and you can use one of the following values:

Note that this is just a partial list, for there are over 50 internet options available.

You also can set the options for a handle with the InternetSetOptionEx() function, which takes an additional dwFlags parameter. You may set the flags to ISO_GLOBAL to modify the settings globally or to ISO_REGISTRY to modify the settings in the Registry.

Querying Handle Options

You can query the current settings for a handle's options with the InternetQueryOption() function:

BOOL InternetQueryOption(HINTERNET hInternet, DWORD dwOption,
    LPVOID lpBuffer, LPDWORD lpdwBufferLength);

This function works much like InternetSetOption() and enables you to query all the options listed previously. In addition, you can query several additional values that are not set with InternetSetOption():

Verifying Internet Connectivity

If your application is capable of operating with or without an Internet connection, you may want to use the InternetAttemptConnect() function, which attempts to connect to the Internet. If this returns ERROR_SUCCESS, the connection was successful and your application should be able to access information on the Internet. If any other error is returned, the connection could not be established and your application should respond appropriately, perhaps operating in an offline mode.

Connecting to a Server

For most cases, in order to communicate with an FTP, HTTP, or Gopher server, you first must establish a connection, although you will see that InternetOpenUrl() does not require you to create a session explicitly before retrieving files. Establishing a connection is done with the InternetConnect() function, which returns a handle (HINTERNET) for the connection. The new connection handle is derived from a session handle created by InternetOpen() and inherits the attributes of the session handle, like the asynchronous mode.

For the FTP protocol, InternetConnect() establishes a genuine connection to the server, although for protocols such as Gopher and HTTP, the actual connection is not established until a specific request is made. The connection represented by the handle returned by InternetConnect() is a sort of "virtual connection" and can be used to store configuration information for the connection.

The prototype for InternetConnect() follows:

HINTERNET InternetConnect(HINTERNET hInternet, LPCTSTR lpszServerName,
    INTERNET_PORT nServerPort, LPCTSTR lpszUsername, LPCTSTR lpszPassword,
    DWORD dwService, DWORD dwFlags, DWORD dwContext);

The handle passed in hInternet comes from a call to InternetOpen(), and the lpszServerName and nServerPort parameters refer to the desired server. You can specify a value of INTERNET_INVALID_PORT_NUMBER to use the default port for the requested service, or you may use one of the following constants:

The optional lpszUsername and lpszPassword parameters may be required to connect to servers that require a login.

The dwService parameter specifies the service to which to connect. This can be one of the following constants:

The dwFlags parameter is used to specify options for the service. Currently, only the INTERNET_CONNECT_FLAG_PASSIVE flag is implemented, which specifies the use of passive mode for FTP connections.

If an error occurs in InternetConnect(), it returns NULL, and you can call GetLastError() or InternetGetLastResponseInfo() for more details on the error. If the connection is established successfully, InternetConnect() returns a valid connection handle, which can be used in the protocol-specific functions that you will explore soon.

Adding a Callback Function

InternetConnect(), like many other functions that you will look at in this chapter, can be used asynchronously. To do this, the INTERNET_FLAG_ASYNC flag must have been set when the session handle was created by InternetOpen(). You also must assign a context value and have a callback function assigned to the handle. A callback function is attached to a handle with the InternetSetStatusCallback() function:

INTERNET_STATUS_CALLBACK InternetSetStatusCallback(
    HINTERNET hInternet, INTERNET_STATUS_CALLBACK lpfnInternetCallback);

The hInternet parameter specifies the handle that will use the callback function specified in lpfnInternetCallback. Any handles that are derived from this handle—after the callback is attached—also will use this callback function.

The callback function specified in lpfnInternetCallback should have the following prototype:

void CALLBACK myCallback(HINTERNET hInternet, DWORD dwContext,
                DWORD dwInternetStatus, LPVOID lpvStatusInformation,
                DWORD dwStatusInformationLength);

When the callback function is called to report the status of an asynchronous operation, the hInternet and dwContext parameters give the Internet handle and context value used in the operation, and the reason for calling the function is given in dwInternetStatus. The data returned through lpvStatusInformation (of length dwStatusInformationLength) is dependent on the reason for the callback, given in dwInternetStatus. The following are possible values for dwInternetStatus:

In many cases, your application may be concerned only with handling the completion of asynchronous operations, specified by a call to the callback function with a value of INTERNET_STATUS_REQUEST_COMPLETE passed in dwInternetStatus, although some operations may generate many other calls to the callback function. A call to InternetConnect(), for example, may generate a dozen or so different calls to the callback function. Because your callback may be called many times, you should try to minimize the operations performed within the callback. Spending excessive time in the callback, like displaying a dialog box, may cause some operations to time out before the callback returns.

Working with URLs

The WinInet API provides several functions that can be useful in simplifying the processing of URLs. You can parse a URL into its various components with InternetCrackUrl(), and you can use InternetCreateUrl() to create a URL string from the individual components. You can use the InternetCanonicalizeUrl() function to convert a URL to canonical form, as well as to convert any unsafe characters into escape sequences. You also can merge a base URL and a relative URL into a single URL string with InternetCombineUrl().

Basic File Operations

For many WinInet functions, you need to explicitly establish a connection (using InternetConnect()) before using the protocol-specific functions. However, the WinInet API does provide a simple method for retrieving data from an FTP, HTTP, or Gopher server in a somewhat generic manner using the InternetOpenUrl() function:

HINTERNET InternetOpenUrl(HINTERNET hInternetSession,
    LPCTSTR lpszUrl, LPCTSTR lpszHeaders, DWORD dwHeadersLength,
    DWORD dwFlags, DWORD dwContext);

Each call to InternetOpenUrl() establishes its own connection, so you do not need to create one explicitly with a call to InternetConnect(). However, you do need to pass a valid session handle returned from InternetOpen() in hInternetSession.

InternetOpenUrl() returns an Internet handle for the file requested by the URL string passed by lpszUrl. If this completes successfully, you can use this handle in calls to functions such as InternetReadFile(), as you will see shortly.

For HTTP requests, you can specify a pointer to an additional header string in the lpszHeaders. The length of this string should be passed in dwHeadersLength, although you can pass a length of -1 if the header's string is null-terminated—InternetOpenUrl() then figures out the length of the header's string.

The following are option flags that may be included in dwFlags:

Querying Data Availability

If InternetOpenUrl() completes successfully, it returns an Internet file handle. You can check to see how much data is available for this file handle by calling InternetQueryDataAvailable(), which also can be used with the file handles returned by the protocol-specific functions that you will see later.

The InternetQueryDataAvailable() function takes an Internet file handle and a pointer to a DWORD where the number of bytes available will be written. Currently, the dwFlags and dwContext parameters must be 0:

BOOL InternetQueryDataAvailable(HINTERNET hFile,
    LPDWORD lpdwNumberOfBytesAvailable,
    DWORD dwFlags, DWORD dwContext);

InternetQueryDataAvailable() returns the amount of data that can be read immediately by a call to InternetReadFile(). If the end-of-file has not been reached and no data is immediately available for reading, this function blocks until data is available.

Reading Data

You can read data from a file handle with InternetReadFile(). This can be used for handles returned from InternetOpenUrl(), as well as handles returned from protocol-specific functions such as FtpOpenFile(), GopherOpenFile(), or HttpOpenRequest(). The following is the prototype for InternetReadFile():

BOOL InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
    DWORD dwNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead);

InternetReadFile() attempts to read the number of bytes specified in dwNumberOfBytesToRead into the buffer at lpBuffer. Upon completion, the DWORD at lpNumberOfBytesRead contains the number of bytes actually read. If there is not enough data currently available to satisfy the request, it blocks until enough data is received. The only time the actual number of bytes requested will be less than the number requested is when the end-of-file has been reached.

Moving the File Pointer

You can move the file pointer for calls to InternetReadFile() by calling the InternetSetFilePointer() function:

BOOL InternetSetFilePointer(HINTERNET hFile, LONG IDistanceToMove,
    PVOID pReserved, DWORD dwMoveMethod, DWORD dwContext);

The file handle passed in hFile can be any file handle returned from calls such as InternetOpenUrl() or FtpOpenFile(), with the exception that caching must be enabled for the handle—that is, it must not have been created with the INTERNET_FLAG_DONT_CACHE or INTERNET_FLAG_NO_CACHE_WRITE option.

The lDistanceToMove parameter specifies the number of bytes to move the file pointer from a location specified by dwMoveMethod, which can have the following values:

Positive values of lDistanceToMove move forward in the file, and negative values move backward.

Currently, pReserved and dwContext must be 0. This operation always completes synchronously, although subsequent calls to InternetReadFile() may complete asynchronously.

Writing to Internet Files

For Internet file handles that have been opened with InternetOpenUrl(), as well as other functions such as FtpOpenFile(), you can write data to a file with the InternetWriteFile() function:

BOOL InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
    DWORD dwNumberOfBytesToWrite, LPDWORD lpdwNumberOfBytesWritten);

This function will write the number of bytes in dwNumberOfBytesToWrite from lpBuffer to the file specified by hFile. On completion, the DWORD at lpdwNumberOfBytesWritten will contain the actual number of bytes written.

Note that the transfer may not be completed until you call InternetCloseHandle() to close the file handle and flush its buffers.

Share ThisShare This

Informit Network