2
votes

I have this MFC app that loads strings from string resource using CString::LoadString function. Each of the apps dialogue box's classes and its associated resources are contained in an MFC extension DLL.

CString::LoadString loads strings from the main module's(.exe) resource's string resource successfully but fails to load string from the DLL's resource's string resource.

In each case I get my instance handle for load string from CWinApp object by calling : CWinApp *WinApp = AfxGetApp(), and of course the instance's handle is WinApp->m_hInstance which I use as the first argument in my call to CString::LoadString function.

What could be the cause and what could be the solution.

2

2 Answers

1
votes

Are you passing the EXE's HINSTANCE to load a string from the extension library? Sounds like it.

With MFC, if you have extension libraries and you make sure your string identifiers are unique, you just need to call the CString::LoadString(UINT nID) version. Because extension libraries create CDynLinkLibrary structures that go into a global linked list, the LoadString(UINT) function will search through all your MFC libraries until it finds the HINSTANCE that contains that string, and then it will load from there. If you insist on using the LoadString() function with an HINSTANCE argument, be sure to use the HINSTANCE of the extension DLL, and not the extension of the EXE when you want to load a string or dialog from the DLL.

For small projects, like less than a dozen DLLs, you probably manage to just use unique IDs for everything. When you get into the insanely large projects like 100+ DLLs, then you have to use other techniques like specially named functions in your DLL that call AfxSetResourceHandle() or know to always use the HINSTANCE of the DLL. That's another topic.

1
votes

Just to complement Joe Willcoxson's answer, be sure to check that every MFC Extension DLL you are using,needs a special initialization code, similar to the example below:

#include "stdafx.h"
#include <afxdllx.h>

static AFX_EXTENSION_MODULE MyExtDLL = { NULL, NULL };

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        TRACE0("MyExt.DLL Initializing!\n");

        // Extension DLL one-time initialization
        if (!AfxInitExtensionModule(MyExtDLL, hInstance))
            return 0;
        new CDynLinkLibrary(MyExtDLL);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        TRACE0("MyExt.DLL Terminating!\n");
        // Terminate the library before destructors are called
        AfxTermExtensionModule(MyExtDLL);
    }
    return 1;   // ok
}

This code just takes care of CDynLinkLibrary creation, the key to share resources between MFC modules.

If all this are setup correctly -- and without ID clashes -- then it's simply a mather of calling:

CString str;
str.LoadString(IDS_MY_STRING_ID);

anywhere in your code, no matter where the string actually persists.

A good start point on resource IDs and numbering can be found in this link.