In some cases, it is useful to create an MFC application where the main window uses a specific window class.
This is especially useful when I want to provide some easy and simple inter process communication (IPC). The easiest way to communicate from one process to another process is to send a message. The only problem is to determine and identify the target window easily.
One way is to iterate over all top level windows and to determine classname or window name. Or to broadcast a registered windows message to all windows. But this is some overhead and there is an easy way to solve the problem to find a window directly.
Windows provides the function FindWindow, and is easy to find a window with a specific name or class name.
Window titles usually change with the opened file, and might change if the users changes the language for the application (if there is support for multiple languages). But if it is possible to define your own class name, you have something really unique to search for.
But in MFC programs, the class names are internally defined and used by the MFC framework. And for a dialog based application, it is the fixed system class #32770.
The problem is how to change the MFC application to use a class name that is provided by the developer.
The function we need to change is
CMainFrame::PreCreateWindow that is normally already created by the application wizards for MFC SDI and MDI applications.
For a dialog based application, we have to force the system to load our dialog resource template with our defined class name.
Using the Code for SDI and MDI Applications
If you create a SDI/MDI application with the MFC application wizard, you find a function
CMainFrame::PreCreateWindow. This function is called several times and is used to provide the information for the window classes and styles that are used to create the window.
The current code just overrides to normal implementation, registers a new window class with a name provided by us and passes the class name to the resulting structure.
You have to remember that
CMainFrame::PreCreateWindow is called at least twice. Also the MFC routines check the icon that is defined in the window class struct if it matches the one used and defined by
CWinApp::LoadFrame. If the MFC routine (
CFrameWnd::GetIconWndClass) that is calling
PreCreateWindow finds a different
hIcon set in the
struct, it creates its own class using the icon that MFC thinks is the correct one. Usually the icon has the ID
The code below just shows what you have to change in your mainfrm.cpp:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
if( !CFrameWnd::PreCreateWindow(cs) )
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
LPCTSTR pszClassName = _T("OwnClassName");
if (!::GetClassInfo(AfxGetInstanceHandle(), pszClassName, &wndcls))
VERIFY(GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls));
wndcls.lpszClassName = pszClassName;
LPCTSTR pszIcon = MAKEINTRESOURCE(IDR_MAINFRAME);
HINSTANCE hInst = AfxFindResourceHandle(pszIcon, ATL_RT_GROUP_ICON);
wndcls.hIcon = ::LoadIcon(hInst, pszIcon);
_ASSERTE(!__FUNCTION__ "RegisterClass failed");
cs.lpszClass = pszClassName;
Using the Code for Dialog Based Applications
In a dialog based application, we have to do two things.
The class name used for a normal dialog is
"#32770". When we want to use a different class, we need to tell the dialog template that it should use this special self defined class name, because we don't control the creation of the dialog. There is a property in the resource editor for a dialog to specify a user defined class name but VS-2008 and VS-2010 have a bug here and don't allow the user to enter some data here. The property is grayed and so disabled. Even a changed class name isn't shown in the property window.
But you can change the class name with the editor, and this information is not deleted by the resource editor when we may change the dialog later. So we open the RC file with our preferred editor, search the entry for the dialog template we want to change and add a
CLASSNAME statement as shown here:
IDD_OWNCLASSNAMEDLG_DIALOG DIALOGEX 0, 0, 199, 28
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
FONT 8, "MS Shell Dlg", 0, 0, 0x1
The only thing left now is to register a new class based on the system class
#32770 with our class name that we set in the dialog template before we call
The code you have to add is shown here and it isn't great magic:
wndcls.lpszClassName = _T("OwnClassNameDlg");
_ASSERTE(! __FUNCTION__ " Failed to register window class");
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
BTW: In fact,
"#32770" is not a class name. It is just a class name registered with an integer ID where
MAKEINTRESOURCE(32770) is used as a class name. It is also ok to use the string
- 10 May, 2011 -- Version 1.0