12.4. Managing resources in a resource only DLL?

Microsoft Visual C++/Microsoft Foundation Classes


12.4. How can I manage resources in a resource only DLL and still benefit from ClassWizard?

The following text is available as RESDLL.ZIP in the MSMFC library on CompuServe (applies to MSVC20):

How To Manage An MFC Project Storing Its Resources Into A Resource-Only DLL

Software localization is much easier when your project stores its resources in a resource-only DLL. There area also many situations where storing the project's resources in a DLL can be a good idea.

However, if this project is an MFC project, doing so will generate a major drawback: you will not benefit from the Class Wizard capabilities any longer because the resources will be managed in a separate project.

However, there's a trick that you can use to develop your project as if it were a standard project while being able to quickly switch to the resource-only DLL model. Here's how to proceed:

METHOD 1 :

  1. Create your project as usual using AppWizard (we'll name it TEST).
  2. Close the project and create a new DLL project in the same directory (call it RESDLL). When you click on the Create button, VC++ opens the Add file dialog. Take this opportunity to add the resource file of the previous project (TEST.RC) to this new project.
  3. Before being able to compile the resources of the TEST project as a resource-only DLL, you must add the /NOENTRY option to the linker. Unfortunately, the settings dialog box of VC++ doesn't allow to do that in a simple way:
  1. Select Project|Settings from the man menu.
  2. Click on the Link tab.
  3. Select General from the category combobox.
  4. In the Object/Library Modules field, remove all references to any .LIB file (they are useless) and add /NOENTRY. This option should then appear in the Common Options display area.
  5. Click OK and compile. You now have a DLL containing only the resources for your project.
  1. Do not open the TEST.MAK project. Instead, copy TEST.MAK to TEST_RES.MAK in your project directory.
  2. Open TEST_RES.MAK and remove TEST.RC from the project files.
  3. Select Project|Settings, click on the General tab and add "USE_RESDLL" to the list of Preprocessor Definitions.
  4. Open TEST.H and modify the class declaration of CTestApp this way:

public:
    CTestApp();
 
#ifdef USE_RESDLL
public:
    virtual int ExitInstance();
private:
    HINSTANCE m_hInstDLL;
#endif //USE_RESDLL
  1. Open TEST.CPP and modify CTestApp::InitInstance as follows. Also, add the newly declared ExitInstance member function:
BOOL CTestApp::InitInstance()
{
    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need.
    #ifdef USE_RESDLL
    if ((m_hInstDLL = LoadLibrary("resdll.dll")) == NULL)
    {
        return FALSE; // failed to load the localized resources
    }
    else
    {
        AfxSetResourceHandle(m_hInstDLL); // get resources from the DLL
    }
    #endif
    //…#ifdef USE_RESDLL
        int CTestApp::ExitInstance()
        {
            FreeLibrary(m_hInstDLL);
            return CWinApp::ExitInstance();
        }
    #endif
  1. Compile. TEST_RES.EXE should work very nicely, loading its resources from the DLL.
  2. Close the project and open TEST.MAK. Compile. TEST.EXE should also work very well but this time, the resources are loaded from the .EXE file because you had not defined USE_RESDLL in this version of the project.

BEWARE:  When switching from one model to another, you must either Rebuild All or touch TEST.CPP. Otherwise, you'll have problems.

Now, you are able to modify your resources and to use Class Wizard when you work with TEST.MAK. To build the resource-only DLL version of the project, just switch to TEST_RES.MAK after recompiling RESDLL (RESDLL.MAK) if changes have been made to the resources.

It's that easy!

METHOD 2 :

  1. Proceed like above for steps 1, 2 and 3
  2. Instead of creating a new project, copy TEST.RC to RESDLL.RC. Remove TEST.RC from your project and add RESDLL.RC. A different name is somewhat safer.
  3. Double-click RESDLL.RC to trigger a rebuild of the .CLW file.
  4. Apply the "Exclude File from Build" command to RESDLL.RC. (Project|Settings, General Page, "Exclude File From Build")
  5. Delete TEST.CLW and TEST.RC.

Now TEST and RESDLL will work together through the ClassWizard. The resources defined in RESDLL.RC will not be added to TEST.EXE. This method is simpler but doesn't allow you to test your program in both cases (resources in the DLL or resources linked to the .EXE file). I prefer the latter when developing because I do not have to bother about orphaned DLLs when a GPF occurs (although this is less a problem under NT).

Don't forget to recompile the DLL before testing your program each time you modify the resources. A batch file calling NMAKE installed in the Tools menu will certainly be faster than switching from project to project. Using the "New Target" facility won't help in that case.

It would be nice if VC++ had the same capability as Borland C++: a project can contain multiple independent targets. So, the developer is able to manage DLL and EXE creation from within the same project.

Patick Philippot, CIS Email, 8/3/95