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


 

 

 

 

 

 

C++, MFC, Winsock and WinInet Part 5

 

 

 

 

 

 

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. Building MYEX33A From Scratch - Continue...

  2. The Coding Part

 

 

The Coding Part

 

Add the following header files in StdAfx.h. You can use winsock2.h, Winsock version 2. The library for the older Winsock (ws_32.lib) cannot be found in Tenouk’s Visual C++ 6.0. Later on, you need to add the ws2_32.lib (Winsock 2) to your project.

 

#include <afxinet.h>    // MFC WinInet

#include <afxmt.h>      // MFC multi-threading classes

#include <winsock.h>    // Winsock

 

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

 

Listing 3.

 

We have to add the ID_INDICATOR_LISTENING status indicator to the resource symbol manually. Select View Resource Symbols menu.

 

Winsock, C++ and MFC - Figure 69: Viewing, adding or modifying resource symbols.

 

Figure 69: Viewing, adding or modifying resource symbols.

 

Click the New button and add the status indicator as shown below.

 

Winsock, C++ and MFC - Figure 70: Adding new resource symbol.

 

Figure 70: Adding new resource symbol.

 

Add string in string table. In ResourceView, double click the String Table sub directory. Right click the area under IDR_MAINFRAME and select New String.

 

Winsock, C++ and MFC - Figure 71: Adding new string to string table.

 

Figure 71: Adding new string to string table.

 

Add the following string.

 

Winsock, C++ and MFC - Figure 72: New string information.

 

Figure 72: New string information.

 

Then we are ready to use the status bar indicator. Add the following status bar indicator with separator in MainFrm.cpp.

 

      ID_SEPARATOR,           // Wininet status

      ID_INDICATOR_LISTENING, // server listening

 

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

 

Listing 4.

 

Change the following code in MainFrm.h file. Later, we need to access those variables.

 

protected:  // control bar embedded members

      CStatusBar  m_wndStatusBar;

      CToolBar    m_wndToolBar;

 

to

 

public:  // control bar embedded members

      CStatusBar  m_wndStatusBar;

      CDialogBar  m_wndDialogBar;

protected:

      CToolBar    m_wndToolBar;

 

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

 

Listing 5.

 

The ID_INDICATOR_LISTENING cannot be found in the ClassWizard (though the ClassWizard database has been rebuilt) so we need to add the code manually. Add the following indicator message handler declaration, command and command update, in MainFrm.h. Add the code just before the DECLARE_MESSAGE_MAP().

 

afx_msg void OnUpdateListening(CCmdUI* pCmdUI);

 

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

 

Listing 6.

 

Add the message map for the declared status bar indicator in MainFrm.cpp.

 

ON_UPDATE_COMMAND_UI(ID_INDICATOR_LISTENING, OnUpdateListening)

 

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

 

Listing 7.

 

Then add the implementation code at the end of the MainFrm.cpp.

void CMainFrame::OnUpdateListening(CCmdUI* pCmdUI)

{

      pCmdUI->Enable(g_bListening);

}

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

 

Listing 8.

 

Next, add the following #include directive.

 

#include "Utility.h"

 

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

 

Listing 9.

 

Add/modify the OnCreate() as shown below.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

              return -1;

       if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

       {

              TRACE0("Failed to create toolbar\n");

              return -1;      // fail to create

       }

 

       if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))

       {

              TRACE0("Failed to create status bar\n");

              return -1;      // fail to create

       }

 

       // TODO: Remove this if you don't want tool tips or a resizable toolbar

       m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

 

       if (!m_wndDialogBar.Create(this, IDD_DIALOGBAR, CBRS_TOP, 0xE810))

       {

              TRACE0("Failed to create dialog bar\n");

              return -1;      // fail to create

       }

       m_wndDialogBar.SetDlgItemText(IDC_URL, g_strURL);

       return 0;

}

 

Listing 10.

 

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

 

Listing 11.

 

And the PreCreateWindow().

 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

      // TODO: Modify the Window class or styles here by modifying

      //  the CREATESTRUCT cs

      return CFrameWnd::PreCreateWindow(cs);

}

 

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

 

Listing 12.

 

Using ClassWizard, add/override ExitInstance() and OnIdle() to CMyex33aApp class.

 

Winsock, C++ and MFC - Figure 73: Adding/overriding message handler.

 

Figure 73: Adding/overriding message handler.

 

Click the Edit Code button, add the following #include directive to myex33a.cpp.

 

#include "Utility.h"

#include "Blocksock.h"

 

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

 

Listing 13.

 

 

Edit myex33a.cpp as shown below.

 

// myex33a.cpp : Defines the class behaviors for the application.

//

 

#include "stdafx.h"

#include "myex33a.h"

 

#include "MainFrm.h"

#include "myex33aDoc.h"

#include "myex33aView.h"

#include "Utility.h"

#include "Blocksock.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

extern CBlockingSocket g_sListen;

 

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

// CMyex33aApp

 

BEGIN_MESSAGE_MAP(CMyex33aApp, CWinApp)

       //{{AFX_MSG_MAP(CMyex33aApp)

       ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

              // NOTE - the ClassWizard will add and remove mapping macros here.

              //    DO NOT EDIT what you see in these blocks of generated code!

       //}}AFX_MSG_MAP

       // Standard file based document commands

       ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

       ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

       // Standard print setup command

       ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

END_MESSAGE_MAP()

 

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

// CMyex33aApp construction

 

CMyex33aApp::CMyex33aApp()

{

       // TODO: add construction code here,

       // Place all significant initialization in InitInstance

}

 

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

// The one and only CMyex33aApp object

 

CMyex33aApp theApp;

 

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

// CMyex33aApp initialization

 

BOOL CMyex33aApp::InitInstance()

{

       AfxEnableControlContainer();

       // Standard initialization

       // If you are not using these features and wish to reduce the size

       //  of your final executable, you should remove from the following

       //  the specific initialization routines you do not need.

 

#ifdef _AFXDLL

       Enable3dControls();        // Call this when using MFC in a shared DLL

#else

       Enable3dControlsStatic();  // Call this when linking to MFC statically

#endif

 

       // Change the registry key under which our settings are stored.

       // TODO: You should modify this string to be something appropriate

       // such as the name of your company or organization.

       SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 

       LoadStdProfileSettings();  // Load standard INI file options (including MRU)

 

       // Register the application's document templates.  Document templates

       //  serve as the connection between documents, frame windows and views.

       CSingleDocTemplate* pDocTemplate;

       pDocTemplate = new CSingleDocTemplate(

              IDR_MAINFRAME,

              RUNTIME_CLASS(CMyex33aDoc),

              RUNTIME_CLASS(CMainFrame),  // main SDI frame window

              RUNTIME_CLASS(CMyex33aView));

       AddDocTemplate(pDocTemplate);

 

       // Enable DDE Execute open

       EnableShellOpen();

       RegisterShellFileTypes(TRUE);

 

       // Parse command line for standard shell commands, DDE, file open

       CCommandLineInfo cmdInfo;

       ParseCommandLine(cmdInfo);

 

       // Dispatch commands specified on the command line

       if (!ProcessShellCommand(cmdInfo))

              return FALSE;

 

       // socket initialization

       WSADATA wsd;

       VERIFY(WSAStartup(0x0101, &wsd) == 0);

       TRACE("WSAStartup -- min version = %x\n", wsd.wVersion);

       g_hMainWnd = m_pMainWnd->m_hWnd;

 

       return TRUE;

}

 

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

// CAboutDlg dialog used for App About

 

class CAboutDlg : public CDialog

{

public:

       CAboutDlg();

 

// Dialog Data

       //{{AFX_DATA(CAboutDlg)

       enum { IDD = IDD_ABOUTBOX };

       //}}AFX_DATA

 

       // ClassWizard generated virtual function overrides

       //{{AFX_VIRTUAL(CAboutDlg)

       protected:

       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

       //}}AFX_VIRTUAL

 

// Implementation

protected:

       //{{AFX_MSG(CAboutDlg)

              // No message handlers

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

};

 

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

       //{{AFX_DATA_INIT(CAboutDlg)

       //}}AFX_DATA_INIT

}

 

void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

       CDialog::DoDataExchange(pDX);

       //{{AFX_DATA_MAP(CAboutDlg)

       //}}AFX_DATA_MAP

}

 

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

       //{{AFX_MSG_MAP(CAboutDlg)

              // No message handlers

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

// App command to run the dialog

void CMyex33aApp::OnAppAbout()

{

       CAboutDlg aboutDlg;

       aboutDlg.DoModal();

}

 

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

// CMyex33aApp message handlers

 

int CMyex33aApp::ExitInstance()

{

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

try {

              if(g_bListening) {  

                     g_sListen.Close();

                     Sleep(30); // wait for thread to exit

              }

              VERIFY(WSACleanup() != SOCKET_ERROR);

       }

       catch(CUserException* e) {

              TRACE("exception in CSock01App::ExitInstance\n");

              e->Delete();

       }

       return CWinApp::ExitInstance();

}

 

BOOL CMyex33aApp::OnIdle(LONG lCount)

{

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

       CStatusBar* pStatus = &((CMainFrame*) m_pMainWnd)->m_wndStatusBar;

       g_csStatus.Lock(); // blocking call in main thread -- could be dangerous

         pStatus->SetPaneText(1, g_pchStatus);

       g_csStatus.Unlock();

       return CWinApp::OnIdle(lCount);

}

 

 

Listing 14.

 

Add/modify the Sheetconfig.cpp code. Add the following code to the second constructor as shown below.

 

CSheetConfig::CSheetConfig(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage):CPropertySheet(pszCaption, pParentWnd, iSelectPage)

{

      AddPage(&m_pageClient);

      AddPage(&m_pageServer);

      AddPage(&m_pageAdv);

}

 

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

 

Listing 15.

 

Add/modify the Blocksock.h code as shown below.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Blocksock.h: interface for the CSockAddr class.

//

// needs winsock.h in the precompiled headers, add ws2_32.lib to the

// project later on...

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

 

#if !defined(AFX_BLOCKSOCK_H__68C3054C_1A67_4CAE_8B43_5BEF5CFA1C19__INCLUDED_)

#define AFX_BLOCKSOCK_H__68C3054C_1A67_4CAE_8B43_5BEF5CFA1C19__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

typedef const struct sockaddr* LPCSOCKADDR;

 

class CBlockingSocketException : public CException

{

       DECLARE_DYNAMIC(CBlockingSocketException)

public:

// Constructor

       CBlockingSocketException(char* pchMessage);

 

public:

       ~CBlockingSocketException() {}

       virtual BOOL GetErrorMessage(LPTSTR lpstrError, UINT nMaxError, PUINT pnHelpContext = NULL);

private:

       int m_nError;

       CString m_strMessage;

};

 

extern void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe);

 

class CSockAddr : public sockaddr_in {

public:

       // constructors

       CSockAddr()

              { sin_family = AF_INET;

                sin_port = 0;

                // Default

                sin_addr.s_addr = 0; }

       CSockAddr(const SOCKADDR& sa) { memcpy(this, &sa, sizeof(SOCKADDR)); }

       CSockAddr(const SOCKADDR_IN& sin) { memcpy(this, &sin, sizeof(SOCKADDR_IN)); }

       // parms are host byte ordered

       CSockAddr(const ULONG ulAddr, const USHORT ushPort = 0)

              { sin_family = AF_INET;

                sin_port = htons(ushPort);

             sin_addr.s_addr = htonl(ulAddr); }

       // dotted IP addr string

       CSockAddr(const char* pchIP, const USHORT ushPort = 0)

              { sin_family = AF_INET;

                sin_port = htons(ushPort);

                // already network byte ordered

                sin_addr.s_addr = inet_addr(pchIP); }

       // Return the address in dotted-decimal format

       CString DottedDecimal()

              // constructs a new CString object

              { return inet_ntoa(sin_addr); }

       // Get port and address (even though they're public)

       USHORT Port() const

              { return ntohs(sin_port); }

       ULONG IPAddr() const

              { return ntohl(sin_addr.s_addr); }

       // operators added for efficiency

       const CSockAddr& operator=(const SOCKADDR& sa)

              { memcpy(this, &sa, sizeof(SOCKADDR));

                return *this; }

       const CSockAddr& operator=(const SOCKADDR_IN& sin)

              { memcpy(this, &sin, sizeof(SOCKADDR_IN));

                return *this; }

       operator SOCKADDR()

              { return *((LPSOCKADDR) this); }

       operator LPSOCKADDR()

              { return (LPSOCKADDR) this; }

       operator LPSOCKADDR_IN()

              { return (LPSOCKADDR_IN) this; }

};

 

// member functions truly block and must not be used in UI threads

// use this class as an alternative to the MFC CSocket class

class CBlockingSocket : public CObject

{

       DECLARE_DYNAMIC(CBlockingSocket)

public:

       SOCKET m_hSocket;

       CBlockingSocket() { m_hSocket = NULL; }

       void Cleanup();

       void Create(int nType = SOCK_STREAM);

       void Close();

       void Bind(LPCSOCKADDR psa);

       void Listen();

       void Connect(LPCSOCKADDR psa);

       BOOL Accept(CBlockingSocket& s, LPSOCKADDR psa);

       int Send(const char* pch, const int nSize, const int nSecs);

       int Write(const char* pch, const int nSize, const int nSecs);

       int Receive(char* pch, const int nSize, const int nSecs);

       int SendDatagram(const char* pch, const int nSize, LPCSOCKADDR psa, const int nSecs);

       int ReceiveDatagram(char* pch, const int nSize, LPSOCKADDR psa, const int nSecs);

       void GetPeerAddr(LPSOCKADDR psa);

       void GetSockAddr(LPSOCKADDR psa);

       static CSockAddr GetHostByName(const char* pchName, const USHORT ushPort = 0);

       static const char* GetHostByAddr(LPCSOCKADDR psa);

       operator SOCKET()

              { return m_hSocket; }

};

 

class CHttpBlockingSocket : public CBlockingSocket

{

public:

       DECLARE_DYNAMIC(CHttpBlockingSocket)

       // max receive buffer size (> hdr line length)

       enum {nSizeRecv = 10000};

       CHttpBlockingSocket();

       ~CHttpBlockingSocket();

       int ReadHttpHeaderLine(char* pch, const int nSize, const int nSecs);

       int ReadHttpResponse(char* pch, const int nSize, const int nSecs);

private:

       // read buffer

       char* m_pReadBuf;

       // number of bytes in the read buffer

       int m_nReadBuf;

};

 

#endif // !defined(AFX_BLOCKSOCK_H__68C3054C_1A67_4CAE_8B43_5BEF5CFA1C19__INCLUDED_)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 16.

 

 

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 4 | C++, MFC, Winsock & WinInet 6 | Download | Site Index |