Click here to Skip to main content
15,886,798 members
Articles / Programming Languages / C++

Using CodeProject - A Day In the Life of an Application - Part 3 of 5

Rate me:
Please Sign up or sign in to vote.
4.63/5 (20 votes)
27 Jan 2007CPOL14 min read 43.3K   436   17  
The right way to code using CodeProject for occasional support
<html><body>
<h2>Introduction</h2>

<p>This article series is another in my series of "code we really use" articles. 
There is no unneccesary discussion about theory, no expounding on technique, and 
no chest-thumping because I thought it all up myself. It's just a bunch of stuff 
I did to stand one of our applications up. MOST of the stuff in this article is 
based on other code that I got from CodeProject, and what follows describes the 
basis for a project I am actively developing and how I integrated articles and 
help I got from CodeProject.</p>

<h2>Rant</h2>
<p>I've been a member on CodeProject for over six years (as of this writing), 
and I've come to discover some disturbing trends regarding articles.  First, 
article authors tend to post an article and as time goes by, the author 
essentially abandons the article and people posting questions are greeted with 
either silence from the author, or a response that says something like "I don't 
code in this/that language any more".  Let's face it, you can't blame them. Many 
of the articles I use are three or four years old, and I understand that 
programmers need to move on and that often means completely abandoning older 
code.</p>

<p>On the other side of the fence are the people that download the source code 
and samples associated with a given article. Many times, someone will post a 
question in an article that has absolutely nothing to do with the article itself, 
but the subject will be related to a certain aspect of the article.  As an 
example, I posted an article about dynamically building a menu.  Recently, someone 
posted a message in that article that asked about adding winhelp to their 
dynamically built menu.  Then there's the people that encounter an issue (real 
or imagined) with an article, and expect someone else to fix it for them.  These
people really annoy me. Afterall, we're all supposed to be programmers here.</p>

<h2>So, What's the Point of This Article?</h2>

<p>The entire point of this article is to illustrate real-world use of 
code-snippets, classes and techniques I gleaned from CodeProject over the last 
six years, including work-arounds to fit code into my sometimes bizarre 
requirements. Many times, I'll use the VC++ forum to ask a question that will 
help me understand an article, or massage the article's code for my own use.

<h2>Assumptions</h2>

<p>The original version of this article started out as a kind of detailed 
tutorial describing how to use the IDE, and other inane items like that. After a 
while, I realized this created a huge amount of overhead as far as the article's 
weight was concerned.  Beyond that, I was starting to become bored with the whole 
thing and I could plainly see that the quality of my writing was beginning to 
suffer as a result.</p>

<p>The only solution was to start over and make the assumption that you, the 
user, have a working knowledge of the VS2005 IDE, especially as it relates to 
creating VC++/MFC applications.  This way, we can talk more about the important 
stuff than suffer through stuff you should already know.</p>

<h2>Other Stuff</h2>

<p>Sprinkled throughout the article, you'll find "Coding Notes". These simply 
describe the way I do things when coding, and why I do them. They are certainly 
not requirements by any stretch of the imagination, but they often concern code 
readability and maintainability.  I'm sure that many of you have your own ways 
of doing things, but please keep comments regarding these issues to a minimum. 
Afterall, this article is not about style.</p>

<p>The total process of coding the complete demo app requires just an hour or 
so (if you know all the steps ahead of time). Writing this article series has 
taken me DAYS, so don't be put off by it's length.</p>

<p>The html and images for this article is included in the project download, but 
doesn't include the pretty CodeProject formatting. If you can mentally handle 
that, you can simply refer to this .HTML file and get on with your programming.
</p>

<p>Finally, I know there are folks out there that vote my stuff a 1 simply 
because it's, well, something I wrote. I request that you be mature and 
professional and restrict your politics to the soapbox when voting. Remember, 
you're voting on the article, not on the author.</p>

<h2>My Real-World Application</h2>

<p>The application allows a hospital emergency department to monitor the status 
of patients and beds in the Emergency Room.  This application is broken into four 
components:</p>

<ul><li>A "big board" application that allows little user interaction 
(there's no menu, but several accelerator keys are available) and is displayed on 
a 50-inch plasma screen suspened from the ceiling.</li></ul>

<ul><li>A "client" application that allows multiple users to manipulate the data 
on their own screens.  Cheanges made in the client app are eventually updated to 
the "big board".</li></ul>

<ul><li>A data access MFC extension DLL This DLL holds the entire database access 
capabilities.</li></ul>

<ul><li>A view manager MFC extension DLL. This is where all of the dialog boxes 
and views are contained.</li></ul>

<ul><li>The whole thing is tied to an Oracle database.</li></ul>

<p>Here are some screen shots of the actual application we created. Keep in mind 
that a lot of the visual elements you might notice are dictated by requirements, 
and may not necessarily be the way I would have preferred to accomplish certain 
aspects of the code.  Knowing this, resist the urge to critique perceived design 
aspects.</p>

<h2>Our Sample Application</h2>

Building our sample application provided me with an opportunity to re-factor 
much of the app, ommitting code that is no longer used in the app and to 
re-organize the code so that it's easier to maintain. The sample app 
illustrates the following design elements:</p>

<ul><li>A multi-project solution.</li></ul>
<ul><li>MFC application using shared MFC DLLs</li></ul>
<ul><li>SDI application using the MFC document/view architecture</li></ul>
<ul><li>A horizontal custom flat-bar splitter window.</li></ul>
<ul><li>View-switching in one of the splitter panes. </li></ul>
<ul><li>Gives example of using the views in the app itself AND using the 
views from an extension DLL.</li></ul>
<ul><li>The switchable views include a grid view, a formview, and a GDI 
drawing view</li></ul>
<ul><li>Removing menus from an application</li></ul>
<ul><li>Creating a timer thread that controls one or more timers</li></ul>
<ul><li>Creating worker threads that respond to timer events posted by the 
timer thread
</li></ul>
<ul><li>Loading/saving program settings in a XML file</li></ul>


<h2>Gathering The Components</h2>

<p>The sample doesn't include all of the code associated with the articles I 
used, but instead only includes the parts of the code that I implemented in my 
own project.</p>

includes all of the code I downloaded from CodeProject, but for 
those who want to follow the same steps I did, or if you just want to organize 
your source code folders differently than I did, here's a list of the articles 
used to create the project:</p>

<ul>
<li><a href="http://www.codeproject.com/miscctrl/gridctrl.asp"				target="top">MFC Grid Control</a>, by Chris Maunder</li>
<li><a href="http://www.codeproject.com/miscctrl/pptooltip.asp"				target="top">CPPToolTip</a>, by  Eugene Pustovoyt</li>
<li><a href="http://www.codeproject.com/splitter/flatsplitter.asp"			target="top">A Flat Splitter Window</a>, by Marc Richarme</li>
<li><a href="http://www.codeproject.com/splitter/DanCMultiViewSplitter.asp"	target="top">Unlimited number of switchable views within a Splitter window</a>, by Dan Clark</li>
<li><a href="http://www.codeproject.com/threads/cthread.asp					target="top">CThread - a Worker Thread wrapper class</a>, by Dominik Filipp.</li>
<li><a href="http://www.codeproject.com/statusbar/ExtStatusControlBar.asp	target="top">CExtStatusControlBar</a>, by Dmitriy Yakovlev</li>
<li><a href="http://www.codeproject.com/file/cxmlprofile.asp"				target="top">CXMLProfile - Easy XML Profiles for applications</a>, by Emilio Guijarro.</li>
</ul>

<p>Generally, I put code from CodeProject into a root-level project folder called 
"CodeProject" (as I've done in these articles) so that it's easy to a) see what 
code I'm using that's not mine, and b) update that code if the author releases 
new stuff. I realize that most of you probably have your own ways to do things, 
so it should be fairly easy to rearrange things to your liking.</p>

<p>I'm a firm believer in using the "Additional include directories" 
setting in the project's properties, so if you move things within the sample, 
remember to remove and re-add the files in the project, and then change both the 
debug and release "Addition include directories" property before re-compiling. 
If I derive new classes from CodeProject stuff, I generally just put the 
derived class files into the project's folder.</p>


<h2>Getting Started - Creating A Solution</h2>

<p>First, we need to create a new solution. Why? Because we will be creating a 
number of projects that are related to each other and it's simply more 
convenient to have them all bundled inside a solution than to have to deal with 
several separate projects. Use "SDIMultiSplit" for the solution name.</p>

<p>Next, we add a new project to the solution.  Since we're talking about VC++ 
and MFC here, that's the kind of project we need to add.  Here's a series of 
screen shots showing the settings you need to use when creating the project.</p>

<p><center><img border="1" src="create_app1_02.png"><br /><br />
<img border="1" src="create_app1_03.png"><br /><br />
<img border="1" src="create_app1_04.png"><br /><br />
<img border="1" src="create_app1_05.png"><br /><br />
<img border="1" src="create_app1_06.png"><br /><br />
<img border="1" src="create_app1_07.png"><br /><br />
<img border="1" src="create_app1_08.png"><br /><br />
<img border="1" src="create_app1_09.png"></center></p>

<p>Kinda boring, but we're about to fix that. We're ready to start adding the 
fun stuff.</p>

<h2>Making The View Interesting</h2>

<p>Since we already have a view graciously provided by the app wizard, we'll 
make it do something more interesting than just show up as a big white box. 
Follow these steps.</p>

<h3>Adding The MFC Grid Control To The Project</h3>

<ul><li>If you don't already have it, go download the 
<a href="http://www.codeproject.com/miscctrl/gridctrl.asp" target="top">MFC 
Grid Control</a>.  You only need the "source" (99k download). I'm using 
version 2.25, but v2.26 beta is also available.  While you're there, you might 
want to browse the article for helpful hints on how to "make it go". The article 
is a little sparse on examples, but a sample project has been provided that 
illustrates some of the more intersting features.  It's one of the most highly 
voted articles (790 votes and counting as of this writing) and it's got a 4.81 
rating.</li></ul>

<ul><li>Due to it's file-count and complexity, we're going to put the grid control 
source into its own folder. Create a new folder in your solution folder called 
<code>MFCGridControl_2-25</code>.  Another reason to do this is so that you can  
easily replace the 2.25 code with the newer 2.26 code without jeapordizing a 
working codebase. Un-ZIP the file to this new folder.</li></ul>

<ul><li>Before we do anything else, there's a small bug that needs to be fixed. While 
trying to have my parent view class respond to notification messages from the 
grid control, I found that GVN_ENDLABELEDIT was not always being passed up to 
the parent view.  The problem was that if you started to edit a cell, and didn't 
change anything, and then stopped editing, the grid control wouldn't send the 
GVN_ENDLABELEDIT message because the contents of the cell didn't change. I fixed 
it by replacing the <code>OnEndEditCell</code> function in <code>GridCtrl.cpp</code> 
with this a slightly modified one. You're going to need this fix, so here's the new 
version of the function:

<pre>
void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
{
/*
	// this is the original version of the function
	CString strCurrentText = GetItemText(nRow, nCol);
    if (strCurrentText != str)
    {
        SetItemText(nRow, nCol, str);
        if (ValidateEdit(nRow, nCol, str) && 
            SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
        {
            SetModified(TRUE, nRow, nCol);
            RedrawCell(nRow, nCol);
        }
        else
        {
            SetItemText(nRow, nCol, strCurrentText);
        }
    }

    CGridCellBase* pCell = GetCell(nRow, nCol);
    if (pCell)
        pCell->OnEndEdit();
*/

	CString strCurrentText = GetItemText(nRow, nCol);
	if (ValidateEdit(nRow, nCol, str)) 
	{
		if (strCurrentText != str)
		{
			strCurrentText = str;
			SetItemText(nRow, nCol, strCurrentText);
			SetModified(TRUE, nRow, nCol);
			RedrawCell(nRow, nCol);
		}
		else
		{
			SetItemText(nRow, nCol, strCurrentText);
		}
	}
	CGridCellBase* pCell = GetCell(nRow, nCol);
	if (pCell)
	{
		pCell->OnEndEdit();
	}
	SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT);
}
</pre>
</li></ul>

<ul><li>Next, we have to add all of these files to our project. Open your Solution 
Explorer pane, right click on the <b>SDIMultiApp1</b> item in the tree, click 
<b>Add | Existing Item...</b>, and browse to the <code>MFCGridControl_2-25</code> 
folder (or whatever you named it), select ALL of the files, and click the <b>ADD</b> 
button. You can safely ignore the files in the Experimental Upgrades folder for 
now.

<p>If you're curious, you can open the Solution Explorer pane and see the new files 
listed in the project.</p>
</li></ul>

<ul><li>
The final preparation step for using the grid control is adding the folder to 
your project settings. Right-click on the <b>SDIMultiApp1</b> item in the tree, 
and click <b>Properties</b> at the bottom of the subsequent context menu.  

<p>In the Properties dialog box, expand the <b>Configuration Properties</b> tree 
item, and then the C++ tree item, and add the following text to the 
<b>Additional Include Directories</b> setting (pointed at by the mouse cursor in 
the image above):</pre>

<pre>	.,../MFCGridControl_2-25</pre>

<p>PLEASE NOTICE that the first folder that shows up in this string is the "." 
(single dot). This tells the compiler to look in the project's folder BEFORE 
looking anywhere else for an include file.  In fact, you should add folders to 
this setting in the PRECISE order in which you want them searched. This is an 
important aspect of including files in a project and should not be overlooked.

<p>Finally, make sure you add the same string to ALL required project 
configurations (debug AND release).
</li></ul>

<h3> Hooking The Grid Control Up</h3>

"Making it go" is fairly simple and straightforward, especially since we're 
just making the grid show up for purposes of example.

<ul><li>Open up the <b>SDIMultiApp1View.h</b> file and add the following code:</b>

<pre>#include "GridCtrl.h"

class CSDIMultiApp1View : public CView
{
private:
	CGridCtrl* m_pGridCtrl;
	
public:
	// give other parts of the program a method for retrieving the grid control.
	// you may not need this right away, but it sure will be convenient when 
	// it's there becaus ethat's one less file you have to check out of source 
	// control to change later.
	/// Retrieves the current gridcontrol pointer
	CGridCtrl* GetGridControl() { return m_pGridCtrl; };
</pre>

<br /><center><table width="500" cellpadding="1" cellspacing="1" style="background-color:#000000;">
<tr style="background-color:#CCCCCC;"><td align="center"><font size="-1"></font><b><i>Coding Notes</i></b></font></td></tr>
<tr style="background-color:#EEEEEE;"><td style="padding:5px;"><font size="-1">
When I add stuff manually to a class, I generally add it at the top of the 
class definition because VS2005 likes to add message handlers at the bottom, and 
it just plain looks ugly after a while. Good code readability means good code 
maintainability - always consider those who follow you.  I also provide 
extensive comments <b>AT THE TIME I WRITE THE CODE</b> because I often forget 
why I do stuff, even as soon as an hour after I wrote the code.<br /><br />

Also notice that the final comment starts with 3 slashes. This is a trigger 
for Intellisense to provide the text as a comment when you use a function. This 
is quite handy for people new to the code. I recommend that you try to do this 
as well.
</font></td></tr>
</table></center>
</li></ul>

<ul><li>Now, open up your <b>SDIMultiApp1View.cpp</b> file, and add the follwoing line to the constructor:
<pre>	m_pGridCtrl = NULL;</pre>
<p>And then add the following code to the destructor:</p>
<pre>	if (m_pGridCtrl)
	{
		delete m_pGridCtrl;
	}
	m_pGridCtrl = NULL;
</pre>
<br /><center><table width="500" cellpadding="1" cellspacing="1" style="background-color:#000000;">
<tr style="background-color:#CCCCCC;"><td align="center"><font size="-1"></font><b><i>Coding Notes</i></b></font></td></tr>
<tr style="background-color:#EEEEEE;"><td style="padding:5px;"><font size="-1">
I know, I don't *have* to set the pointer to NULL, but I'm old and IMHO, the old 
ways are the best ways.
</font></td></tr>
</table></center>
</li></ul>

<p>The next few steps concern adding message handlers to the view class. Microsoft 
has made it difficult for MFC programmers to make effective use the IDE. Adding 
message handlers is one of the most annoying of these limitations via the IDE.</p>

<p>To add a message handler (other than manually) to a CCmdTarget-derived class 
(CView being one of them), you must put your edit cursor on either the opening 
or closing line of the message map macro, like so:</p>

<p><center><img border="1" src="code_notes_msgmap_01.png"></center></p>

<p>After you've done this, you can open the <b>Properties</b> pane and you'll 
see this toolbar:</p>

<p><center><img border="1" src="code_notes_msgmap_02.png"></center></p>

<p>Well, *sometimes* you'll see that toolbar. VS2005 (yes, even with SP1 applied) 
sometimes refuses to show the toolbar in the Properties pane.  If this happens 
to you, try shutting down the IDE and opoening it back up again (I offer no 
guarantees that this will work every time).</p>

<p>In any case, there are three buttons you're interested in. Clicking the lightning 
bolt button (tooltip says "Events") will show you message IDs that are defined in 
the resource file. The button to the immediate right of the Events button is the 
Messsage button. Clicking this button presents you with all of the appropriate 
*Windows* messages for the class you're working on.  The last button in the series 
is the Overrides button which allows you to activate override functions, such as 
OnExitInstance, OnInitialUpdate, etc.</p>

<p>We're interested in the <b>Messages</b> button, so let's continue.</p>

<ul><li>Open the Proeprties pane, and click the <b>Messages</b> button in the 
Properties toolbar. You'll be presented with a list of Windows messages. Scroll 
down the list until you find <code><b>WM_SIZE</b></code>.  Click in the blank 
field next to the message ID, and select <code>OnSize</code> in the dropdown 
list. The IDE will add all the necessary code to handle the message, but we have 
to change it, so make the function look like this (just copy/paste the contents 
of the function):

<pre>void CSDIMultiApp1View::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	if (m_pGridCtrl->GetSafeHwnd())
	{
		CRect rect;
		GetClientRect(rect);
		m_pGridCtrl->MoveWindow(rect);
	}
}
</pre>
</li></ul>

<ul><li>Add a message handler for WM_ERASEBACKGROUND, using the method described 
above for the WM_SIZE message, and change the IDE-generated code to look like 
this:

<pre>BOOL CSDIMultiApp1View::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}
</pre></li></ul>

<ul><li>Add an *override* handler for OnCmdMsg. Remember, you have to use the 
Overrides button (the icon looks like a little box) to add an override. Change 
the IDE-generated code to look like this:

<pre>BOOL CSDIMultiApp1View::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
   if (m_pGridCtrl && IsWindow(m_pGridCtrl->m_hWnd))
    {
		if (m_pGridCtrl->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
        {
			return TRUE;
		}
	}
	return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
</pre>

</li></ul>

<ul><li>Add an *override* handler for OnInitialUpdate. Remember, you have to use the 
Overrides button (the icon looks like a little box) to add an override. Change 
the IDE-generated code to look like this:

<pre>void CSDIMultiApp1View::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	CRect rect;
	GetClientRect(rect);
	m_pGridCtrl = new CGridCtrl(0, 0, 10, 1, 1);
	m_pGridCtrl->Create(rect, this, IDC_GRID_CTRL);
	UpdateWindow();
}
</pre>
</li></ul>

<br /><center><table width="500" cellpadding="1" cellspacing="1" style="background-color:#000000;">
<tr style="background-color:#CCCCCC;"><td align="center"><font size="-1"></font><b><i>Coding Notes</i></b></font></td></tr>
<tr style="background-color:#EEEEEE;"><td style="padding:5px;"><font size="-1">
You can alternately try using the Class View t add message handlers, but for 
some reason, I never got into the habit of doing that.</font></td></tr>
</table></center>

<ul><li>Create a new folder in your solution directory called 
<b><code>Includes</code></b>.</li></ul>

<ul><li>Create a new file called Constants.h in your project folder, and insert 
the following code:

<pre>#pragma once

#define IDC_GRID_CTRL            49000
</pre>

<p>We'll be coming back to this file in Part 2 and Part 3 of this series of 
articles as we add more features to the program.</p></li></ul>

<ul><li>Add the following line to the bottom of the project's stdafx.h file:

<pre>#include "Constants.h"</pre>

<br /><center><table width="500" cellpadding="1" cellspacing="1" style="background-color:#000000;">
<tr style="background-color:#CCCCCC;"><td align="center"><font size="-1"></font><b><i>Coding Notes</i></b></font></td></tr>
<tr style="background-color:#EEEEEE;"><td style="padding:5px;"><font size="-1">
<p>I know, every time we change this file, it will cause a complete program 
rebuild, but I have a couple of reasons for doing this; a) our app is so 
small that it won't matter in terms of compilation time, and b) it's just 
plain convenient because all CPP files in the project have to <code>#include 
stdafx.h</code>, and this include is performed by default when you create 
new classes in a MFC project (saving me typing time in this article series).
</font></td></tr>
</table></center>
</li></ul>

<ul><li>Add the new Includes folder to your "Additional Include Directories" 
project setting. Your new entry should look like this:

<pre>	.,../Includes,../MFCGridControl_2-25</pre>
</li></ul>

<ul><li>Optional step - Since we don't need the OnDraw function in our view, I 
chose to minimize it's appearance in the code.  CView is an abstract class, and 
thus forces us to override OnDraw. However, the grid control takes care of it's 
own drawing, and there's really no reason to keep OnDraw around.  All you really 
have to do is delete the function from yourview's CPP file and change the 
function declaration in the view's header file to the following:

<pre>virtual void OnDraw(CDC* pDC) {};</pre>

<p>This helps to keep the CPP file uncluttered.</p>
</li></ul>

<p>Now, compile the code. You may notice a stream of warnings go by as the code 
compiles. This is because the version of the grid control I'm using has not been 
modified for use with VS2005. This will not impact the reliability of the 
application, but if this bothers you, download version 2.26 beta, create a new 
folder within the solution folder (I'd use <b>MFCGridControl_2-26</b>). If you 
do put it into it's own folder, make sure you go back into the project 
properties and change the include directory setting to the new folder (make sure 
you do it for both the debug AND release configurations. After compiling, run the 
application. You should see something like this:</p>

<p><center><img border="1" src="app1_stage_01b.png"></center></p>

<p>Congratulations. You've reached the end of Stage 1 - creating an interesting 
basic application.</p>

<br /><center><table width="500" cellpadding="1" cellspacing="1" style="background-color:#000000;">
<tr style="background-color:#CCCCCC;"><td align="center"><font size="-1"></font><b><i>Coding Notes</i></b></font></td></tr>
<tr style="background-color:#EEEEEE;"><td style="padding:5px;"><font size="-1">
At this point in the development process, I usually take time to add comments 
and start organizing code into sections, separating the overrides from the 
windows message handlers, and stuff like that. The sample code provided in this 
article illustrates that process. Again, it's just something I do to help keep 
the code readable and is not a requirement on your part. 
</font></td></tr>
</table></center>

<p>Feel free to play around with the grid control (add rows, use images, and 
stuff like that. The grid control's demo source should help you figure out how 
to do use some of the more interesting features. And while you're at it, make 
sure you go vote on the Grid Control's page.  Also, if you have any questions 
regarding the use of the grid control, please post those questions on the grid 
control's article page.</p>

<h2>End of Part 1</h2>
<p>Due to the length of this article, I've decided to break it up into several 
parts.  If the site editors did what I asked, all of the subsequent parts 
should be in the same code section of the site. Each part has it's own source 
code, so as youread the subsequent parts, make sure you download the source code 
for that part (unless you're doing manually all the stuff I'm outlining in the 
article in question).</p>

<p>In the interest of maintaining some cohesiveness (and sanity), please vote on 
all of the parts, and vote the same way. This helps keep the articles together 
in the section. Thanks for understanding.</p>

</body></html>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Paddedwall Software
United States United States
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.

My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Comments and Discussions