Export dialogs in MFC Extension DLLs

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

It seems to be quite easy to export dialogs from mfc-extension dll's. Just export the corresponding class with AFX_EXT_CLASS and your done. If you do so with an application and a dll you create from scratch you probably even will succeed. But if you insert more and more resources in both the application and the dll, you will get some serious bugs. Here is the reason:

The regular way to identify a specific resource is its ID. This is an integer constant defined by the resource editor. Now say you have got a resource (which is a string) called ID_MY_TEXT.

  
	CString strText;
	strText.LoadString( ID_MY_TEXT );
	afxDump << strText;

Code like this prints the resource-string into the debug window. Sometimes you may get a wrong text and this happens only if the text is in a mfc-extension-dll (mfc-ext-dll). The reason for this error lies in the way the application gets a resource. Since both the application and the dll can have a resource file, IDs can be the same for different resources. (Which is very likely because the VC resource editor starts numbering the IDs at a certain value for each module.)

As you may guess the order the application searches for a resource is first in your application and afterwards in your dll(s) (and finally in the mfc-resources). We need to change the search order for resources.

There is another article on this site which deals with dialog exports from DLL's. But that (as far as I have tested) works only in regular-mfc-dlls.

I wrote a class that (with a little change in the dll main source file and the dialog) will enable you to freely call your dialog from wherever you want. Like:

  
CMyApp::OnDLLDialog()
{
    CDLLDialog dlg;
    dlg.DoModal();
}

As you see there is no need for an export function (which would not be very OO).

I wrote a simple class that sets the resource handle of the dll at its construction and sets back the previous handle at its destruction.

Here it is:

/////////////////////////////////////////////////////////////////////////////////////////////
// File ExtDllState.h
//////////////////////////////////////////////////////////////////////////////////////////// 
#ifndef __EXTDLLSTATE_H__
#define __EXTDLLSTATE_H__
 
class CEXTDLLState
{
public:
  CEXTDLLState();
  ~CEXTDLLState();
protected:
  HINSTANCE m_hInstOld;
};
 
#endif
////////////////////////////////////////////////////////////////////////////////////////////
File ExtDllState.cpp
//////////////////////////////////////////////////////////////////////////////////////////// 
CEXTDLLState::CEXTDLLState()
{
  m_hInstOld = AfxGetResourceHandle();
  AfxSetResourceHandle(extensionDLL.hModule);
}
 
CEXTDLLState::~CEXTDLLState()
{
  AfxSetResourceHandle(m_hInstOld);
}
//////////////////////////////////////////////////////////////////////////////////////

Quite short as you may see, but there is a little more to do:

Copy the class texts from above into the files ExtDllState.h and ExtDllState.cpp. Put BOTH files in a public include directory where every project can reach it. In your DLL go to the main source file (which is named after the DLL). Here you find something like this:

static AFX_EXTENSION_MODULE MY_DLL_NAMEDLL = { NULL, NULL };
where MY_DLL_NAME your dll name is (:

Replace this variable name with "extensionDLL". Below this line put the following lines:

 
    #include "EXTDLLState.h"
    #include "ExtDllState.cpp"

Look for occurrences of MY_DLL_NAMEDLL in the rest of the file and replace it with extensionDLL. Occurrences can only happen in this file since the variable is static.

Now if you want to export a Dialog go into the source file of the corresponding class and include EXTDLLState.h again. Override the function DoModal() (Best done with the ClassWizard). You should get something like:

int CMyDLLDlg::DoModal()
{
  // TODO: Add your specialized code here and/or call the base class
  return CDialog::DoModal();
}
replace the TODO line with "CEXTDLLState State;". Now it looks like

int CDLLDlgDlg::DoModal()
{
  CEXTDLLState State;
  return CDialog::DoModal();
}

With this approach you got a comfortable way to export classes that use resources. Be aware that if you need resources in other places too, to define CEXTDLLState before use. (Especially this must be done with modeless dialogs!!!).

You can use CEXTDLLState everywhere you want to access resources in mfc-ext-dlls. You will always get the right thing. I hope this will help some of you, since I had some troubles till I found an easy and nice way to do handle this.



Comments

  • Small tweak

    Posted by Sumyrda on 04/18/2017 05:00am

    This didn't work out of the box for me (because extensionDLL.hModule was null when my code got to that point), but the following variant works. Instead of: AfxSetResourceHandle(extensionDLL.hModule); Do something like this: AfxSetResourceHandle(GetModuleHandle("MyExtensionDllName.dll"));

    Reply
  • Assertion failute in Debug build

    Posted by rahul.shukla on 09/09/2008 02:17am

    Hi, 
    I have created an MFC extension DLL, And did the same thing but its giving assertion failure at 
    m_hInstOld = AfxGetResourceHandle();
    
    Its because of ...
    _AFXWIN_INLINE HINSTANCE AFXAPI AfxGetResourceHandle()
    	{ ASSERT(afxCurrentResourceHandle != NULL);
    		return afxCurrentResourceHandle; }
    
    I am not able to find out How the afxCurrentResourceHandle is getting NULL.

    Reply
  • Alternate Approach

    Posted by Atul Arora on 03/08/2004 12:55am

    Hi Andreas,
    
    Good article. I found an alternate approach to do this.
    You dont have to make a new class. Instead,
    
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
    in the function
     
    int CDLLDlgDlg::DoModal()
    {
      AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
      return CDialog::DoModal();
    }
    
    Call this function to set the module state before 
    initialization and/or to restore the previous module state after cleanup (end of current scope).
    
    By default, MFC uses the resource handle of the main application to load the resource template. 
    If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, 
    this template is actually stored in the DLL module. 
    You need to switch the module state for the correct handle to be used. 
    You can do this by adding the following code to the beginning of the function:
    
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
    So, you dont require a new class to manage this.

    Reply
  • Alternate Approach

    Posted by Atul Arora on 03/08/2004 12:52am

    Hi Andreas,
    
    Good article. I found an alternate approach to do this.
    You dont have to make a new class. Instead,
    
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
    in the function
     
    int CDLLDlgDlg::DoModal()
    {
      AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
      return CDialog::DoModal();
    }
    
    Call this function to set the module state before 
    initialization and/or to restore the previous module state after cleanup (end of current scope).
    
    By default, MFC uses the resource handle of the main application to load the resource template. If you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. You need to switch the module state for the correct handle to be used. You can do this by adding the following code to the beginning of the function:
    
    AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
    
    So, you dont require a new class to manage this.

    Reply
  • How to convert pdf file to text file in vb & vc?

    Posted by Legacy on 11/07/2003 12:00am

    Originally posted by: prajakta

    I have a code of pdf2txt but it converts only 1st 3 pages from pdf to txt. can anyone help me how to change the content of that dll, so that i can convert the whole pdf file to the txt.

    Reply
  • Great work

    Posted by Legacy on 08/14/2003 12:00am

    Originally posted by: Aman

    This had really helped me. Thanx!!

    Reply
  • how can I Add Progress control into win32 dll(not use MFC dll),

    Posted by Legacy on 11/22/2002 12:00am

    Originally posted by: ttmonkey

    how can I Add Progress control into win32 dll(not use MFC dll),

    Reply
  • Dynamic Loading DLL with class export.

    Posted by Legacy on 06/25/2002 12:00am

    Originally posted by: Mac

    I've a dll Which exports a Class. How do I dynamically load it?

    Thank you.
    Mac

    Reply
  • ExtFloodFill

    Posted by Legacy on 05/20/2002 12:00am

    Originally posted by: shankar reddy

    please explain how to use ExtFloodFill function

    Reply
  • need help

    Posted by Legacy on 11/07/2001 12:00am

    Originally posted by: yujie_cai

    I can't make it work!
    Who can send me a simple sample in MFC.Thank you very much

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With the cloud transforming application development and deployment — enabling organizations to improve flexibility, automate processes, and decrease time to market — some big questions remain. One of the most important issues an organization must address is how it can best employ the smarter tools and limitless scale that the cloud offers. One way that enterprises take advantage of the benefits of the cloud is by deploying their own private cloud. Read this white paper to learn how private clouds …

  • Download this IDC report to learn how your organization can benefit from new flash architecture built for the cloud era. The IDC report examines the evolving primary flash array market with a particular emphasis on how next generation flash–driven enterprise storage architectures will take performance, scalability and infrastructure density to the next level.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date