![]() |
Desktop Development »
Dialogs and Windows »
General
Intermediate
License: The Code Project Open License (CPOL)
XDialogImport - How to share dialogs between projectsBy Hans DietrichXDialogImport describes a simple and effective method for sharing frequently-used dialogs between projects, using some documented and some poorly documented techniques. |
VC6Win2K, WinXP, Win2003, MFC, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
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:
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.
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,
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:

Just click on OK - About.rc will be included.
#include "about.rc" right before the #endif:

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:

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

CDialog constructor - here is what the CAboutDlg constructor looks like: CAboutDlg::CAboutDlg() : CDialog(_T("IDD_ABOUTBOX")) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT }
Finally, here is
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:

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

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:

and here is how it looks in Release mode:

In each of these, there are actually four pieces of data that are being retrieved from an external source:
CString strTitle;
if (!strTitle.LoadString(AFX_IDS_APP_TITLE))
strTitle.Empty();
WORD wFileVersion[4]; CVersion version; version.Init(); version.GetFileVersion(&wFileVersion[0], &wFileVersion[1], &wFileVersion[2], &wFileVersion[3]);
CString strCopyright(_T("")); version.GetLegalCopyright(strCopyright); m_Copyright.SetWindowText(strCopyright);
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.
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();
}
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:
Keeping in mind the above goals, here are some other approaches that you might want to consider:
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.
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.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 18 Jun 2003 Editor: Smitha Vijayan |
Copyright 2003 by Hans Dietrich Everything else Copyright © CodeProject, 1999-2009 Web09 | Advertise on the Code Project |