The Power of Visual C++ - Case Study II

A lot of criticism has been heaped upon Microsoft from many quarters and for many reasons, some of it justified, some of it not. This page illustrates something that Microsoft has done very well, tools for programmers, and in particular Visual C++. (Click here for a more detailed discussion of these issues.) The development of such tools was not selfless, but they provide facilities for anyone to use and are quite useful for algorithm develops who want to test ideas quickly without having to write a lot of code. I use Visual C++ a lot to test ideas for image analysis algorithms but in order to illustrate the power of the tool I chose a very simple algorithm, the one that calculates the years for which the calendar of a given year is repeated. (For such a simple application AWK or PERL might have the job equally well, but these languages cannot handle more challenging task such as those encounterd in image analysis.) The program generates the display below

The user types in the year (in this case 1991) and then clicks the "Update" button and the program returns with the list of the years that have the same calendar as well as the date of the week of January 1.

The program has about 380 substantive lines of code, but most of them are generated automatically by Visual C++. The programmer starts by using an interactive tool to draw the dialogue box shown and to link pieces of code with the action of the buttons and the text entry boxes. The lines of code that have to be written by the programmer are shown in red, 55 of them, or about 15% of the total. A few more lines (about 10) have been produced by Visual C++ in response to programmers actions through interactive graphics. These are shown in dark green. The rest of the code is shown in orange. The program icon has been drawn with an icon editor and it is not really required. Visual C++ provides a default icon. (I wrote this program over four years ago, in December of 2001, and the labeling of the lines may be a little off in some cases.)

In addition, Visual C++ provides excellent debugging facilities.

While the purpose of this page is to illustrate how little code the programmer has to write, if you want to take a closer look at this particular (trivial) application click here to download the executable file of the program (20 Kbytes). You can copy the source from the listing below or ask me for the project directory.

The automatically generated (and bizzare looking) code may loo intimidating at first, but one learns to ignore it,

Theo Pavlidis (t.pavlidis AT ieee DOT org)

February 19, 2005

Calendar Repeats Calculator - Code Listing

stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes
//	year.pch will be the pre-compiled header
//	stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"
stdafx.h
// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__14F9A868_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
#define AFX_STDAFX_H__14F9A868_FC65_11D5_8F40_DFCBC813A245__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdisp.h>        // MFC Automation classes
#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common 

Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>			// MFC support for Windows Common 

Controls
#endif // _AFX_NO_AFXCMN_SUPPORT


//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the 

previous line.

#endif // !defined(AFX_STDAFX_H__14F9A868_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)

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

#include "stdafx.h"
#include "year.h"
#include "yearDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CYearApp

BEGIN_MESSAGE_MAP(CYearApp, CWinApp)
	//{{AFX_MSG_MAP(CYearApp)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG
	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CYearApp construction

CYearApp::CYearApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CYearApp object

CYearApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CYearApp initialization

BOOL CYearApp::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

	CYearDlg dlg;
	m_pMainWnd = &dlg;
	int nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		TRACE("%d\n", dlg.m_year);
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}
year.h
// year.h : main header file for the YEAR application
//

#if !defined(AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
#define AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef __AFXWIN_H__
	#error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h"		// main symbols

/////////////////////////////////////////////////////////////////////////////
// CYearApp:
// See year.cpp for the implementation of this class

//

class CYearApp : public CWinApp
{
public:
	CYearApp();

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CYearApp)
	public:
	virtual BOOL InitInstance();
	//}}AFX_VIRTUAL

// Implementation

	//{{AFX_MSG(CYearApp)
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};


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

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the 

previous line.

#endif // !defined(AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
year.rc
// year.h : main header file for the YEAR application
//

#if !defined(AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
#define AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef __AFXWIN_H__
	#error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h"		// main symbols

/////////////////////////////////////////////////////////////////////////////
// CYearApp:
// See year.cpp for the implementation of this class
//

class CYearApp : public CWinApp
{
public:
	CYearApp();

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CYearApp)
	public:
	virtual BOOL InitInstance();
	//}}AFX_VIRTUAL

// Implementation

	//{{AFX_MSG(CYearApp)
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};


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

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the 

previous line.

#endif // !defined(AFX_YEAR_H__14F9A864_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
yearDlg.cpp
// yearDlg.cpp : implementation file
//

#include "stdafx.h"
#include "year.h"
#include "yearDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// 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)
	//}}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()

/////////////////////////////////////////////////////////////////////////////
// CYearDlg dialog

CYearDlg::CYearDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CYearDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CYearDlg)
	m_year = 0;
	m_repeats = _T("");
	m_day = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CYearDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CYearDlg)
	DDX_Text(pDX, IDC_EDIT_YEAR, m_year);
	DDV_MinMaxInt(pDX, m_year, 1801, 2200);
	DDX_Text(pDX, IDC_EDIT_RESULT, m_repeats);
	DDX_Text(pDX, IDC_EDIT_DAY, m_day);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CYearDlg, CDialog)
	//{{AFX_MSG_MAP(CYearDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_RPT, OnButtonRepeat)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

static void YearTable(Year T[], int tabSize)
{
	int k;
	for(int i=1; i<tabSize; i++) {
		T[i].number = T[i-1].number+1;
		T[i].first  = T[i-1].first+1;
		if(T[i-1].leap==1) T[i].first++;
		T[i].first = T[i].first%7;
		if(T[i].number%100==0) k = T[i].number%400;
		else k = T[i].number%4;
		if(k==0) T[i].leap = TRUE;
		else T[i].leap = FALSE;
	}
}

static enum { sun, mon, tue, wed, thu, fri, sta, qqq };

static char * weekDay[8] = {"Sun", "Mon", "Tue", 

"Wed", "Thu", "Fri", "Sat", "???"};

/////////////////////////////////////////////////////////////////////////////
// CYearDlg message handlers

BOOL CYearDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_Y[0].set(1801, thu, 0);	// base year 1801 starting on Thursday
	YearTable(m_Y, TAB_SIZE);
	m_year = 1991;
	Repeats();
	Day();
	UpdateData(FALSE);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CYearDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CYearDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CYearDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CYearDlg::Day()
{
	int i;
	for(i=0; i<TAB_SIZE; i++) if(m_year==m_Y[i].number) break;
	if(i<TAB_SIZE) m_day = weekDay[m_Y[i].first];
	else m_day = "???";
}

void CYearDlg::Repeats()
{
	int i, j;
	CString tmp;
	m_repeats = "";
	for(i=0; i<TAB_SIZE; i++) if(m_year==m_Y[i].number) break;
	if(i<TAB_SIZE) {
		for(j=i+1; j<TAB_SIZE; j++) {
			if(m_Y[j].sameAs(&m_Y[i])) {
				tmp.Format("%d, ", m_Y[j].number);
				m_repeats += tmp;
			}
			if(m_Y[j].number >= m_year+100) break;
		}
	}
	else m_repeats = "No repeats";
}

void CYearDlg::OnButtonRepeat() 
{
	UpdateData(TRUE);
	Repeats();
	Day();
	UpdateData(FALSE);
}
yearDlg.h
// yearDlg.h : header file
//

#if !defined(AFX_YEARDLG_H__14F9A866_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
#define AFX_YEARDLG_H__14F9A866_FC65_11D5_8F40_DFCBC813A245__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// Class use for calendar calulations
class Year
{
public:
	int number;
	int first;
	BOOL leap;

	void set(int n, int f, BOOL l) { number = n; first = f; leap = l; }

	BOOL sameAs(Year *a) {
		if(a->first == first && a->leap == leap) return TRUE;
		else return FALSE;
	}
};

#define TAB_SIZE 400

// CYearDlg dialog

class CYearDlg : public CDialog
{
// Construction
public:
	CYearDlg(CWnd* pParent = NULL);	// standard constructor
	void Day();
	void Repeats();

// Dialog Data
	//{{AFX_DATA(CYearDlg)
	enum { IDD = IDD_YEAR_DIALOG };
	int		m_year;
	CString	m_repeats;
	CString	m_day;
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CYearDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	Year m_Y[TAB_SIZE];
	HICON m_hIcon;

	// Generated message map functions
	//{{AFX_MSG(CYearDlg)
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void OnButtonRepeat();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_YEARDLG_H__14F9A866_FC65_11D5_8F40_DFCBC813A245__INCLUDED_)
 
theopavlidis.com Site Map