Introduction

This is the fourth edition of this article, with a review code, based on the templates presented in "A policy based reference counting", providing classes to make "smart" Win32 objects.

I'll not go in to the introductory disclaimers of the previous article, they'll be the same here. Pure C++ and STL (and –obviously- "windows.h") this time.

Code structure

Same as in the previous article: a collection of headers whose dependency are solved in the headers themselves. The winx project is just a collection for those headers, with the GE_::winx namespace containing Windows related classes and functions.

First thing: I used main instead of WinMain. But don't be fooled by this: the linker had been instructed to use the WINDOWS subsystem and to use mainCRTStartup as the entry point. We lose some useless Win16-only meaningful parameters, but we gain the C++ standard command line parsing (not needed here, but who knows!).

Forget about the stdx::New<Win>->set_createhook and you find the entire program in the return statement. (That is "we leave to die": although it seems pessimistic, if you are not in hurry ... you can do anything to do that, including live for one-hundred years or more!)

Now, app::msgloop is a constructor taking an HWND parameter. And run is the usual Windows application message loop (while GetMessage(.) { Translate and Dispatch }).

The HWND is obtained with the Win32 CreateWindow API (but anything creating a window works!), where the classname parameter is obtained with the app:wndcls::frame static function (that registers a WNDCLASSEX ) and GetModuleHandle(0) is used to retrieve the HINSTANCE for the executable module.

The run function will return when IsWindow for the passed HWND will be found false.

Well ... this is not perfectly orthodox in Windows (no PostQuitMessage call to make GetMessage to return 0) but works always, even if the main window is closed by an application unhandled syscommand, with no WM_QUIT message to be posted.

Window class registration

The key is to box the RegisterWinClassEx in a shortcutting class.

Class winx::wndcls is a box class containing an stdx::refcountable derived data structure to hold an ATOM and HINSTANCE values. wndcls constructors keep some convenient default parameters to fill-in a WNDCLASSEX structure, allocate a boxed structure referring it with a smart pointer, and call RegisterClassEx storing the return value.

The on_delete function of the internal structure calls UnregisterClass when no more references exist. Thus, app::wndclass(…) registers a Win32 window class on construction and unregisters it on the last destruction (copy and assignment pass the smart pointer, hence, sharing the ownership).

Since certain parameter value combinations are of frequent use, some static functions are available to shortcut such constructions: pane() registers a "genericpane" with IDI_APPLICATION icon and IDC_CURSOR and a COLOR_WINDOW background; gray() registers "genericgray" with COLOR_BTNFACE background, and frame() registers a frame with no background.

All of them take DefWindowProc as a window procedure. That makes all windows created with those classes to behave as default-behaving windows.

The message loop

Class app::msgloop is constructed on the stack starting from an HWND and an optional HACCEL.

Its loopbody function does the typical Get/Translate/Dispatch actions of a message loop body. It can be used as-is (for example, in calculation modal loops) or called by loop_while (that loops until a given bool reference becomes false, or until the related HWND exists) and run (that calls loop_while passing an always true variable).

Thus, the app::msgloop(...).run() will create and run the loop until the passed HWND (the newly created window) is destroyed.

Handling Windows messages

To stay with the Win32 API, Windows message handling happens through window procedures, associated to window classes, or to other "subprocedures" (like dialog procedure etc.) called by a system-defined default procedure. Handling messages for already existent windows can instead be done with subclassing (that is, replacing the window procedure with another).

This second method is more general, since it applies to every possible existing window. We can so create windows using the default procedure (DefWindowProc) and then subclass them as needed.

But there are two problems to solve:

A window procedure is a global-linkage function (a global or static member), while we would like to get messages into C++ class instances.

A modal window exists inside a single API call (think of DialogBox: a window exists while it runs, but doesn't before and after the call). When do you subclass it?

Thunking, delegates and whatsoever

Associating an HWND to an object instance and calling a member given the HWND value can be done with a technique named "thunking". It's the technique used in ATL / WTL. In fact, it is a hack: a data structure (something residing in the data segment) is executed after appropriate CPU registers loading as its bytes are the machine code to push a this pointer in the stack and do a jump.

Here I'll follow a different approach: HWND to this mapping is done … in a statically available std::map for a static wndproc that seizes the map and calls the instance on_message function.

The subclasser

Class winx::win_subclasser does exactly that, through the subclass and on_message function (and the subclass opposite reclass). And since it is a template taking a Derived class, we will have as many map and window procedures as C++ classes. And hence, each map will have as many entries as the total number of windows subclassed by the same C++ class. Hence, with an accurate definition of classes, seeking in the map can be not so time wasting.

As a consequence, we can sublclass the same HWND using different C++ classes and handle different HWND with different instances of a given C++ class. But not subclass twice an HWND with two instances of the same Derived. (And –in fact- it should be quite strange: why subclass twice to do the same things twice?)

The on_message function is what you'll override in your implementation classes. The base implementation (remember to call it!) handles the map HWND erasure at WM_NCDESTROY. The from_hwnd static function, seeks for the subclasser of a given type, creating it if not available.

Since win_subclasser is an stdx::refcountable and since the HWND map holds strong pointers, a subclass will exist until someone refers it, or until its referred HWND is destroyed.

Creation hook

The problem of handling the creation messages or handling modal windows' messages can be managed with the createhook class (that's also the base for win_subclasser): before creating the HWND (with any Windows API) just instantiate the appropriate createhook derived, and call set_createhook(). A Windows wndproc hook is installed, and the first WM_NCCREATE message seen will map the HWND with the C++ class instance. Then, the hook is deinstalled, and all subsequent messages received by the C++ class instance. The WM_NCDESTROY will cause the reclass thus eliminating the mapping.

Message routing

Receiving messages in a C++ class can be only a first step, in a complex application. When there is the need to "route" messages between objects (think of frames, views, documents and items) winmsgrouter / winmsglink classes can be a solution. They are respectively the nodes and the arcs of a generic graph. Nodes have virtual bool on_message and bool route_message functions, all taking a winmsg structure (a convenient wrapper for window procedure parameters and message routing information).

Routing functionality is –in fact- a specialization of the generics graph::link, router and routabledata templates, that, in a Windows related context become winx::winmsglink, winmsgrouter and winmsg, respectively.

Calling routemessage pushes in the parameter structure the arcs begin/end iterators, and calls the do_default function that iterates the arcs' destinations, calling on_message until someone will return true.

Of course, you can override winmsgrouter::on_message calling routemessage once again, propagating the message through the graph.

Arcs contain a property named metric, (accessible with get_ and set_), whose value is added as the message is routed. The idea is let on_message to have a way to know about how far a message comes from. By discarding too far-coming messages, you can have a very simple way to avoid routing loops.

Dynamic windows

An alternative way to distribute messages is the win class. It combines a winmsgrouter with a createhook. An internally defined source combines a win_subclasser with a winmsgrouter having on_message (that's called by the subclasser window procedure) calling routemessage. The createhook::set_hwnd is overridden to create a winmsglink between the win and the HWND associated source.

win also contains a self-pointing strong pointer that is initialized when the HWND is assigned to it, and cleared when WM_NCDESTROY is received or when the HWND is de-assigned. This makes the class to exist until some other strong pointer holds it or until its referred HWND exists.

Now, let's go back to the "/* forgot this by now */" of the previous code fragment: Win is a winx::win derived class defined in the test unit: instantiating one and calling set_createhook makes the window created soon after to be subclassed by a winx::win::source and its messages to be routed to Win. Since nothing else in the program will refer to Win, it will be deleted at HWND destruction (when the user will close the window).

To recap, the following picture shows the Windows and messages related classes.

Handling Windows handlers

Windows handlers can be reference counted with value-semantic wrappers. In the stdx project, smart::hnd and smart::mappedhnd declare the strong and weak variants for those wrappers when the destruction policy is a simple call to a Win32 API.

This is certainly true for GDI object handles (like HBRUSH, HPEN etc.), where "handles.hpp" defines the HSxxx and HWxxx strong and weak variants with simple typedef-s.

Handling DCs

Device contexts are a different story:

They can be obtained in a variety of ways, and must be destroyed coherently.

There is certain "internal dependency" between DCs and GDI objects: when a GDI object is selected into a DC, a DC cannot be destroyed, and a DC cannot be destroyed while having GDI selected objects without causing memory leaks in the GDI.

To overcome these limitations, there is the need of several classes managing the correspondent acquisition and destruction policies. And there is also the need to keep track of the selections, in order to "deselect" before destroy.

Class stdx::smart (see the referring article), by itself, translates copies and assignments into calls to assign. A number of policies are defined in the winx::DCs namespace. The base for all is DCs::Save.

It declares HDC to be the alias_type, the value_type and the acquire_type, and act as a box for an inner strong pointer to a polymorphic data class, whose base is Save::data, that stores strong handles for the selected GDI object and the handle values for the "default DC selected object" (what was in the DC before any selection).

Assigning an HDC makes Save to allocate a new Save::data, while copy between Save makes the data to be shared.

The data deletion policy (Save::data::on_lastrelease) restores the selected data wit the default values (causing object deselection) and data deletion causes the GDI referred object to be released and –if not else referred- deleted.

This basic behaviour allows to save a DC state and restore it before leaving the DC unreferred. It doesn't delete the DC.

Policy derived from Save will:

override the acquire_type definition accordingly to their behaviour.

override the data structure definition by inheriting the Save's one and overriding on_last_release to do proper DC deletion.

override the assign functions to create to allocate their own data instead of the base one.

In general, different DC policies cannot assign each-other in a heterogeneous way, apart Save (since all policies derive from it). And since data are passed by smart pointers, the last releasing smart handle will use the policy that data carries on, that is the one belonging to the data type created during the first assignment.

Practically, no matter what smart handle causes a DC deletion: the deletion action is always coherent with the creation.

File "handles.hpp"typedefs the following DC smart handles:

DC_Save

Just a typedef for stdx::smart<DCs::Save>: implements state saving and restoring, and objects retaining at selection.

DC_Client

Accepts HWND in assignment, calling GetDC, and calls ReleaseDC on last release.

DC_Window

Same as DC_client, but using GetWindowDC.

DC_Paint

Accepts HWND, calls BeginPaint on acquisition and EndPaint on releasing.

DC_Mem

Accepts an HSBITMAP, creates a screen-compatible memory DC and selects the bitmap in it.

DC_Mem_xy

Accepts a SIZE, creates a screen-compatible memory DC, creates a compatible bitmap with those sizes, and selects it in the DC.

DC_MemPaint

Accepts an HWND, and combines DC_Paint and DC_Mem creating an internal DC_Paint, a window-like sized bitmap and a DC_Mem that exposes. The alias DC (where all selection and drawing happens) is the memory DC. On last release, the bitmap is blit-ed in the Paint DC. Practically a double-buffer painter.

Other helpers

To help in certain annoying parameter passing and type definitions, some frequently used Win32 structs can be inherited by C++ classes to embed certain shortcuts or some arithmetic.

Class stdx::operators<Derived> defines all C++ arithmetic operators in terms of assignments and all relations in term of == and <.

Win32 POINT, SIZE and RECT arithmetic can be defined using winx::point, winx::size and winx::rect respectively. All of them inherit stdx::operators and the respective Win32 struct, and define assignment operators. They don't redefine Win32 functions: since they auto convert in their respective structs, they can be passed as parameters to those functions.

winx::String

The stdx::string template allows the management of shared sequence of data. When those data are char or wchar_t they're nothing more than ordinary strings.

When data are TCHAR, winx::strings::traits provides len and copy in terms of lstrlen and lstrcpy. At that point, winx::String is the typedef for stdx::string<TCHAR, winx::strings::traits>.

We already talked about main. Now is the time to look at its second code line.

The class Win is created on heap and its set_createhook member is called. As a consequence, a Windows hook is installed to spy all the windowproc calls. When CreateWindow is called, a new HWND is created and the WM_NCCREATE message is sent. This condition is seized by the hook that calls the Win::set_hwnd override, then dismisses itself. (Note: to let this operation to be thread-safe, only one thread is allowed to run during these steps by a Win32 critical-section internally managed.)

The win implementation of set_hwnd creates and maps a win::source, instantiates a winmsglink and use it to link the source to the Win instance. It will begin to receive the HWND messages.

The on_message implementation returns a complex Boolean expression whose side effect is … dispatching the message: to on_paint if it is WM_PAINT or to the base if it is anything else.

The on_paint function creates a DC_MemPaint for the HWND (*this converts into HWND automatically), then selects a newly created font.

Note that the HFONT returned by CreateFont is converted in HSFONT by the parameter passing, and stored in the DC policy.

The win::get_windowtext shortcut calls GetWindowText using a winx::String as a buffer. Hence no buffer allocation and handling is required.

At the return statement, the following effects occur:

dc is destroyed, and its data released.

The release policy restores the memory DC (thus deselecting the internal bitmap, and the passed font) and deletes it.

Then, it blits the bitmap that was drawn by the DC into an internally created PaintDC (that already called BeginPaint on its creation).

Then the data are deleted, causing the bitmap to be deleted and the PaintDC to be released.

The release of the PaintDC causes EndPaint to be called.

Conclusions

The usage of the reference counting pattern can greatly simplify Windows programming, allowing an implicit management of resources reducing the risk of leaks in the memory and in the system.

A convenient separation between data and related management (inside classes) and algorithm (namespaced functions) also allows a flexible and extendible way to simplify coding.

Share

About the Author

Born and living in Milan (Italy), I'm an engineer in electronics actually working in the ICT department of an important oil/gas & energy company as responsible for planning and engineering of ICT infrastructures.Interested in programming since the '70s, today I still define architectures for the ICT, deploying dedicated specific client application for engineering purposes, working with C++, MFC, STL, and recently also C# and D.

Do we really need yet another gui library when there are better ones out there than you could possible compete with. I never really understood why Windows developers always felt the need to reinvent the wheel, pretty much on everything there is.

You're classes aren't consistently styled.The functions names are poorly obfuscated named (who does that anyone?).You should learn to use boost::signals for handling events.You make poor creation of widgets. I mean you are calling CreateWindow() instead of using sane functions like setBackgroundColour/backgroundColour(), etc.It looks like it was just written in a rush and not taken the time to actually be developed.The proper way if you are going to waste time writing a wrapper around crusty outdated win32. You have to design it like to the point where it doesn't even look like you are using Win32. Look at Qt, wxWidgets, Gtkmm, Gtk+. They are cross platform yes, but they don't show an ounce of win32 in the names, any of the win32 flags, etc. It's all abstracted away.

First: it has been written in 2005 (five years ago) just after Microsoft removed MFC from its free compiler distribution. Five years later (with template finally standardized) it is obvious that certain choices aren't anymore up-to-date.Reading a comment today about the re-invention of wheel at that time not yet "fully-invented" (in the sense that no clear standard was existing yet) look almost strange.

Second: You pose a number of points that may be interesting today, but cannot apply directly to something done 5 years ago with today (2010) 7 years old C++ compilers and libraries. (the header of the article says VS2003)

Third: The purpose of this article is not to "provide an alternative to WxWidget" but to show how certain basic concepts can be used to create wrappers that automatize certain Win32 tasks.Its purpose are clearly didactic, as it is stated in the introduction:

"I'll not go in to the introductory disclaimers of the previous article, they'll be the same here. Pure C++ and STL (and obviously- "windows.h") this time." If you just click the link, you find another article whose introduction says:

"Many of you probably know libraries like Boost or Loki.

Well .. if you feel fine with that implementation of smart pointers ... forget about this article! Even if it can give something new to you, you'll probably already have enough motivations to stay with them, asking why another set of wheel.

But if you think that code to be sometimes an overkill, and you need something tiny, or you also need something simpler to be expanded, or you simply want to understand something about a possible way to do a policy based design, then you can get something from here.

Since I'm not new to this kind of stuffs, and some readers may also know other articles by me on the same subject, I must warn you: this is not an update of the previous series, but restarting with a new engine, more "modern" and less oriented in conserving old habitudes like Hungarian notation or other zealot implementation of patterns.

This time I won't respect any religion, but I consider all of them, case by case, with one objective: minimize the needed code."

That said, all your comment become meaningless:

"You're classes aren't consistently styled.": That's a matter of taste. There is people (one of them is Andrei Alexandrescu) that retain the STL itself has this same problem.

"The functions names are poorly obfuscated named (who does that anyone?)." That was not in the purpose of this article. It had to be transparent.

"You should learn to use boost::signals for handling events". I was explicitly saying I was specifically not using any other dependency on other libraries. Before telling me what I have to learn, try thinking I may have already learnt, and consciously taken another direction. (Boost signal is criticized be other boost author as well ... so, that's not that perfect). Fell free to disagree, but before tell me what to "learn", at least tell us who you are. Your profile is completely blank and you are fully anonymous. You may be a 40 years experience MIT professor, or just a 14 y.o. wanker. (or anything else in the middle, of course!)

"You make poor creation of widgets" I was not doing a widget library.

"The proper way if you are going to waste time writing a wrapper around crusty outdated win32. You have to design it like to the point where it doesn't even look like you are using Win32."I was not "hiding" win32: just automating the management of the handles. This is not (and doesn't want to be) a multi-platform library. (and they where not so "outdated": it was 2005. And even today -2010- application that are not "freaky cheeky", but are business critical are written on them: .Net changes too frequently to be trusted in certain process controlling tools.

"Look at Qt, wxWidgets, Gtkmm, Gtk+. They are cross platform yes, but they don't show an ounce of win32 in the names, any of the win32 flags, etc. It's all abstracted away"Oh no! Win32 are "Abstract" exacly like wxWidget are: you don't know what's behing an HWND.Win32 are OOP written in plain old C. WxWidget are "abstract" in self-defined elements because -to be multi-platform- they have to rely on self-consistent definitions, since the underlying platform can change.I am at the same abstraction level of win32, using C++ feature to manage them, not "above it" (as WxWidget, Qt etc. are)

But consider also that those libraries are themselves dated: today releases are still retaining some "old-style C++" (like macros, preprocessing and flat namespaces) that makes many people think they are themselves not "modern C++". They where good examples in 2003-2005. Not today (although perfectly working and useful: many of my activity is based on WxWidget!)

"If you manage to fix this, i'll change my rating"No, sorry: this article is "historical" and we cannot "fix the history".But today other deployments are in progress, much and much more "modern C++", than WxWidget.Give a look yoursef to algierlib[^]

Sorry I can't seem to find the project I know I have it here somewhere, , there were some "member redeclared" errors , on declarations like "friend some_class_name" ; sorry I can't be more specific at this time, I 'll get back to you when I find the project

P.S.: There were a lot of errors compiling , I think over a hundread, (just thought you should know) anyway maybe I'm doing something wrong

Always respect for your very great well designed work but i have some problems to follow your mind about the struct EvMsg... Why did you use this design with structure and unions... I hope you understand it what i mean...

Good old-days style for good old-days data like WPARAM and LPARAM.The problem is to have an esasy and dirty access to the lParam and wParam memebrs, avoiding to continuously copy them.

I understand that a more "modern" code should use functions, but windows istelf use those data by imposing they position in memory. So I'm not forcing anything by saying that EvMsg::lParamLo is like LOWORD(lParam). but with read-write access (I mean: they're all l-values)

It's just a quick and dirty trick to process certain messages (like WM_SIZE, or WM_COMMAND, for example) where the 32bit W- and LPARAM are used as 16bit two-ples.

So LPARAM is reinterpreted as a two-WORD lParamLo-lParamHi, and the same for WPARAM.

It's a old C trick, I know, but the entire Win32 message dispatching is an old C trick.

Anonimous(the same as before) ??? it's not the same because the one before was anonymous without the same as before, but ... ah yes ! It is a function call! or ... no ... two overloaded function call, that whithout or with that parameters return the same pointer !

Anyway, thanks for the links! And for anyone would like to have any further reading on the same subject !

It seems they are all good starting points, but thay may have some scalability problems.The idea to redirect the window procedure to a C++ class instance by storing the address as GWL_USERDATA than, can be problematic if you are not the "creator" of the window (because you canno kwow what - the code that creates the windos- is using that data to do what).I use a more "plug and play" approach.

As far as I can feel, if you never programmed widows with C++ and you and have to do a standalone application from scratch, that can be a usefull library.But if you want something more flexible, that can hook windows from any sources ... I'm not so confident.

There's a ongoing article in CUJ that takes care of that bit. I assume that documentation, as usual, comes as an afterthought but as he already had redesigned some base object it might be a wise decision.

> Talking about WinLib, how about Win32GUI...http://sourceforge.net/projects/win32gui/[^]

Jonas - Wow, I'm impressed. I'm going to seriously check it out. It's clearly under very active development - the last release was 12 hours ago! And it seems to have a reasonable level of documentation now. Certainly it's one to watch - it deserves to be better known.

Emilio - I always enjoy your articles. I usually have to read them several times, sometimes they are a bit hard to follow -- but they are always worthwhile. Your neutral position on templates vs OOP has really broadened my thinking.

Something that I would like to hear from you now that you've done this stuff a few times is: Where do the main difficulties lie? My guess is that resources, especially DCs, are the biggest problem. But event handling looks a bit messy too.

Something that would make a fantastic article would be a 'battle of the frameworks'. Implement a simple program using several different frameworks (eg MFC, WTL, .NET, WinLib,Win32GUI, and a couple of your ones), and see how appealing the resulting code is. Preferably something that was only just complex enough to tie MFC in knots, but that wasn't trivial in any of the frameworks. I don't think a "hello world' program really shows you anything. Just a thought.

Thanks a “very lot” for your appreciation, Don.You’re posing interesting points, but – at the moment- I believe I’m not yet reached a sufficient “battery limit” (in military terminology) to sustain a “framework battle”.

At the moment I’m not yet delivered a “framework” but only a set of classes with a purpose that’s more didactical than other, and that wants to demonstrate (how was I able to … depends on everyone’s opinion) that there is no need of a rigid framework to implement windows apps.

I understand that a “hello world” doesn’t demonstrate the “limits” of an implementation, but – at this point – I cannot compete with MFC to sustain an app that requires a doc/view model, or with a number WTL classes to manage controls or COM objects etc.

My purpose is not to fully rewrite MFC or WTL but to show an alternative approach to build a framework (in respect of the design approach used to build MFC: MFC itself, not an MFC app!).MFC was the first C++ framework around W32, when C++ was missing many of its actual features. We can do better, of course, but I cannot have the man-hours af the entire AFX group!

About your question about difficulties … most of them depend on the fact that windows itself is messy: DCs and GDI object are internally unsafe. You can destroy a selected pen (compromising the DC) and delete a DC with selected object inside (compromising GDI memory). The only way go ahead is to completely wrap GDI APIs with something else ... but if you want to stay open towards underlying layers … you can only provide “helper classes” (and that’s what I did) to be used with certain discipline, hoping this discipline is simple to control then the one required by the original function. And the fact that you specify how to delete during acquisition (or creation) certainly helps. And this is – by now –what I did.

To move towards a more structured framework I need a better abstraction layer, and this is what I’m working on just now. May be – sooner or later – I’ll come to have something really comparable.

I’m instead not sure to understand your point about events. What are you meaning saying they’re “messy”? Are you referring to my scheme or to windows messages? Or both or.. to their interaction?

> I’m instead not sure to understand your point about events. What are you meaning saying they’re “messy”? Are you referring to my scheme or to windows messages? Or both or.. to their interaction?

I was just observing that the most complex and messy part of MFC is the message routing. I don't know whether this is an inevitable consequence of the Windows message pump scheme, or whether it because of the poor design of MFC.

But it does seem that the GDI problems date back to Windows 1.0, probably before Microsoft had even heard of C++, let alone RAII .