|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionIn spite of the proliferation of object-oriented libraries for Windows, such as the Microsoft Foundation Classes (MFC), programming with nothing more than the Win32 SDK still remains a popular choice when performance and size are issues. However, the terminology used by the SDK is a bit different than that of MFC, and in some cases can be completely opposite. This article was written in an attempt to explain some of these differences, and to provide a few examples. Under the hood, MFC is really a normal Win32 SDK application, even if it does not appear to be one. The features that Microsoft has added to MFC over the years to make programming for Windows simpler, has in some cases obscured the underlying principles and even renamed these concepts from what SDK programmers known them as. I myself had this problem recently when reading several of the articles on CodeProject about subclassing controls. MFC allows you to create a C++ class, which is derived from a base class - subclassing in the C++ definition of the word - to change the behavior and the visual appearance of the control described by the base class. This is very different from the SDK meaning of "subclassing," which is used only to change the behavior, but not the appearance. As an example: If you look at
Chris Maunder's
subclassing article, you will notice that he changes one of the style bits
in his subclassed button to make it owner-drawn, and then overrides the On the other hand, if you look at
Daniel
Kopitchinski's message handling article, the behavior of an edit control is
modified by preventing certain keys from getting to the control. Considering
that the control does not send every keystroke to its parent in a
Samples And ExplanationsWhat follows is code fragments, taken from the Zip file included with this article that should illustrate both of these concepts from the SDK point of view. Subclassing, The SDK WayFirst, we will examine "true" subclassing. The code is adapted directly
from Daniel's, so it should look familiar. When you run the program, you will
find that only numbers are recognized by the edit control. The important thing
to notice in the dialog callback is the code in the g_oldEditProc = (WNDPROC)SetWindowLong(
GetDlgItem( window, IDC_EDIT ), GWL_WNDPROC, long( EditProc ) );
This is the function responsible for subclassing. The calling format for
DWORD SetWindowLong( HWND handleOfWindowToSubclass,
int indexOfPropertyToChange,
DWORD newValueOfProperty );
The returned value from this function is the old value of the property. The
The new edit control callback looks like this: int __stdcall EditProc( HWND window, UINT message, WPARAM wparam, LPARAM lparam ) { // Keystrokes are intercepted before the edit control sees them. if( message == WM_CHAR ) { // Only allow numbers to reach the control. if( IsCharNum( char( wparam ) ) ) { return( CallWindowProc( g_oldproc, window, message, wparam, lparam ) ); } // All other characters are dropped. else { return(0); } } // All other messages get through without any modification. else { return( CallWindowProc( g_oldproc, window, message, wparam, lparam ) ); } } First, note that Windows does not provide an Just like Daniel's code, the callback traps all characters sent to the edit control, and drops everything except for numbers. This could be the basis for a template that only allows telephone numbers, prices, or social security numbers, for example. One of the messages that cannot be properly trapped this way, is
if( message == WM_PAINT ) { HDC dc = GetDC( window ); RECT rect; GetWindowRect( window, &rect ); FillRect( dc, &rect, HBRUSH( GetStockObject( GRAY_BRUSH ) ) ); ReleaseDC( window, dc ); return( 0 ); } All this will do is cause the control to not be painted at all. Subclassing is obviously not going to help in customizing the appearance of the control. That brings this tutorial to its second topic: Allowing a control to be drawn by its parent. Owner DrawingFirst, notice that in the SetWindowLong( GetDlgItem( window, IDC_BUTTON ), GWL_STYLE,
GetWindowLong( GetDlgItem( window, IDC_BUTTON ), GWL_STYLE ) |
BS_OWNERDRAW );
When any owner-drawn controls need to be updated, Windows sends a
if( ( ( DRAWITEMSTRUCT* ) lparam )->hwndItem == GetDlgItem( window, IDC_BUTTON ) ) { DrawItem( ( DRAWITEMSTRUCT* ) lparam ); return( TRUE ); } Instead of doing the usual "hot tracking" demonstration, in which the
background color of the button changes when the mouse is over it, the example
program completely changes the appearance of the button to be rounded, instead
of the boring standard rectangle. All of the drawing magic is contained in Also of importance in an SDK program, is deleting any GDI objects that are created. If this is not done, the program would suffer from memory leaks that would keep building until memory was exhausted: pen = CreatePen( PS_NULL, 1, 0 ); ... DeleteObject( pen ); ConclusionHopefully the sample code and the explanations in this tutorial will clear up some confusion, and help other developers understand the difference between subclassing and owner drawing. Also, knowing what goes on behind all of the "MFC magic" can help to understand MFC a little better.
|
||||||||||||||||||||||