Programming with Microsoft Visual C++.NET 6ed [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming with Microsoft Visual C++.NET 6ed [Electronic resources] - نسخه متنی

George Shepherd, David Kruglinski

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید








WinInet


WinInet is a higher-level API than Winsock, but it works only for HTTP, FTP, and gopher client programs in either asynchronous or synchronous mode. You can't use it to build servers. The WININET DLL is independent of the WINSOCK32 DLL. Internet Explorer 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. Here are just some of the WinInet benefits:



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



    Security WinInet supports basic authentication, Windows NT/ 2000/XP challenge/response authentication, and Secure Sockets Layer (SSL).



    Web proxy access You enter proxy server information through Control Panel, and it will be 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 will return 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 user interface 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-friendliness WinInet parses and formats headers for you. If a server has moved a file to a new location, it will send back the new URL in an HTTP Location header. WinInet will seamlessly access the new server for you. In addition, it will put 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 following sections.


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 WinInet 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're finished with it.)

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



CFtpConnection and 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—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 and 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 will block even if 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 user interface and returns, and then the Internet operation continues. For HTTP, most of the callbacks originate in the CHttpFile::SendRequest function.

What kinds of events trigger callbacks? Here's a list of the codes passed in the dwInternalStatus parameter:

















































Code Passed


Action Taken


INTERNET_STATUS_RESOLVING_NAME


Looking up the IP address of the supplied name. The name is now in lpvStatusInformation.


INTERNET_STATUS_NAME_RESOLVED


Successfully found the IP address. The IP address is now in lpvStatusInformation.


INTERNET_STATUS_CONNECTING_TO_SERVER


Connecting to the socket.


INTERNET_STATUS_CONNECTED_TO_SERVER


Successfully connected to the socket.


INTERNET_STATUS_SENDING_REQUEST


Send the information request to the server.


INTERNET_STATUS_REQUEST_SENT


Successfully sent the information request to the server.


INTERNET_STATUS_RECEIVING_RESPONSE


Waiting for the server to respond to a request.


INTERNET_STATUS_RESPONSE_RECEIVED


Successfully received a response from the server.


INTERNET_STATUS_CLOSING_CONNECTION


Closing the connection to the server.


INTERNET_STATUS_CONNECTION_CLOSED


Successfully closed the connection to the server.


INTERNET_STATUS_HANDLE_CREATED


Program can now close the handle.


INTERNET_STATUS_HANDLE_CLOSING


Successfully terminated this handle value.


INTERNET_STATUS_REQUEST_COMPLETE


Successfully completed the asynchronous operation.


You can use your status callback function to interrupt a WinInet operation. You can, 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.



/ 319