(Throughout the article, click on the thumbnails to see larger versions)
The Trouble with Resources
A typical MFC or ATL project will contain at least one resource (.RC) file. Associated with each resource file is a symbol definition file - named "resource.h" by default, which contains
#define directives for each of the symbols used in the project. Resource symbol definitions are created and modified by the Visual C++ Integrated Development Environment (IDE) when the resources for a project are edited.
Unfortunately, when it does so, it often gets it wrong. How often have you seen this message box whilst editing a dialog?
This happens because two symbols have the same value. The problem is that the IDE is not particularly intelligent at allocating symbol ID values - and does not provide any facilities to unravel the mess that can easily arise as a result. The end result can easily be runtime behavior which is unpredictable to say the least.
An Answer to the Problem
The Resource ID Organiser (ResOrg for short) is an Add-in for Visual C++ 5.0, 6.0 and .NET designed to help simplify one of the most annoying - and unnecessary - chores of developing/maintaining Windows applications: maintaining resource symbol IDs.
ResOrg came about when I finally got sick of renumbering resources by hand or using Excel. I was working on a fairly large multi-project application (there were 40 modules at the time), and the difficulty of maintaining the number of resources within the workspace (over 3200!) convinced me to do something about it. Surprisingly, I couldn't find any similar tools to do the same thing, though there are a couple of macros which do something similar, albeit in a much more limited fashion. There are actually three incarnations of ResOrg: a standalone application, a Visual C++5.0/6.0 add-in, and a Visual C++ .NET add-in. Whilst the application is a conventional tabbed MDI application which edits resource symbol files directly, the add-ins integrate with Visual C++ and therefore have direct access to the workspace currently being edited.
ResOrg offers many features to help make managing resource symbol files easier, of which the following are a small selection:
- Easy to interpret displays of the symbols within resource files.
- Detection of out of range and conflicting symbols, both within and between resource symbol files.
- Detection and correction of incorrect "Next Symbol" values.
- Customizable HTML reports.
- Manual and automated symbol renumbering.
- Automatic exclusion of specified symbols (such as
IDR_MAINFRAME) from renumbering operations.
- Available as both a Visual C++ add-in and a standalone application.
- Compatible with Visual C++ 5.0, 6.0, .NET 2002, 2003 and 2005.
ResOrg allows the resources within a given workspace to be viewed or edited easily. For each project within the workspace, it will allow the symbol definition file (it doesn't have to be called resource.h) to be viewed or edited directly. If (as happens all too often) a symbol file has two or more symbols with the same value, they will be identified as conflicting symbols and displayed in red in the Symbols Display (see the first screenshot).
As you'd expect, individual symbols can be added, edited or removed (be careful with the latter!), but the real power of ResOrg is its ability to detect conflicts and intelligently renumber resource symbols.
The Symbol Properties dialog for a symbol whose value conflicts with another in the same resource symbol file will warn of the conflict, and provides a quick way to resolve it:
The Symbol File Properties dialog allows statistics on the types of symbols in the symbol file to be viewed, and the Next Symbol values easily inspected and corrected:
In large projects, the ability to identify problems can become critical. To that end, ResOrg provides facilities for generating HTML reports showing the symbols in a module - or just those which ResOrg has identified having a problem with their name or value:
Automated Symbol Renumbering
If bulk changes are required, the Resource Symbol Renumbering Wizard will guide you through the process of renumbering all of the symbols in a given resource file (click on a thumbnail to see a larger image):
When run, the wizard will identify suitable ranges for the symbols, and renumber them appropriately. Conflicting symbol values can be fixed quickly and easily by this process.
Unfortunately, renumbering some symbols can cause problems. Although the Symbol Renumbering Wizard allows individual symbols to be excluded from renumbering operations, it can be convenient to globally exclude specific symbols (such as
IDR_MAINFRAME) from automatic renumbering across any file.
Exclusion of Symbols from Renumbering Operations
The "Fixed Symbols" page in the Options dialog provides the ability to do this:
Any symbols listed in this page will not be automatically considered for renumbering by the Symbol Renumbering Wizard.
Additional Features in ResOrg.NET
ResOrg.NET is the ResOrg add-in for Visual C++ .NET. As well as a radically different IDE, Visual C++ .NET also introduces a new extensibility model, which allows add-ins much closer integration with the IDE than previous versions.
Unfortunately, this comes at the price of backward compatibility, since the new extensibility model is not backward compatible to previous versions of Visual C++.
For ResOrg, the new model and IDE adds a whole pile of possibilities. In fact, when I started seriously looking at how to approach the IDE, it took me about a month to settle upon a design which was both useful and sufficiently unambitious for my first stab at working with the new IDE!
Although ResOrg.NET does not include a standalone ResOrg app (although it's buildable from the source) and therefore does not have an "Add-In" tab in the Options dialog - it has exactly the same capabilities as ResOrg. It does however add one new bit of UI - a "Tool Window" which shows a summary of the properties of a selected resource symbol file:
From the tool window, you can quickly see whether a symbol file has ID conflicts or if its "Next Symbol" values are in use...and view/modify its properties, or even launch the Symbol Renumbering Wizard. You can of course open the main ResOrg.NET UI to do more in-depth editing or multi-file conflict analysis.
IDE integration is likely to be further improved in subsequent versions, so watch this space!
ResOrg is a fairly complex product, and we try to produce updates as often as we reasonably can. However, releasing new versions is all very well, but how do you let those using the software know that it's been updated?
ResOrg includes several mechanisms to make this process easier (and reduce the number of versions we have to support!):
- Access to the ResOrg website from the Help menu within the application/add-in itself.
- A prompt (displayed the first time ResOrg is run after installation) asking the user whether they want to subscribe to the ResOrg Mailing List, upon which version updates are announced as soon as they become available:
- An automated mechanism to check whether version updates are available. If so, a message is displayed giving details of the new version, and offering the option to visit the download page, from where you can download the new version if you choose:
Note that the update check does not send any information to the server - it merely reads a small text file to determine the latest released product version, and compares that against the version which is currently running. If the running version is older than that reported by the server, the details of the new version will be displayed in the prompt above.
By default, this check occurs every 7 days. This interval can be changed (or version checking disabled entirely) from the "Updates" page of the Options dialog:
Installation (Visual C++ 5.0/6.0 version)
ResOrg has its own installer, which will install the necessary files for you. Although it will not configure Visual Studio to load the add-in, the ResOrg application will optionally set up the registry entries needed to configure Visual Studio to do so. Since the installer launches the application by default anyway, this usually happens automatically.
If you need to configure it to do so manually, follow the following steps:
- Copy the ResOrg DLLs to the location you want them to run from (the default location for add-ins is C:\Program Files\Microsoft Visual Studio\Common\SharedIDE\Add-Ins).
- Start Visual C++ and select the Customize command on the Tools menu.
- Select the "Macros and Add-Ins" tab.
- If the entry "Resource ID Organiser" does not appear in the list control, press the Browse button to find the directory containing the DLLs, and select ResOrgAddIn.dll. Once you've done this, the entry should appear in the list control.
- Check the box next to the name of the add-in to load it. You should see the ResOrg toolbar, which you can dock anywhere convenient.
Installation (Visual C++ .NET version)
ResOrg.NET has its own (MSI based) installer, which will install the necessary files for you and configure Visual Studio to load the add-in. Once installed, the add-in can be loaded from the Add-In Manager on the Tools menu of the Visual Studio IDE.
When the add-in is loaded, it will re-create its commands and toolbar. You can dock the ResOrg toolbar anywhere convenient or hide it if you prefer.
Note: Unfortunately for add-in authors, the installation of add-ins under Visual Studio .NET is much more complex and fraught than it was under Visual Studio 6.0 * and can cause the IDE to fail to load in certain circumstances. To reduce the risk of this happening, it is highly recommended that you do not install an add-in whilst Visual Studio .NET is running.
* Early indications are that Visual Studio .NET 2005 (Whidbey) is slightly more tolerant than Visual Studio .NET 2002 and 2003, however.
Should you find that Visual Studio .NET refuses to load the add-in, the following sequence of operations should fix it:
- Shut down all copies of Visual Studio .NET.
- Uninstall the add-in using the Add/Remove Programs applet of Control Panel.
- Open the Registry Editor and remove all keys from
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.x \AddIns\ResOrgNETAddIn and
- Reinstall the add-in.
- Restart Visual Studio .NET. The add-in should load automatically, create its toolbar, and add its commands to the Tools menu.
If after doing the above, you still can't get the add-in to load correctly, please contact us and we'll try to investigate further.
System Dependencies (Visual C++ 5.0/6.0 version)
In order to function correctly, ResOrg may require several system DLLs to be installed:
- ComCtl32.dll version 5.80
- Shlwapi.dll version 4.71
- Mfc42.dll version 6.00.8665.0
- Msvcrt.dll version 6.00.8797.0
The installer includes appropriate copies of mfc42.dll and msvcrt.dll which are installed into the application folder.
ResOrg uses features introduced in the common controls updates shipped with Internet Explorer 5.0. Specifically, it requires version 5.80 of comctl32.dll to be installed. ResOrg will check the version of comctl32.dll upon start-up, and inform you if an update is necessary. You can download an installer (50comupd.exe) for the update from the Microsoft web site.
An appropriate version of Shlwapi.dll is included with Windows 98, NT 4.0 or later versions of Windows. If ResOrg is to be installed on a Windows 95 system which does not have this file, it can be installed by installing Internet Explorer 4 or later.
The ResOrg source includes both the Visual C++ 6.0 workspace and Visual C++ .NET solution. The projects within the two workspaces (to use VC6 terminology) differ slightly, although the core components are common. The projects are:
||An extension library hosting David Wulf's Office2K style file dialog class and an associated
||The CodeJock library (no longer freely available I'm afraid) provides the framework for the user interface, including support for the docking projects display and "cool" menus.
||My own extension library which provides general purpose classes, many of which are from either CodeGuru, CodeProject or MSJ, renamed with a "CNG" prefix for namespacing reasons
||The Visual C++ 5.0/6.0 add-in (an MFC regular DLL)
||The standalone ResOrg application
||The Core ResOrg module. Most of the useful and interesting stuff lives here!
||The Visual C++ .NET add-in (an MFC regular DLL)
||An ActiveX control DLL used by the Visual C++ .NET add-in to host tool windows within the IDE
The ResOrg add-ins are a little unusual in that they are implemented as an MDI application rather than the usual modal dialog or property sheet. To implement this, the mainframe contains a
DoModal() method which uses
CWnd::RunModalLoop() to create a modal mainframe which performs in a similar manner to its
CDialog counterpart. When the add-in is invoked, its main window will appear (starting the modal loop), and the Visual C++ main window will be hidden. When the main window of the add-in is closed (ending the modal loop), Visual C++ will reappear.
Beyond that, their structure is that of a conventional MDI application, save for some additional plumbing to integrate a "workspace" docking window and David Wulf 's Office2K style File Dialogs (the latter in the VC 5.0/6.0 version only).
UI aside, the core of ResOrg is fairly simple: a class (
CResourceSymbolManager) which manages a resource symbol file, and a class representing a resource symbol (
CResourceSymbol). The add-ins themselves use a helper class (
CVc7AutomationHelper as appropriate) to insulate itself from the COM interface of Visual Studio, since I found that doing so makes the code more readable.
The Visual C++ 6.0 workspace has integrated Source Code Control enabled. To open the workspace without access to the SourceSafe database, please run the macro Toggle DevStudio SCC.vbs (in the source code ZIP file) to disable integrated source code control before attempting to load it. You will have to restart Visual Studio for the change to take effect.
- Since the Symbol Renumbering Wizard is implemented using the Wizard97 style, it does not display quite as intended on Windows 95 systems (the background of controls on the first and last page aren't transparent as they should be). Having said that, the display is quite readable and all features work as intended.
- The source does not support Unicode. This is more down to the fact that I haven't got around to it than anything else...
- The source can be compiled only with Visual C++ 6.0 and .NET 2003 - Visual C++ 5.0 and .NET 2002 are not supported. The former limitation is mainly because of the use of
CPropertyPageEx, and the latter just because maintaining two sets of project files is bad enough, let alone three!
- After the ResOrg app has been used to configure Visual C++ 5.0/6.0 to load the add-in, multiple toolbars may be visible in the Visual Studio IDE if a previous version was installed. Unloading the add-in and reloading it through Visual Studio cures the problem (or you can just delete the toolbars).
- The ResOrg.NET tool window has an OLE "in-place editing" border around it when first created - this seems to be a result of it being an ActiveX control, but I haven't been able to nail it down yet.
- The icon buttons in the ResOrg.NET tool window have tooltips, but for some reason they're not being displayed.
As with any project of this nature, there are always a million things that could be done to make it that little bit more useful. Which ones actually get implemented is a matter of luck, judgment, peer-pressure and time!
Some of the major features I hope to add to future versions of ResOrg include:
- Improved integration between ResOrg and Visual C++
- Improved support for conflict checking throughout a workspace
- Additional HTML reports
ResOrg in its current form would not have been possible with the existence of CodeProject, CodeGuru and MSJ. Code from these sources used by ResOrg includes (but isn't limited to):
Thanks are also due to Oz Solomonovich for his excellent WndTabs add-in, which gave me the inspiration to get started on this in the first place...
A Word of Caution
Please exercise caution when renumbering symbols using ResOrg. Under certain circumstances, doing so can cause problems, which is the last thing I want to happen.
The most significant issues I'm aware of are:
- If you have a dialog template which contains a bitmap resource, the Visual C++ Resource Editor stores the ID of the bitmap as a literal value, rather than an ID. Changing the value of the bitmap's ID will break this association, and you will have to re-enter the ID in the dialog editor or the bitmap will not be displayed.
- The icon shown by the Windows shell for an application is that with the lowest ID. If you renumber the icons, this may no longer be the case, and the wrong icon may be shown.
- Visual C++ will not automatically rebuild implementation files as a result of resource symbol changes, since doing so would cause all dependent files (and there could be a lot of them) to be rebuilt every time a resource symbol was added or changed.
Unfortunately, when you renumber symbols, this is exactly what you want to happen - if you don't rebuild the right files, all sorts of strange behavior can result! If in doubt, clean the affected projects before attempting to rebuild them.
MFC Technical Note TN035: Using Multiple Resource Files and Header Files with Visual C++ - discusses this subject.
Since ResOrg allows you to specify which symbols you want to renumber (and how to do it), you can exclude symbols from the renumbering process if changing their values is likely to cause problems.
A good version control system is invaluable here, since it provides a quick way to review (and throw away if necessary) any changes made. If you haven't got access to one, please back up your resource and resource symbol files before attempting to renumber symbols (WinDiff can be used to review the changes if necessary, but it's a poor substitute I'm afraid).
Ultimately, I hope to add the capability to properly handle resource files (a subject for another article, I think...). Once this is in place, ResOrg will be able to circumvent some of these issues.
6th January, 2005
Minor update to the article to add details of the automated version checking included within ResOrg, and add troubleshooting information for Visual Studio .NET add-in installation. The code and binaries are unaffected by this update.
31st December, 2004
ResOrg version 1.6.1 released to CodeProject. This release adds support for Visual C++ .NET 2005.
Symbols and Symbol Files:
- Added support for toolbar (
IDT_xxx) and accelerator (
- Added support for detection of out of range symbols, based on symbol type and the defined base values for the associated file.
- Added support for the "
_APS_NO_MFC" define sometimes found in non-MFC projects.
- Added support for "Fixed" symbols. Such symbols (e.g.,
IDR_MAINFRAME) will be excluded from renumbering operations, by default).
- Added an "Autosave Symbol File Configuration" option to the "Symbols" page of the Options dialog. When active, an XML file containing the symbol file configuration (Base Values etc.) is automatically written when a file is saved or the Base Values are changed.
- Added a "Check for out of range symbols" control to the "Symbols" page of the Options dialog. A corresponding control has also been added to the "General" page of the Symbol File Properties dialog.
- Added "Next Problem" and "Previous Problem" commands to Symbols Displays.
- The "Properties" command on the main toolbar now displays the properties for the current file if the properties for a symbol cannot be displayed.
- Added dynamic splitter windows to Symbols Displays.
- Double clicking status bar panes now does something vaguely sensible.
- Added a "File Properties" button to the "General" page of the Symbol File Properties dialog to provide access to the general properties for the file.
- Revised the layout of the Report dialog. It is now resizable, and the stylesheet pathname edit control is now a combo box showing all recently used report templates.
- Added Problem Symbol Report.
- Added table sorting capability to HTML reports (courtesy of Mike Hall - www.brainjar.com).
- Various minor layout improvements.
- Added support for Visual Studio .NET 2005.
- Updated the "author" image in the About box and rebranded as a Riverblade product.
- Toolbar buttons in the ResOrg.NET add-in are now stored in a satellite DLL and have transparent backgrounds.
- Added an icon to the tool window displayed by the ResOrg.NET add in.
4th July, 2003
ResOrg version 1.5.2 released to CodeProject. This release adds support for Visual C++ .NET 2003.
- Added support for multi-file conflict checking, through a new "Open Together" command on the context menu of the Workspace Display. The Symbol File Properties dialog also displays an additional tab (named "Files") when such a display is opened.
- Added conflict filtering to the Symbols Display (multi-file Symbols Displays can be set to be filtered by default through a new setting in the Options dialog).
- Added support for XML export and HTML reports. A predefined or user defined XSL stylesheet is used to generate HTML reports, but you can also supply your own if you're feeling adventurous. I'll probably add more stylesheets in the future.
- The Symbol File Properties dialog has gained a "Base Values" page, and is now resizable.
- Improved support for symbol base values (these are now the responsibility of the appropriate
CResourceSymbolManager object, and calculated when the symbol file is loaded).
- Website/email addresses are now obtained from the registry rather than hard-coded (I learnt the importance of this one the hard way when I had to move the ResOrg website at the end of 2002!).
- Removed the
TCS_SCROLLOPPOSITE style from the MDI tab control to prevent tabs jumping to the opposite side of the window.
- Corrected bugs in the renumbering process which could cause invalid values to be assigned under certain circumstances.
- Various modifications for better compatibility with Visual C++ .NET. In particular, a couple of bugs in the ResOrg.NET tool window have been fixed, and the ResOrg.NET installer also now forces the add-in's commands to be recreated, which will hopefully make the installation process much less problematical.
- Upgraded the ResOrg.NET solution to Visual C++ .NET 2003.
- The "Fix Conflicts" command now uses the base values for that symbol type defined in the "Base Values" page of the Symbol File Properties dialog.
- Added a manifest to the ResOrg application to allow support for visual styles on WinXP systems.
- Improved version checking code. It will now tell you if your version is newer than that on the website, which is proving useful to me while testing new versions!
- Removed the QHTM module (it's just more than I need for ResOrg).
- Corrected/improved some string table prompts.
- Added support for native (ComCtl v6) sort images in header controls.
- Updated website address on file banners.
- Changed name/email address throughout the code. The act that was "Andy Metcalfe" is now history.
- Updated the splash screen and About box. Added a fade effect when the splash screen closes. Also added a mug shot to the About box (just call me a vain cow, OK?).
- Started DOxygen'ing the source code.
12th August, 2002
ResOrg version 1.4.5 released to CodeProject. This release marks the debut of ResOrg.NET (thanks to Nick Hodapp of Microsoft for making this possible).
- Added "Use Office XP style menus" option to allow the user to specify whether they want the old or new style menus.
- ResOrg now uses the VS.NET visual style for file dialogs used when running on Windows XP systems.
- The About box is now expandable - it now includes a list of the loaded modules.
- The splash screen and About box now display the target environment (Visual C++ 5.0/6.0 or Visual C++ .NET).
- Resource Symbol Files are now marked as modified if multiply selected symbols are deleted in the Symbols Display.
- Improved column auto-sizing in the Symbols Display.
- Corrected a bug in the calculation of "Next Symbol" values.
- The "Back" button on the "Completion" page of the Symbol Renumbering Wizard now correctly opens the "New Symbol Values" page, rather than the "Base Values" page as before.
- Corrected the control layout in the "General" property page for resource symbol files.
CResourceSymbolBuffer class has now been renamed to
CResourceSymbolManager, and the header file parsing/writing code within it moved to a new class (
CResourceSymbolFileBuffer). This is more to make the code cleaner than anything else.
- Lots of modifications for compatibility with Visual C++ .NET.
- Improved parsing of VC.NET project files (.vcproj) to make the parser more robust.
- Renamed the
ResOrgUtils module to
CVc6AutomationHelper, and moved it to the
ResOrgCore module. Added a corresponding
CVc7AutomationHelper class in the ResOrg.NET version.
- Revised the way symbol value conflicts are stored, to remove a two-way code dependency which caused big problems in Visual C++ .NET.
7th May, 2002
ResOrg version 1.4.4 released to CodeProject.
- Traded in the old ResOrg logo for a much improved one by Stefan Pedersen. The splash screen, About box and Symbol Renumbering Wizard have all been updated to use the new logo.
- Replaced the File Properties dialog with a Property Sheet.
- Integrated a new "this is what the new values will be" page to the Symbol Renumbering Wizard.
- Double clicking on a symbol in the Select Symbols Page of the Symbol Renumbering Wizard now includes/excludes it from the renumbering process.
- Added an "Original ID" column to the Symbols Display.
- Added "Fix Conflicts" and "Restore Original Value" commands to the context menu of the Symbols Display.
- Added a "Properties" command (which opens the File Properties dialog for the corresponding resource symbol file) to the context menu of the Workspace Display.
- Added a new pane to the status bar (an indicator to let you know if the Next Symbol values are in use) and removed the duff ones (NUM LOCK etc.).
- Added a new option to determine whether development versions should be included when checking for updates.
- Added the following options: Prompt the user after loading a file if its "Next Symbol" values are in use; Automatically correct "Next Symbol" values when necessary; Show text on toolbars; Automatically reload modified files and Hide the workspace display when not in use.
- Added support for VC7 workspaces and project files (though the ResOrg source code doesn't compile under VC7 yet).
- The workspace now uses the "flat" look.
- Upgraded the CodeJock Library to BCMenu 3.03 (WinXP style and lots of bug fixes).
- Changed the formatting of symbol
#define directives written to resource symbol files to be a closer match to the Visual C++ 6.0 format (better for file differencing).
- Corrected the order in which the "Next Symbol" values are written to resource symbol files.
_APS_3D_CONTROLS value is now written to a resource symbol file only if its value is 1 (i.e.
CResOrgVersionCheck::DoThreadFunc() now resets
NULL after calling
OnDownloadCompleted() - this prevents a continuable exception when running under the debugger on Win2000 systems.
- Fixed a bug in the calculation of Next Symbol values after symbol renumbering.
- Added some
#defines from AfxPriv.h to CJDockContext.cpp in the CodeJock library (the August 2001 Platform SDK broke it).
- Got rid of compiler warnings. ResOrg modules are now compiled at level 4 with the "warnings as errors" option enabled.
CRenumWizSelectSymbolsPage::OnWizardBack() now re-enables the "Next" button just in case it was disabled (thanks to Arnt Witteveen for the bug report).
- Corrected the background colors in the Status Bar.
- Various other minor bug fixes.
24th July, 2001
ResOrg version 1.3.10 released:
- Fixed symbol ID conflicts in ResOrgUtils_Res.h.
- The Symbols Display list control is now created with the
LVS_SHOWSELALWAYS style so that the selection is retained when it loses the focus.
- Corrected the Mailing List prompt to point at the new mailing list.
- ResOrg now terminates lines with carriage return-linefeed pairs instead of single linefeed characters.
- Reduced dependencies on Shlwapi.dll.
21st July, 2001
Removed shlwapi.dll from the installer (it was causing problems on some NT 4.0 systems), and added a ZIP file containing just the binaries. No code changes (yet...).
15th July, 2001
ResOrg version 1.3.9 first released to CodeProject.
I'd like to take this opportunity to thank all of the developers who have taken the time to either give me feedback or participate in testing, including: Beth Mackenzie (my partner in
crimecoding!), Leo Davidson, Gavin Jerman, Penina Weiss, Oz Solomonovich, Jean Palmer, Mustafa Demirhan, Andrew Gebbie, Don Sanders, Bassam Abdul-Baki, Dave Wolfe, John Williams, Glynn Morgan, Andy Greenwood, Martin Palmer, David Wulff and Nick Hodapp (my apologies if I've left anyone out!).
The latest information on ResOrg can be found on the ResOrg website.
Finally, although not a part of the product itself, the Riverblade Developers' Blog (Products, the Universe and Everything) is another way to find out about the current plans for ResOrg, and discuss forthcoming or requested features. (An RSS feed is also included for convenience. If you have any comments, suggestions, bug reports etc., please feel free to contact us, or record your suggestion either here or in a comment on an appropriate post in the blog.)