Click here to Skip to main content
Click here to Skip to main content

XDialogImport - How to share dialogs between projects

, 18 Jun 2003 CPOL
Rate this:
Please Sign up or sign in to vote.
XDialogImport describes a simple and effective method for sharing frequently-used dialogs between projects, using some documented and some poorly documented techniques.

Introduction

After you have worked on two or three major projects, you begin to understand that many apps incorporate common features, components, and dialogs. Just like you will set up a common directory of frequently-used functions, you can do the same thing for other common components. This article discusses one approach (there are others - see Other Approaches below) to sharing dialog resources between projects.

What exactly does "sharing a dialog resource" mean? Well, first there is the dialog resource definition, usually stored in a .rc file. And then there will be controls on the dialog, and these controls will each have an ID - such as IDC_NAME or IDI_MYICON. The definitions of these IDs must accompany the dialog's resource (.rc) file. It is convenient to store all these definitions together in one .h file - but it must be named something unique, and must not be named resource.h. And finally, the dialog will have some code - typically at least OnInitDialog(), DoDataExchange(), and maybe OnOk(). So for each dialog, there will be at least four files:

  1. Dialog.cpp - contains implementation code for the dialog.
  2. Dialog.h - contains class definition for dialog. Initially, this file and the one above should be generated by Visual Studio, so that later on you can use the Class Wizard in case you need to modify it.
  3. Dialog.rc - contains dialog's resource template, in a form that can be edited by Visual Studio's Resource Editor.
  4. DialogRes.h - contains definitions for IDs used in resource template. This file must have same format as standard resource.h, so that Visual Studio tools will be able to read and modify it.

    WARNING: You must have a DialogRes.h (or some other name) for each rc file. If you do not, Visual Studio will associate resource.h with the rc file, and your original resource.h will be overwritten. PLEASE MAKE A BACKUP.

But it is not enough to just organize the dialog's functionality into four files. It is also necessary to ensure that any app which includes these files can do so transparently: by this I mean it will not be necessary to edit or change any of the four files. When this requirement is met, you will have truly shareable dialogs. In the remainder of this article, I will discuss the specific things that must be done to meet this requirement.

Tricks

Trick #1

Achieving transparency is actually documented in MSDN, but few people make use of it. I refer to the fact that CDialog has three constructors:

CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);

CDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);

CDialog();

It is the first form that is important here. What we are trying to do is insulate the app from the specific implementation details of the dialog. Unfortunately, the usual Visual Studio-generated header file for dialogs has a line that looks like:

enum { IDD = IDD_ABOUTBOX };

This effectively ties the dialog to the app, because the app needs to know the value of IDD_ABOUTBOX if it is going to include About.h. With the standard enum approach, either the app or About.h must include AboutRes.h. This is very undesirable, because it means that all the IDs defined in AboutRes.h will be visible to the app, and hence must be unique across the app. If you are dealing with an app that has hundreds of dialogs, you will quickly run out of replacements for things like IDC_NAME.

This is where the first CDialog constructor comes in - that, plus,

one other trick

That is not documented too well: The only resource IDs that need to be unique are those that have application scope.. This means that dialog IDs, string resource IDs, and a few others need to be unique. All the rest (in fact, the majority) of IDs do not need to be unique application-wide, as long as they are unique within any one dialog.

Putting these things together, we know that we can use a string as the dialog identifier. So what we do is this:

  1. Include the four files in the project - collect or generate the four files mentioned above, for the dialog you wish to include in a project. It is important that the format of these files follow closely the Visual Studio format, to allow use of Visual Studio tools. In the FileView tab, right-click on the "Project files" entry (in this demo, it would be "XDialogImport files"). Select "Add Files to Project..." and then select the four files (for the demo, it would be About.cpp, About.rc, About.h, AboutRes.h). Visual Studio will complain about About.rc, because there is already a .rc file in the project:

    screenshot

    Just click on OK - About.rc will be included.

  2. Add to project rc file - go to "View | Resource Includes..." and in the bottom listbox, scroll down to the end. Insert #include "about.rc" right before the #endif:

    screenshot

  3. Remove the enum from About.h - no enum, no need to include AboutRes.h. Note that IDD_ABOUTBOX is not defined in AboutRes.h, so that it will appear in quotes when the About.rc resources are viewed in the ResourceView tab:

    screenshot

    When IDD_ABOUTBOX is double-clicked, the dialog from About.rc will be displayed in the Resource Editor:

    screenshot

  4. Use the first CDialog constructor - here is what the CAboutDlg constructor looks like:
    CAboutDlg::CAboutDlg() : CDialog(_T("IDD_ABOUTBOX"))
    {
        //{{AFX_DATA_INIT(CAboutDlg)
        //}}AFX_DATA_INIT
    }
  5. Include AboutRes.h in About.cpp - this will have no impact at all on any IDs that are defined in other app modules.

Finally, here is

Trick #3

As you have seen, you can double-click on IDD_ABOUTBOX to get into the Resource Editor. You can then change the dialog, add controls, etc., just as with any other dialog. But there is one thing you cannot do: Normally, you could go to View | ClassWizard and add variables for the various control IDs. If you do this with the demo, you will not see any of the control identifiers, such as IDC_ABOUT_EMAIL. Here is the trick: right-click on the dialog you see in the Resource Editor, and select ClassWizard.... You will be presented with this dialog:

screenshot

Click Cancel. You will then see the standard Class Wizard dialog, with all control identifiers:

screenshot

Tips

The key to creating a shareable dialog resource is to minimize coupling with the app. Here is how the About dialog looks in Debug mode:

screenshot

and here is how it looks in Release mode:

screenshot

In each of these, there are actually four pieces of data that are being retrieved from an external source:

  1. The name of the app is being loaded from a string resource:
    CString strTitle;
    if (!strTitle.LoadString(AFX_IDS_APP_TITLE))
        strTitle.Empty(); 
  2. The version and build numbers are loaded from the VERSIONINFO resource:
    WORD wFileVersion[4];
    CVersion version;
    version.Init();
    version.GetFileVersion(&wFileVersion[0],
                      &wFileVersion[1],
                      &wFileVersion[2],
                      &wFileVersion[3]); 
  3. The copyright statement is loaded from the VERSIONINFO resource:

    CString strCopyright(_T(""));
    version.GetLegalCopyright(strCopyright);
    m_Copyright.SetWindowText(strCopyright); 
  4. The email address is loaded from the VERSIONINFO resource:

    CString strEmail(_T(""));
    version.GetStringInfo(_T("E-mail"), strEmail); 

In addition to the above, About.cpp uses the global defines _DEBUG and BETA_VERSION to display additional information.

In summary, to effectively implement shareable dialogs, you must combine good organization with well thought-out design. In the demo About dialog, external information comes from string and version resources that are implemented in the app. This works well, but the consequence is that every app must implement these string and version resources in the same way, in order to be able to use the About dialog. There are other app-dialog interfaces possible, of course, but the point is that when you have chosen the interface, every app must implement the interface in the same way.

How to use

Using a dialog that has been included in the way described above is no different than using any other dialog:

void CXDialogImportDlg::OnButton1()
{
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
}

Goals

Of course there are other ways to realize shareable dialogs. In considering the various approaches, I had in mind a few goals that I did not want to give up:

  1. The approach must be simple to implement, and cost no more than regular dialogs to maintain.
  2. The standard Visual Studio tools (Resource Editor, Class Wizard, etc.) must be usable on the resulting dialogs.
  3. The dialog-app coupling must be minimal, to improve reusability.
  4. Ideally, the dialog's supporting files should not have to be modified at all, from one app to the next.

Other approaches

Keeping in mind the above goals, here are some other approaches that you might want to consider:

  • Load dialog from a DLL - There are many examples of how to do this. Downside: you have another DLL to ship with your app.
  • Use a COM component - In practice, the same as previous.
  • How to include a dialog without copying from .RC by Brad Bruce. Downside: You have to read the article for yourself and decide if this is something you would want to maintain.
  • Dialog Template by Max McGuire. This class allows you to create DLGTEMPLATEs on the fly. Downside: You exchange a GUI resource editor for a lot of code.

Acknowledgments

One piece of information that is indispensable in production apps is the build number. In the demo About dialog, the build number comes from the version resource. I use Auto-Incrementing Build Numbers by Navi Singh to automatically increment the build number inside the version resource. All you have to do is put the version resource inside the .rc2 file, replace the hard-coded versions with strings (see Navi's article), and install Navi's autobuild add-in. After that, each time you hit Build, the build number will be incremented.

Revision history

Version 1.0 - 2003 June 18

  • Initial public release.

Usage

This software is released into the public domain. You are free to use it in any way you like. If you modify it or extend it, please do consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Hans Dietrich
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.
 
Recently, I have moved to Los Angeles where I am doing consulting and development work.
 
For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions

 
Questionhow can i customize fontsize combo box with my specific values Pinmembersanthi_malli30-Oct-07 4:29 
GeneralNice code... but maybe not that practical PinmemberDouglas R. Keesler1-Nov-05 16:34 
AnswerRe: Nice code... but maybe not that practical PinmemberHans Dietrich5-Nov-05 0:32 
GeneralDoes this work in VS 2003 Pinmemberdigby the lonely lone ranger13-Oct-05 17:24 
GeneralRe: Does this work in VS 2003 PinmemberDanYELL23-Jan-06 5:22 
GeneralRe: Does this work in VS 2003 PinmemberAnna-Jayne Metcalfe21-Sep-06 0:57 
GeneralTwo file can't find in my project. Pinmembercop112-Jun-05 21:02 
Generalbest way to create those dialog files Pinmemberpreeti_ras13-Jan-05 11:48 
GeneralRe: best way to create those dialog files Pinmemberws_webking14-Apr-05 6:48 
GeneralRe: best way to create those dialog files Pinsussali130585-May-05 12:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 19 Jun 2003
Article Copyright 2003 by Hans Dietrich
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid