Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Provide Your Custom Class Name to your MFC Application

0.00/5 (No votes)
14 May 2011 1  
Provide your customized class name to MFC application SDI/MDI and dialog based

Introduction

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.

Background

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 IDR_MAINFRAME.

The code below just shows what you have to change in your mainfrm.cpp:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;

    // Just clear the styles we don't want.
    cs.dwExStyle &= ~WS_EX_CLIENTEDGE;

    // Check if our class is already defined
    LPCTSTR pszClassName = _T("OwnClassName");
    WNDCLASS wndcls;
    if (!::GetClassInfo(AfxGetInstanceHandle(), pszClassName, &wndcls))
    {
        // Get the current requested window class
        VERIFY(GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls));

        // We want to register this info with our name
        wndcls.lpszClassName = pszClassName;

        // Need to preset the icon otherwise the function GetIconWndClass
        // calling us will overwrite our class.
        LPCTSTR pszIcon = MAKEINTRESOURCE(IDR_MAINFRAME);
        HINSTANCE hInst = AfxFindResourceHandle(pszIcon, ATL_RT_GROUP_ICON);
        _ASSERTE(hInst!=NULL);
        wndcls.hIcon =     ::LoadIcon(hInst, pszIcon);

        // Register our class now and check the outcome
        if (!::RegisterClass(&wndcls))
        {
            _ASSERTE(!__FUNCTION__ "RegisterClass failed");
            return FALSE;
        }
    }

    // Now use our class 
    cs.lpszClass = pszClassName;
    return TRUE;
}

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
EXSTYLE WS_EX_APPWINDOW
CAPTION "OwnClassNameDlg"
CLASS "OwnClassNameDlg"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
...

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 dlg.DoModal();

The code you have to add is shown here and it isn't great magic:

...
    // Just get default class for the dialogs
    WNDCLASS wndcls;
    ::GetClassInfo(NULL,MAKEINTRESOURCE(32770),&wndcls);
    
    // Set our own class name
    wndcls.lpszClassName = _T("OwnClassNameDlg");

    // Just register the class
    if (!::RegisterClass(&wndcls))
    {
        _ASSERTE(! __FUNCTION__ " Failed to register window class");
        return FALSE;
    }
    
    COwnClassNameDlgDlg dlg;
    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 "#32770".

Have fun...

History

  • 10 May, 2011 -- Version 1.0

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here