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.
|
|
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.
Listing 3.
We have to add the ID_INDICATOR_LISTENING status indicator to the resource symbol manually. Select View Resource Symbols menu.
Figure 69: Viewing, adding or modifying resource symbols. |
Click the New button and add the status indicator as shown below.

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.

Figure 71: Adding new string to string table.
Add the following string.

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

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;

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);

Listing 6.
Add the message map for the declared status bar indicator in MainFrm.cpp.
ON_UPDATE_COMMAND_UI(ID_INDICATOR_LISTENING, OnUpdateListening)

Listing 7.
Then add the implementation code at the end of the MainFrm.cpp.
void CMainFrame::OnUpdateListening(CCmdUI* pCmdUI)
{
pCmdUI->Enable(g_bListening);
}

Listing 8.
Next, add the following #include directive.
#include "Utility.h"

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.

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);
}

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

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"
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);
}

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:
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Win32 process, thread and synchronization story can be found starting from Module R.
MSDN MFC 9.0 class library online documentation - latest version.
Unicode and Multibyte character set: Story and program examples.