| Tenouk C & C++ | MFC Home | C++, MFC, Winsock & WinInet 6 | C++, MFC, Winsock & WinInet 8 | Download | Site Index |


 

 

 

 

 

 

C++, MFC, Winsock and WinInet Part 7

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2 and some Figure screen snapshots have been taken on Windows 2000 server. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer.  Supplementary item is WEBSITE.

  1. The Coding Part...Continue

  2. Running MYEX33A

 

Add the following client threads source files for Winsock, WinInet and OpenURL(): ClientinetThread.cpp, ClientsockThread.cpp and ClienturlThread.cpp.

 

Winsock, C++ and MFC - Figure 77: Adding another new source file to project.

 

Figure 77: Adding another new source file to project.

Add the following codes.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// clientinetthread.cpp (uses MFC Wininet calls)

 

#include <stdafx.h>

#include "utility.h"

#define MAXBUF 80000

 

HWND g_hMainWnd = 0;

char g_pchStatus[25] = "";

CCriticalSection g_csStatus;

 

UINT ClientWinInetThreadProc(LPVOID pParam)

{

       CCallbackInternetSession session;

       CHttpConnection* pConnection = NULL;

       CHttpFile* pFile1 = NULL;

       char* buffer = new char[MAXBUF];

       UINT nBytesRead = 0;

       DWORD dwStatus;

       try {

              // username/password doesn't work yet

              if(!g_strServerName.IsEmpty()) {

                     pConnection = session.GetHttpConnection(g_strServerName, (INTERNET_PORT) g_nPort);

              }

              else {

                     pConnection = session.GetHttpConnection(g_strServerIP, (INTERNET_PORT) g_nPort);

              }

              pFile1 = pConnection->OpenRequest(1, g_strFile, NULL, 1, NULL, NULL, // GET request

                           INTERNET_FLAG_KEEP_CONNECTION); // needed for NT Challenge/Response authentication

              // INTERNET_FLAG_RELOAD forces reload from the server (bypasses client's cache)

              pFile1->SendRequest();

              pFile1->QueryInfoStatusCode(dwStatus);

              TRACE("QueryInfoStatusCode = %d\n", dwStatus);

              nBytesRead = pFile1->Read(buffer, MAXBUF - 1);

              buffer[nBytesRead] = '\0'; // necessary for message box

              char temp[100];

              if(pFile1->Read(temp, 100) != 0) { // makes caching work if read complete

                     AfxMessageBox("File overran buffer -- not cached");

              }

              ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "WININET CLIENT", MB_OK);

              // could use existing pFile1 to SendRequest again if we wanted to

       }

       catch(CInternetException* e) {

              LogInternetException(pParam, e);

              e->Delete();

       }

       // could call OpenRequest again on same connection if we wanted to

       if(pFile1) delete pFile1; // does the close -- prints a warning

       // why does it print a warning?

       if(pConnection) delete pConnection;

       delete [ ] buffer;

       g_csStatus.Lock();

       // problem with empty string. bug #9897

         strcpy(g_pchStatus, "");

       g_csStatus.Unlock();

       return 0;

}

 

 

Listing 21.

 

 

// clientsockthread.cpp (uses Winsock calls only)

 

#include <stdafx.h>

#include "blocksock.h"

#include "utility.h"

#define MAXBUF 80000

 

CString g_strIPClient;

CString g_strProxy = "ITGPROXY";

BOOL g_bUseProxy = FALSE;

 

UINT ClientSocketThreadProc(LPVOID pParam)

{

       // sends a blind request, followed by a request for a specific URL

       CHttpBlockingSocket sClient;

       char* buffer = new char[MAXBUF];

       int nBytesReceived = 0;

       // We're doing a blind GET, but we must provide server name if we're using a proxy.

       // A blind GET is supposed to retrieve the server's default HTML document.

       // Some servers don't have a default document but return a document name in the Location header.

       char request[ ] = "GET %s%s%s HTTP/1.0\r\n";

       char headers[ ] =

              "User-Agent: Mozilla/1.22 (Windows; U; 32bit)\r\n"

              "Accept: */*\r\n"

              "Accept: image/gif\r\n"

              "Accept: image/x-xbitmap\r\n"

              "Accept: image/jpeg\r\n"

      // following line tests server's ability to not send the URL

      //             "If-Modified-Since: Wed, 11 Sep 1996 20:23:04 GMT\r\n"

              "\r\n"; // need this

       CSockAddr saServer, saPeer, saTest, saClient;

       try {

              sClient.Create();

              if(!g_strIPClient.IsEmpty()) {

                     // won't work if network is assigning us our IP address

                     // good only for intranets where client computer has several IP addresses

                     saClient = CSockAddr(g_strIPClient);

                     sClient.Bind(saClient);

              }

              if(g_bUseProxy) {

                     saServer = CBlockingSocket::GetHostByName(g_strProxy, 80);

              }

              else {

                     if(g_strServerIP.IsEmpty()) {

                     saServer = CBlockingSocket::GetHostByName(g_strServerName, g_nPort);

                     }

                     else {

                           saServer = CSockAddr(g_strServerIP, g_nPort);

                     }

              }

              sClient.Connect(saServer);

              sClient.GetSockAddr(saTest);

              TRACE("SOCK CLIENT: GetSockAddr = %s, %d\n", saTest.DottedDecimal(), saTest.Port());

              if(g_bUseProxy) {

              wsprintf(buffer, request, "http://" , (const char*) g_strServerName, g_strFile);

              }

              else {

                     wsprintf(buffer, request, "", "", g_strFile);

              }

              sClient.Write(buffer, strlen(buffer), 10);

              sClient.Write(headers, strlen(headers), 10);

              // read all the server's response headers

              do {

                     nBytesReceived = sClient.ReadHttpHeaderLine(buffer, MAXBUF, 10);

                     TRACE("SOCK CLIENT: %s", buffer);

              } while(strcmp(buffer, "\r\n"));

              // read the server's file

              nBytesReceived = sClient.ReadHttpResponse(buffer, MAXBUF, 10);

              TRACE("SOCK CLIENT: bytes received = %d\n", nBytesReceived);

              if(nBytesReceived == 0) {

                     AfxMessageBox("No response received. Bad URL?");

              }

              else {

                     buffer[nBytesReceived] = '\0';

                     ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "WINSOCK CLIENT", MB_OK);

              }

              // could do another request on sClient by calling Close, then Create, etc.

       }

       catch(CBlockingSocketException* e) {

              LogBlockingSocketException(pParam, "CLIENT:", e);

              e->Delete();

       }

       sClient.Close();

       delete [ ] buffer;

       return 0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 22.

 

// clienturlthread.cpp (uses CInternetSession::OpenURL)

 

#include <stdafx.h>

#include "utility.h"

#define MAXBUF 80000

 

CString g_strURL = "http://";

 

UINT ClientUrlThreadProc(LPVOID pParam)

{

       char* buffer = new char[MAXBUF];

       UINT nBytesRead = 0;

 

       CInternetSession session; // can't get status callbacks for OpenURL

       CStdioFile* pFile1 = NULL; // could call ReadString to get 1 line

       try {

              pFile1 = session.OpenURL(g_strURL, 0, INTERNET_FLAG_TRANSFER_BINARY |

                           INTERNET_FLAG_KEEP_CONNECTION);

              // if OpenURL fails, we won't get past here

              nBytesRead = pFile1->Read(buffer, MAXBUF - 1);

              buffer[nBytesRead] = '\0'; // necessary for message box

              char temp[100];

              if(pFile1->Read(temp, 100) != 0) { // makes caching work if read complete

                     AfxMessageBox("File overran buffer -- not cached");

              }

              ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "URL CLIENT", MB_OK);

       }

       catch(CInternetException* e) {

              LogInternetException(pParam, e);

              e->Delete();

       }

       if(pFile1) delete pFile1;

       delete [ ] buffer;

       return 0;

}

 

 

Listing 23.

 

Using ClassWizard, add SaveModified() virtual function to CMyex33aDoc class.

 

Winsock, C++ and MFC - Figure 78: Adding SaveModified() function to CMyex33aDoc class.

 

Figure 78: Adding SaveModified() function to CMyex33aDoc class.

 

Click the Edit Code button and edit the SaveModified() as shown below.

 

BOOL CMyex33aDoc::SaveModified()

{

      // TODO: Add your specialized code here and/or call the base class

      return TRUE; // eliminates "save doc" message on exit

}

 

Using ClassWizard, add the following message map to CMyex33aView class. Before that, open the ResourceView, select the IDD_DIALOGBAR under the dialog folder and launch ClassWizard. When the Adding a class prompt displayed, choose Select an existing class radio button and select CMyex33aView class. Just click Yes button if warning/prompt dialog displayed.

 

 

Winsock, C++ and MFC - Figure 79: Adding new class prompt dialog.

 

Figure 79: Adding new class prompt dialog.

 

Winsock, C++ and MFC - Figure 80: Selecting the existing class.

 

Figure 80: Selecting the existing class.

 

Next, add the following message handlers.

 

ID

Message

Function

IDR_REQUEST

BN_CLICK

OnRequest()

 

Table 28.

 

Winsock, C++ and MFC - Figure 81: Adding message handler to CMyex33aView class.

 

Figure 81: Adding message handler to CMyex33aView class.

 

Next, add the following command, command updates and Windows message handler to the CMyex33aView class.

 

ID

Message map

Function

ID_INTERNET_START_SERVER

Command

OnInternetStartServer()

-

Command Update

OnUpdateInternetStartServer(CCmdUI* pCmdUI)

ID_INTERNET_REQUEST_SOCK

Command

OnInternetRequestSocket()

ID_INTERNET_REQUEST_INET

Command

OnInternetRequestWininet()

ID_INTERNET_STOP_SERVER

Command

OnInternetStopServer()

-

Command Update

OnUpdateInternetStopServer(CCmdUI* pCmdUI)

ID_INTERNET_CONFIGURATION

Command

OnInternetConfiguration()

-

Command Update

OnUpdateInternetConfiguration(CCmdUI* pCmdUI)

ID_EDIT_CLEAR_ALL

Command

OnEditClearAll()

IDR_CONTEXT_MENU

WM_CONTEXTMENU

OnContextMenu(CWnd* pWnd, CPoint point)

 

Table 29.

 

Winsock, C++ and MFC - Figure 82: Adding command, command update and Windows message handler.

 

Figure 82: Adding command, command update and Windows message handler.

 

You can verify the result in Myex33aView.h as shown below.

 

MFC, C++ and Winsock - Source code Listing 24.

 

Listing 24.

 

And in Myex33aView.cpp as shown below.

 

MFC, C++ and Winsock - Source code Listing 25.

 

Listing 25.

 

Next, add the implementation codes to CMyex33aView.cpp. Don’t forget the related header files that need to be included as shown below.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// myex33aView.cpp : implementation of the CMyex33aView class

//

 

#include "stdafx.h"

#include "myex33a.h"

#include "MainFrm.h"

 

#include "myex33aDoc.h"

#include "myex33aView.h"

#include "Utility.h"

#include "Sheetconfig.h"

#include "Blocksock.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

extern CBlockingSocket g_sListen;

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView

 

IMPLEMENT_DYNCREATE(CMyex33aView, CEditView)

 

BEGIN_MESSAGE_MAP(CMyex33aView, CEditView)

       //{{AFX_MSG_MAP(CMyex33aView)

       ON_BN_CLICKED(IDC_REQUEST, OnRequest)

       ON_COMMAND(ID_INTERNET_START_SERVER, OnInternetStartServer)

       ON_UPDATE_COMMAND_UI(ID_INTERNET_START_SERVER, OnUpdateInternetStartServer)

       ON_COMMAND(ID_INTERNET_REQUEST_SOCK, OnInternetRequestSocket)

       ON_COMMAND(ID_INTERNET_REQUEST_INET, OnInternetRequestWininet)

       ON_COMMAND(ID_INTERNET_STOP_SERVER, OnInternetStopServer)

       ON_UPDATE_COMMAND_UI(ID_INTERNET_STOP_SERVER, OnUpdateInternetStopServer)

       ON_COMMAND(ID_INTERNET_CONFIGURATION, OnInternetConfiguration)

       ON_UPDATE_COMMAND_UI(ID_INTERNET_CONFIGURATION, OnUpdateInternetConfiguration)

       ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)

       //}}AFX_MSG_MAP

       ON_WM_CONTEXTMENU()

       // Standard printing commands

       ON_COMMAND(ID_FILE_PRINT, CEditView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_DIRECT, CEditView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_PREVIEW, CEditView::OnFilePrintPreview)

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView construction/destruction

 

CMyex33aView::CMyex33aView()

{     // TODO: add construction code here  }

 

CMyex33aView::~CMyex33aView()

{  }

 

BOOL CMyex33aView::PreCreateWindow(CREATESTRUCT& cs)

{

       BOOL bPreCreated = CEditView::PreCreateWindow(cs);

       cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL);       // Enable word-wrapping

       cs.style |= ES_READONLY;

       return bPreCreated;

}

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView drawing

 

void CMyex33aView::OnDraw(CDC* pDC)

{

       CMyex33aDoc* pDoc = GetDocument();

       ASSERT_VALID(pDoc);

       // TODO: add draw code for native data here

}

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView printing

 

BOOL CMyex33aView::OnPreparePrinting(CPrintInfo* pInfo)

{

       // default CEditView preparation

       return CEditView::OnPreparePrinting(pInfo);

}

 

void CMyex33aView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)

{

       // Default CEditView begin printing.

       CEditView::OnBeginPrinting(pDC, pInfo);

}

 

void CMyex33aView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)

{

       // Default CEditView end printing

       CEditView::OnEndPrinting(pDC, pInfo);

}

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView diagnostics

 

#ifdef _DEBUG

void CMyex33aView::AssertValid() const

{

       CEditView::AssertValid();

}

 

void CMyex33aView::Dump(CDumpContext& dc) const

{

       CEditView::Dump(dc);

}

 

CMyex33aDoc* CMyex33aView::GetDocument() // non-debug version is inline

{

       ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyex33aDoc)));

       return (CMyex33aDoc*)m_pDocument;

}

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CMyex33aView message handlers

 

void CMyex33aView::OnInternetStartServer()

{

       try {

              CSockAddr saServer;

              if(g_strIPServer.IsEmpty()) { // first or only IP

                     saServer = CSockAddr(INADDR_ANY, (USHORT) g_nPortServer);

              }

              else { // if our computer has multiple IP addresses...

                     saServer = CSockAddr(g_strIPServer, (USHORT) g_nPortServer);

              }

              g_sListen.Create();

              g_sListen.Bind(saServer);

              g_sListen.Listen();// start listening

              g_bListening = TRUE;

              g_nConnection = 0;

              AfxBeginThread(ServerThreadProc, GetSafeHwnd(), THREAD_PRIORITY_NORMAL);

       }

       catch(CBlockingSocketException* e) {

              g_sListen.Cleanup();

              LogBlockingSocketException(GetSafeHwnd(), "VIEW:", e);

              e->Delete();

       }

}

 

void CMyex33aView::OnUpdateInternetStartServer(CCmdUI* pCmdUI)

{

       pCmdUI->Enable(!g_bListening);

}

 

void CMyex33aView::OnInternetRequestSocket()

{

       AfxBeginThread(ClientSocketThreadProc, GetSafeHwnd(), THREAD_PRIORITY_NORMAL);

}

 

void CMyex33aView::OnInternetRequestWininet()

{

       AfxBeginThread(ClientWinInetThreadProc, GetSafeHwnd(), THREAD_PRIORITY_NORMAL);

}

 

void CMyex33aView::OnInternetStopServer()

{

       try {

              if(g_bListening) {

                     g_sListen.Close();

              }

       }

       catch(CBlockingSocketException* e) {

              LogBlockingSocketException(GetSafeHwnd(), "VIEW:", e);

              e->Delete();

       }

}

 

void CMyex33aView::OnUpdateInternetStopServer(CCmdUI* pCmdUI)

{

       pCmdUI->Enable(g_bListening);

}

 

void CMyex33aView::OnInternetConfiguration()

{

       CSheetConfig sh("Configuration");

       sh.m_pageServer.m_strDirect = g_strDirect;

       sh.m_pageServer.m_strDefault = g_strDefault;

       sh.m_pageServer.m_nPortServer = g_nPortServer;

       sh.m_pageClient.m_strServerIP = g_strServerIP;

       sh.m_pageClient.m_nPort = g_nPort;

       sh.m_pageClient.m_strServerName = g_strServerName;

       sh.m_pageClient.m_strFile = g_strFile;

       sh.m_pageClient.m_strProxy = g_strProxy;

       sh.m_pageClient.m_bUseProxy = g_bUseProxy;

       sh.m_pageAdv.m_strIPClient = g_strIPClient;

       sh.m_pageAdv.m_strIPServer = g_strIPServer;

       if(sh.DoModal() == IDOK) {

              g_strDirect = sh.m_pageServer.m_strDirect;

              g_strDefault = sh.m_pageServer.m_strDefault;

              g_nPortServer = sh.m_pageServer.m_nPortServer;

              g_strServerIP = sh.m_pageClient.m_strServerIP;

              g_nPort = sh.m_pageClient.m_nPort;

              g_strServerName = sh.m_pageClient.m_strServerName;

              if(sh.m_pageClient.m_strFile.IsEmpty()) {

                     g_strFile = "/";

              }

              else {

                     g_strFile = sh.m_pageClient.m_strFile;

              }

              g_strProxy = sh.m_pageClient.m_strProxy;

              g_bUseProxy = sh.m_pageClient.m_bUseProxy;

              g_strIPClient = sh.m_pageAdv.m_strIPClient;

              g_strIPServer = sh.m_pageAdv.m_strIPServer;

              if(!g_strIPClient.IsEmpty() && g_bUseProxy) {

                     AfxMessageBox("Warning: you can't assign a client IP address if you are using a proxy server");

              }

              if(!g_strServerIP.IsEmpty() && g_bUseProxy) {

                     AfxMessageBox("Warning: you must specify the server by name if you are using a proxy server");

              }

              if(g_strServerIP.IsEmpty() && g_strServerName.IsEmpty()) {

                     AfxMessageBox("Warning: you must specify either a server name or a server IP address");

              }

              if(!g_strServerIP.IsEmpty() && !g_strServerName.IsEmpty()) {

                     AfxMessageBox("Warning: you cannot specify both a server name and a server IP address");

              }

              ::SetCurrentDirectory(g_strDirect);

       }

}

 

void CMyex33aView::OnUpdateInternetConfiguration(CCmdUI* pCmdUI)

{

       pCmdUI->Enable(!g_bListening);

}

 

void CMyex33aView::OnEditClearAll()

{

       SetWindowText("");

}

 

void CMyex33aView::OnRequest()

{

       CWnd& rBar = ((CMainFrame*) AfxGetApp()->m_pMainWnd)->m_wndDialogBar;

       // g_strURL: thread sync?

       rBar.GetDlgItemText(IDC_URL, g_strURL);

       TRACE("CMyex33aView::OnRequest -- URL = %s\n", (const char*) g_strURL);

       AfxBeginThread(ClientUrlThreadProc, GetSafeHwnd(), THREAD_PRIORITY_NORMAL);

}

 

void CMyex33aView::OnContextMenu(CWnd* pWnd, CPoint point)

{

       // clear-all menu activated on right button

       CMenu menu;

       menu.LoadMenu(IDR_CONTEXT_MENU);

       menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,

              point.x, point.y, this);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 26.

 

 

Continue on next Module...

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | C++, MFC, Winsock & WinInet 6 | C++, MFC, Winsock & WinInet 8 | Download | Site Index |