WinInet

WinInet is a higher-level API than Winsock, but it works only for HTTP, FTP, and gopher client programs in both asynchronous and synchronous modes. You can't use it to build servers. The WININET DLL is independent of the WINSOCK32 DLL. Microsoft Internet Explorer 3.0 (IE3) uses WinInet, and so do ActiveX controls.

WinInet's Advantages over Winsock

WinInet far surpasses Winsock in the support it gives to a professional-level client program. Following are just some of the WinInet benefits:

  • Caching—Just like IE3, your WinInet client program caches HTML files and other Internet files. You don't have to do a thing. The second time your client requests a particular file, it's loaded from a local disk instead of from the Internet.

  • Security—WinInet supports basic authentication, Windows NT challenge/response authentication, and the Secure Sockets Layer (SSL). Authentication is described in Chapter 35.

  • Web proxy access—You enter proxy server information through the Control Panel (click on the Internet icon), and it's stored in the Registry. WinInet reads the Registry and uses the proxy server when required.

  • Buffered I/O—WinInet's read function doesn't return until it can deliver the number of bytes you asked for. (It returns immediately, of course, if the server closes the socket.) Also, you can read individual text lines if you need to.

  • Easy API—Status callback functions are available for UI update and cancellation. One function, CInternetSession::OpenURL, finds the server's IP address, opens a connection, and makes the file ready for reading, all in one call. Some functions even copy Internet files directly to and from disk.

  • User friendly—WinInet parses and formats headers for you. If a server has moved a file to a new location, it sends back the new URL in an HTTP Location header. WinInet seamlessly accesses the new server for you. In addition, WinInet puts a file's modified date in the request header for you.

The MFC WinInet Classes

WinInet is a modern API available only for Win32. The MFC wrapping is quite good, which means we didn't have to write our own WinInet class library. Yes, MFC WinInet supports blocking calls in multithreaded programs, and by now you know that makes us happy.

The MFC classes closely mirror the underlying WinInet architecture, and they add exception processing. These classes are summarized in the sections on the following pages.

CInternetSession

You need only one CInternetSession object for each thread that accesses the Internet. After you have your CInternetSession object, you can establish HTTP, FTP, or gopher connections or you can open remote files directly by calling the OpenURL member function. You can use the CInternetSession class directly, or you can derive a class from it in order to support status callback functions.

The CInternetSession constructor calls the WinInet InternetOpen function, which returns an HINTERNET session handle that is stored inside the CInternetSession object. This function initializes your application's use of the Win- Inet library, and the session handle is used internally as a parameter for other WinInet calls.

CHttpConnection

An object of class CHttpConnection represents a "permanent" HTTP connection to a particular host. You know already that HTTP doesn't support permanent connections and that FTP doesn't either. (The connections last only for the duration of a file transfer.) WinInet gives the appearance of a permanent connection because it remembers the host name.

After you have your CInternetSession object, you call the GetHttpConnection member function, which returns a pointer to a CHttpConnection object. (Don't forget to delete this object when you are finished with it.)

The GetHttpConnection member function calls the WinInet InternetConnect function, which returns an HINTERNET connection handle that is stored inside the CHttpConnection object and used for subsequent WinInet calls.

CFtpConnection, CGopherConnection

These classes are similar to CHttpConnection, but they use the FTP and gopher protocols. The CFtpConnection member functions GetFile and PutFile allow you to transfer files directly to and from your disk.

CInternetFile

With HTTP, FTP, or gopher, your client program reads and writes byte streams. The MFC WinInet classes make these byte streams look like ordinary files. If you look at the class hierarchy, you'll see that CInternetFile is derived from CStdioFile, which is derived from CFile. Therefore, CInternetFile and its derived classes override familiar CFile functions such as Read and Write. For FTP files, you use CInternetFile objects directly, but for HTTP and gopher files, you use objects of the derived classes CHttpFile and CGopherFile. You don't construct a CInternetFile object directly, but you call CFtpConnection::OpenFile to get a CInternetFile pointer.

If you have an ordinary CFile object, it has a 32-bit HANDLE data member that represents the underlying disk file. A CInternetFile object uses the same m_hFile data member, but that data member holds a 32-bit Internet file handle of type HINTERNET, which is not interchangeable with a HANDLE. The CInternetFile overridden member functions use this handle to call WinInet functions such as InternetReadFile and InternetWriteFile.

CHttpFile

This Internet file class has member functions that are unique to HTTP files, such as AddRequestHeaders, SendRequest, and GetFileURL. You don't construct a CHttpFile object directly, but you call the CHttpConnection::OpenRequest function, which calls the WinInet function HttpOpenRequest and returns a CHttpFile pointer. You can specify a GET or POST request for this call.

Once you have your CHttpFile pointer, you call the CHttpFile::SendRequest member function, which actually sends the request to the server. Then you call Read.

CFtpFileFind, CGopherFileFind

These classes let your client program explore FTP and gopher directories.

CInternetException

The MFC WinInet classes throw CInternetException objects that your program can process with try/catch logic.

Internet Session Status Callbacks

WinInet and MFC provide callback notifications as a WinInet operation progresses, and these status callbacks are available in both synchronous (blocking) and asynchronous modes. In synchronous mode (which we're using exclusively here), your WinInet calls block even though you have status callbacks enabled.

Callbacks are easy in C++. You simply derive a class and override selected virtual functions. The base class for WinInet is CInternetSession. Now let's derive a class named CCallbackInternetSession:

class CCallbackInternetSession : public CInternetSession { public:     CCallbackInternetSession( LPCTSTR pstrAgent = NULL, DWORD dwContext = 1,         DWORD dwAccessType = PRE_CONFIG_INTERNET_ACCESS,         LPCTSTR pstrProxyName = NULL, LPCTSTR pstrProxyBypass = NULL,         DWORD dwFlags = 0 ) { EnableStatusCallback() } protected:     virtual void OnStatusCallback(DWORD dwContext, DWORD dwInternalStatus,         LPVOID lpvStatusInformation, DWORD dwStatusInformationLength); };

The only coding that's necessary is a constructor and a single overridden function, OnStatusCallback. The constructor calls CInternetSession::EnableStatusCallback to enable the status callback feature. Your WinInet client program makes its various Internet blocking calls, and when the status changes, OnStatusCallback is called. Your overridden function quickly updates the UI and returns, and then the Internet operation continues. For HTTP, most of the callbacks originate in the CHttpFile::SendRequest function.

What kind of events trigger callbacks? A list of the codes passed in the dwInternalStatus parameter is shown here.

Code PassedAction Taken
INTERNET_STATUS_RESOLVING_NAMELooking up the IP address of the supplied name. The name is now in lpvStatusInformation.
INTERNET_STATUS_NAME_RESOLVEDSuccessfully found the IP address. The IP address is now in lpvStatusInformation.
INTERNET_STATUS_CONNECTING_TO_SERVERConnecting to the socket.
INTERNET_STATUS_CONNECTED_TO_SERVERSuccessfully connected to the socket.
INTERNET_STATUS_SENDING_REQUESTSend the information request to the server.
INTERNET_STATUS_REQUEST_SENTSuccessfully sent the information request to the server.
INTERNET_STATUS_RECEIVING_RESPONSEWaiting for the server to respond to a request.
INTERNET_STATUS_RESPONSE_RECEIVEDSuccessfully received a response from the server.
INTERNET_STATUS_CLOSING_CONNECTIONClosing the connection to the server.
INTERNET_STATUS_CONNECTION_CLOSEDSuccessfully closed the connection to the server.
INTERNET_STATUS_HANDLE_CREATEDProgram can now close the handle.
INTERNET_STATUS_HANDLE_CLOSINGSuccessfully terminated this handle value.
INTERNET_STATUS_REQUEST_COMPLETESuccessfully completed the asynchronous operation.

You can use your status callback function to interrupt a WinInet operation. You could, for example, test for an event set by the main thread when the user cancels the operation.

A Simplified WinInet Client Program

And now for the WinInet equivalent of our Winsock client program that implements a blind GET request. Because you're using WinInet in blocking mode, you must put the code in a worker thread. That thread is started from a command handler in the main thread:

AfxBeginThread(ClientWinInetThreadProc, GetSafeHwnd());

Here's the client thread code:

CString g_strServerName = "localhost"; // or some other host name UINT ClientWinInetThreadProc(LPVOID pParam) {     CInternetSession session;     CHttpConnection* pConnection = NULL;     CHttpFile* pFile1 = NULL;     char* buffer = new char[MAXBUF];     UINT nBytesRead = 0;     try {         pConnection = session.GetHttpConnection(g_strServerName, 80);         pFile1 = pConnection->OpenRequest(1, "/"); // blind GET         pFile1->SendRequest();         nBytesRead = pFile1->Read(buffer, MAXBUF - 1);         buffer[nBytesRead] = `\0'; // necessary for message box         char temp[10];         if(pFile1->Read(temp, 10) != 0) {             // makes caching work if read complete             AfxMessageBox("File overran buffer — not cached");         }         AfxMessageBox(buffer);     }     catch(CInternetException* e) {         // Log the exception         e->Delete();     }     if(pFile1) delete pFile1;     if(pConnection) delete pConnection;     delete [] buffer;     return 0; }

The second Read call needs some explanation. It has two purposes. If the first Read doesn't read the whole file, that means that it was longer than MAXBUF -1. The second Read will get some bytes, and that lets you detect the overflow problem. If the first Read reads the whole file, you still need the second Read to force WinInet to cache the file on your hard disk. Remember that WinInet tries to read all the bytes you ask it to—through the end of the file. Even so, you need to read 0 bytes after that.



Programming Microsoft Visual C++
Programming Microsoft Visual C++
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 332

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net