<html>
<head>
<title>Generic</title>
<meta name="description" content="Reliable software Win32 Tutorial: Generic app">
<meta name="keywords" content="reliable, software, windows, cplusplus, source code, example, tutorial, object oriented, CreateWindow, WindowClass, MVC, model, view, controller">
</head>
<body background="../images/grid.gif" bgcolor="white" text="black">
<table cellpadding=10 width="100%">
<tr>
<td width=100 align=center valign=middle>
<a href="../index.htm">
<img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
<br>Home</a>
<td><font face="arial" color="#009966">
<h1 align=center>The Generic Windows Program</h1>
</font>
</table>
<table width="100%"><!-- main table -->
<tr>
<td width=10> <!-- Left margin -->
<td> <!-- Middle column, there is also the right margin at the end -->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td bgcolor=white>
<hr><!--Text-->
<font size="+1"><b>This program uses</b></font> the basic set of classes that encapsulate the Windows API.
<ul>
<li>Controller-- The bridge between Window Procedure and Object Oriented world.
<li>View-- Encapsulates the output of a Windows program.
<li>Canvas-- Encapsulated various Device Contexts and things you can do with them.
<li>Model-- The worker and the brain of your program. Doesn't deal with Windows at all.
</ul>
<table bgcolor="#FFFF99" cellspacing="2" cellpadding="2" border="1" frame="box">
<tr>
<td>
Note: This is a Win32 program-- it will run under Windows 95 and Windows NT.
</td>
</tr>
<tr>
<td>
Note: <b>_set_new_handler</b> is Microsoft-specific. If you're using some other compiler, just remove this line of code. According to current C++ standard, operator new should throw exceptions anyway.
</td>
<tr>
<td>
Note: Older compilers might have problems with templates. In such case, you may substitute the use of <b>Win[Get/Set]Long</b> templates with direct calls to <b>Get/SetWindowLong</b>. For instance, instead of calling
<p><font face="courier">
Controller * pCtrl = WinGetLong<Controller *> (hwnd);
</font>
<p>you can call
<p><font face="courier">
Controller * pCtrl = reinterpret_cast<Controller *> (::GetWindowLong (hwnd, GWL_USERDATA));
</font>
</td>
</tr>
</table>
<p>Download <a href="source/generic.zip"><img src="images/generic.gif" alt="generic icon" width=32 height=32>eneric</a> sources (zipped file 11k).
<hr>
<p><font size="+1"><b>Let's start with WinMain</b></font> where we create the Window class and the top window of our application. I have encapsulated these actions inside two classes: <font color="#cc0066"><b>WinClass</b></font> and <font color="#cc0066"><b>WinMaker</b></font>. WinClass can also tell us if there already are running instances of our program. When something like that happens, in our example, we will simply activate the previously running instance of the program and exit. You should do that when you want only one instance of your program running at a time.
<p>Once the top window is successfully created, we enter the message loop. Notice that this time we are processing keyboard shortcuts by calling <font color="#000099"><b>TranslateMessage</b></font>. That's because our program has menu items that can be accessed using Alt+key combinations.
<p>Another interesting twist in this program is that we are no longer using strings to name our resources--we use numerical ids. More than that--even when the API's call for strings, like the name of the Windows class or the caption, we store the strings in <i>string resources</i> and access them through ids. Your Windows development environment most likely has a resource editor that lets you create icons, menus, and string resources and assign them appropriate numerical ids. Symbolic names for these ids are stored in a header file produced by such an editor--in our case it's called <i>resource.h</i>.
<p>The constant, ID_MAIN, for instance, refers to the main program's icons (large and small in the same resource), the main menu, and the string with the Windows class name. ID_CAPTION refers to the window caption string. Such organization promotes code reusability, not to mention the ease of localization.
<hr>
<!--Yellow background-->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td width=20>
<td bgcolor="#e0e080">
<pre><font face="courier">int WINAPI <font color="#cc0066"><b>WinMain</b></font>
(HINSTANCE hInst, HINSTANCE hPrevInst,
char * cmdParam, int cmdShow)
{
_set_new_handler (& NewHandler);
<font color="#cc0066">// Using exceptions here helps debugging your program
// and protects from unexpected incidents.</font>
try
{
<font color="#cc0066">// Create top window class</font>
TopWinClass topWinClass (ID_MAIN, hInst, MainWndProc);
<font color="#cc0066">// Is there a running instance of this program?</font>
HWND hwndOther = topWinClass.GetRunningWindow ();
if (hwndOther != 0)
{
::SetForegroundWindow (hwndOther);
if (::IsIconic (hwndOther))
::ShowWindow (hwndOther, SW_RESTORE);
return 0;
}
topWinClass.Register ();
<font color="#cc0066">// Create top window</font>
ResString caption (hInst, ID_CAPTION);
TopWinMaker topWin (topWinClass, caption);
topWin.Create ();
topWin.Show (cmdShow);
<font color="#cc0066">// The main message loop</font>
MSG msg;
int status;
while ((status = ::GetMessage (&msg, 0, 0, 0)) != 0)
{
if (status == -1)
return -1;
::TranslateMessage (&msg);
::DispatchMessage (&msg);
}
return msg.wParam;
}
catch ( WinException e )
{
char buf [50];
wsprintf (buf, "%s, Error %d", e.GetMessage (), e.GetError ());
::MessageBox (0, buf, "Exception", MB_ICONEXCLAMATION | MB_OK);
}
catch (...)
{
::MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK);
}
return 0;
}</font></pre><!--End Code-->
<td width=20>
</table>
<!--End of yellow background-->
<hr><!--Text-->
Let's have a look at the <font color="#cc0066"><b>WinClass</b></font> class. It encapsulates a Windows-defined structure called <font color="#009966">WNDCLASSEX</font> and provides reasonable defaults for all its fields. It is derived from a simple WinSimpleClass class, which you might use to encapsulate some built-in Windows classes (like buttons, list views, etc.).
<p>I have provided examples of methods that can be used to override the defaults. For instance, <font color="#cc0066"><b>SetBgSysColor</b></font> changes the default background color of the user area of the window to one of the predefined system colors. The method <font color="#cc0066"><b>SetResIcons</b></font> loads appropriate icons from resources and attaches them to the Window class. These icons will then appear in the upper left corner of the main window and on the Windows' taskbar.
<p><font color="#cc0066"><b>TopWinClass</b></font> derived from <font color="#cc0066"><b>WinClass</b></font> makes use of this method. It also assigns the menu to the top window class.
<hr><!--End Text-->
<!--Yellow background-->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td width=20>
<td bgcolor="#e0e080">
<pre><font face="courier"><!--Code-->
class <font color="#cc0066"><b>WinSimpleClass</b></font>
{
public:
WinSimpleClass (char const * name, HINSTANCE hInst)
: _name (name), _hInstance (hInst)
{}
WinSimpleClass (int resId, HINSTANCE hInst);
c
评论1