7
votes

I have built an MFC project (executable) as dll or more accurately I have added export functions to it just like a dll. I can load and execute the exported functions however the problem is that when I load the module, the main application class CMyApp theAppdoesn't get instantiated. This means I can't use the theApp object which I really want to. I have even modified the function below so it matches that of a standard MFC dll.

BOOL CMyApp::InitInstance()
{
   CWinApp::InitInstance();

   return TRUE;
}

I am using LoadLibrary() to load the exe/dll. Note, I am not exporting any c++ class from dll, just few standard C style functions. These functions internally would like to use the main application object but it is not instantiated (its constructor is never called). What do I need to do the app class is instantiated properly just like it would in a standard mfc dll?

** Update **

Ideally I would like to have the exported functions available in exe itself and I have already done that but when I load it with LoadLibrary the application theApp class doesn't get instantiated. I believe this is same behavior even if it was a dll. My projects has many dependencies and creating a new dll project and adding all files and libraries is too cumbersome. I would really like to change the project settings of the current project if any so I can have it loaded with the application class properly instantiated just like a regular MFC dll. But the question is what project settings I need to change?

Note: I will take out instantiating of main dialog object with #define. Basically the dll version of InitInstance() function can be as simple the one I posted above.

2

2 Answers

6
votes

What you describe is a Regular DLL Dynamically Linked to MFC. Selecting part of the description from this linked article gives you a sub-set of the characteristics:

A regular DLL, dynamically linked to MFC has the following requirements:

  • These DLLs are compiled with _AFXDLL defined, just like an executable that is dynamically linked to the MFC DLL. But _USRDLL is also defined, just like a regular DLL that is statically linked to MFC.

  • This type of DLL must instantiate a CWinApp-derived class.

  • This type of DLL uses the DllMain provided by MFC. Place all DLL-specific initialization code in the InitInstance member function and termination code in ExitInstance as in a normal MFC application.

If you use the New Project Wizatd from VS2010 and choose the option to create an MFC DLL, this is the default you get, although you can select other types of DLL from the wizard options:

wizard

So, create a regular DLL. It will generate the necessary boilerplate code for you, including a CWinApp derived class. For example:

// CMFCLibrary1App

BEGIN_MESSAGE_MAP(CMFCLibrary1App, CWinApp)
END_MESSAGE_MAP()

// CMFCLibrary1App construction

CMFCLibrary1App::CMFCLibrary1App()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}

// The one and only CMFCLibrary1App object

CMFCLibrary1App theApp;

// CMFCLibrary1App initialization

BOOL CMFCLibrary1App::InitInstance()
{
    CWinApp::InitInstance();

    return TRUE;
}

I suggest you create such a project and then port your existing code into it, then you will have all of the correct project settings and structure from the start. This is much easier than trying to convert e.g. an exe project to a dll project.

Be sure to note the differences in the way you must write your exported functions. As the link above says:

Because this kind of DLL uses the dynamic-link library version of MFC, you must explicitly set the current module state to the one for the DLL. To do this, use the AFX_MANAGE_STATE macro at the beginning of every function exported from the DLL.

So even if you only export C-style functions, if they wrap objects that use MFC, then the exported functions and any public functions of exported classes must use the above technique, particularly for multi-threaded applications.

The New Project template helpfully inserts comments explaining this too:

//TODO: If this DLL is dynamically linked against the MFC DLLs,
//      any functions exported from this DLL which call into
//      MFC must have the AFX_MANAGE_STATE macro added at the
//      very beginning of the function.
//
//      For example:
//
//      extern "C" BOOL PASCAL EXPORT ExportedFunction()
//      {
//          AFX_MANAGE_STATE(AfxGetStaticModuleState());
//          // normal function body here
//      }
//
//      It is very important that this macro appear in each
//      function, prior to any calls into MFC.  This means that
//      it must appear as the first statement within the 
//      function, even before any object variable declarations
//      as their constructors may generate calls into the MFC
//      DLL.
//
//      Please see MFC Technical Notes 33 and 58 for additional
//      details.
//

The Technical Notes referred to in the above comments are:

Seeing that you use LoadLibrary to dynamically load your DLL, if you are doing this from an MFC application, you would be wise to use AfxLoadLibrary instead (and the corresponding AfxFreeLibrary). As MSDN says:

For MFC applications that load extension DLLs, we recommend that you use AfxLoadLibrary instead of LoadLibrary. AfxLoadLibrary handles thread synchronization before you call LoadLibrary. The interface (function prototype) to AfxLoadLibrary is the same as LoadLibrary.

The documentation for AfxLoadLibrary has more details.

0
votes

I just had the same problem and my problem was an empty lpszClassName for RegisterClassEx. Make sure you call CreateWindow then with the same string.

If that's not the case for your problem, print the actual error message with GetLastError(). Missing lpszClassName resulted for me in error code 1407.