Solved

Dialog with custom control won't work with satellite DLL

Posted on 2009-06-30
33
1,102 Views
Last Modified: 2016-08-29
I use satellite DLL for localization purposes in my application. And loading the dll with AfxSetResourceHandle. This works fine for all of my dialogs that doesn't use a custom control.

For those with custom control the constructor is called but not OnInitDialog or DoDataExchange
And DoModal returns -1

Any suggestion?

Thanks.
// Loading satellite DLL

HINSTANCE hInst = LoadLibrary(_T("myres.dll"));

AfxSetResourceHandle(hInst);

Open in new window

0
Comment
Question by:JasonMewes
  • 12
  • 9
  • 4
  • +2
33 Comments
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
Probably, there is a problem with the creation of these controls.
Where you create your controls? They are just on the dialog form and then you have associated class members?
It is not a case that you just don't have enough memory on stack to create the dialog?
Just for a verification, can you create your controls in another dialog that does work, but do not put them on the resource - just say CMyControl* pCtrl = new CMyControl; if it works, try pCtrl->Create.
Regards,
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> HINSTANCE hInst = LoadLibrary(_T("myres.dll"));
>>>> AfxSetResourceHandle(hInst);

No more code?

How and when did you create a dialog and run it?
0
 

Author Comment

by:JasonMewes
Comment Utility
okej now I have tested to manually load them like pgnatyuk asked me to do. (CMyControl* pCtrl = new CMyControl; try pCtrl->Create) and thats works fine.

So have stripped down my project and attached it - so that you can see the problem four your self
You can see that it works fine by choosing About in the Help-menu.
The custom control now draw a ellipse

And failing by now choosing Switch to MyRes in the Help-menu.
Then choose About in MyRes in the Help in MyRes-menu
Now DoModal returns -1
0
 

Author Comment

by:JasonMewes
Comment Utility
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
I'd say to remove all these custom controls from one of your dialogs and see if it works. If it does, I'd add one control, and continue this way.
If the dialog with removed all custom control still will have the problem, we will know what to do.
It's all just in order to split the problematic area.
 
0
 

Author Comment

by:JasonMewes
Comment Utility
Yes it's works, so I have just one dialog with one custom object that doesn't work
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
if this controls will work with new and create, just use this way.
Your custom controls have a lot of heavy members? When they are created from the resource (when you just call DoModal) which constructor and which method are called? Can you temporary remove/comment all code from this contructor and this method?
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
BTW, you can just set break point on DoModal and debug - we will know what makes the trouble.
0
 

Author Comment

by:JasonMewes
Comment Utility
The example project only conations one dialog (about-dialog) with no buttons, just the custom control.

So I have tried to step the code using breakpoints but its not making any sense for me

In my real project I use a lot of different custom controls - and I need to know what's going wrong before doing any workarounds like manual create.
code for the custom control
 

// EllipseCtrl.h : header file

//
 

#define BITMAPVIEWER_CLASSNAME    _T("MFCBitmapViewerCtrl")  // Window class name
 

/////////////////////////////////////////////////////////////////////////////

// EllipseCtrl window
 

class CEllipseCtrl : public CWnd

{

// Construction

public:

	CEllipseCtrl();
 

// Attributes

public:

// Operations

public:

	BOOL Create(CWnd* pParentWnd, const RECT& rect, UINT nID, DWORD dwStyle = WS_VISIBLE);
 

// Overrides

	// ClassWizard generated virtual function overrides

	//{{AFX_VIRTUAL(EllipseCtrl)

	protected:

	virtual void PreSubclassWindow();

	//}}AFX_VIRTUAL
 

// Implementation

public:

	virtual ~CEllipseCtrl();

protected:

    BOOL RegisterWindowClass();
 
 

	// Generated message map functions

protected:

	//{{AFX_MSG(EllipseCtrl)

	afx_msg void OnPaint();

	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()

};
 
 
 

///////////////////////////////////////////////////////////////////////

// EllipseCtrl.cpp

//
 
 

CEllipseCtrl::CEllipseCtrl()

{

    RegisterWindowClass();

}
 

CEllipseCtrl::~CEllipseCtrl()

{

}
 

// Register the window class if it has not already been registered.

BOOL CEllipseCtrl::RegisterWindowClass()

{

    WNDCLASS wndcls;

    HINSTANCE hInst = AfxGetInstanceHandle();
 

    if (!(::GetClassInfo(hInst, BITMAPVIEWER_CLASSNAME, &wndcls)))

    {

        // otherwise we need to register a new class

        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

        wndcls.lpfnWndProc      = ::DefWindowProc;

        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;

        wndcls.hInstance        = hInst;

        wndcls.hIcon            = NULL;

        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);

        wndcls.lpszMenuName     = NULL;

        wndcls.lpszClassName    = BITMAPVIEWER_CLASSNAME;
 

        if (!AfxRegisterClass(&wndcls))

        {

            AfxThrowResourceException();

            return FALSE;

        }

    }
 

    return TRUE;

}
 
 

BEGIN_MESSAGE_MAP(CEllipseCtrl, CWnd)

	//{{AFX_MSG_MAP(EllipseCtrl)

	ON_WM_PAINT()

	ON_WM_ERASEBKGND()

	//}}AFX_MSG_MAP

END_MESSAGE_MAP()
 
 

/////////////////////////////////////////////////////////////////////////////

// EllipseCtrl message handlers
 

void CEllipseCtrl::OnPaint() 

{

	CPaintDC dc(this); // device context for painting
 

	// Get Size of Display area

  CRect rect;

  GetClientRect(rect);
 

	dc.Ellipse(rect);
 

	// Do not call CWnd::OnPaint() for painting messages

}
 

void CEllipseCtrl::PreSubclassWindow() 

{

	// TODO: Add your specialized code here and/or call the base class

	// In our case this is not needed - yet - so just drop through to

    // the base class

	CWnd::PreSubclassWindow();

}
 

/////////////////////////////////////////////////////////////////////////////

// EllipseCtrl methods
 

BOOL CEllipseCtrl::Create(CWnd* pParentWnd, const RECT& rect, UINT nID, DWORD dwStyle /*=WS_VISIBLE*/)

{

	return CWnd::Create(BITMAPVIEWER_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID);

}

Open in new window

0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
I see your ellipse.  I tested it in a small app. Just declared CEllipseCtrl m_Ellipse and than call SubclassDlgItem(IDC_STATIC1, this) in OnInitDialog. What you did?
I'm still downloading your project. You know how I want to make a project for a dll.
Can you put a break point in the RegisterWindowClass method and check hInst value (is it like in LoadLibrary call?) and be sure that you get to return TRUE line?
 
 
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> So I have tried to step the code using breakpoints but its not making any sense for me

After you changed the resources and invoke the about dialog again, the dialog doesn't shop up since the

            hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,
                  pParentWnd->GetSafeHwnd(), AfxDlgProc);

returned NULL for hwnd, what means that the (resource) template somehow was wrong.

Unfortunately it is plain WINAPI and cannot be debugged. I would suggest you try a new (test) project where the myres.rc is main rc file and check whether it works if the rc file wasn't switched.


 
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
AFX_MANAGE_STATE(AfxGetStaticModuleState());
You have this line in your functions?
 
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
You can call DWORD nErr = GetLastError() and see the error.
 
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
>>>> You can call DWORD nErr = GetLastError() and see the error.

The GetLastError() is 0 after CreateDialogIndirect.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 33

Accepted Solution

by:
pgnatyuk earned 500 total points
Comment Utility
I cannot download your project. It says that it need 4 hours.
I found the article with this control:
http://www.codeproject.com/KB/miscctrl/customcontrol.aspx
I do not understand which way you took for your controls. I thought that the subclassing is the easiest one. So on your dialog resource you will have only standard static text controls and CreateDialogIndirect will work.
You didn't say if you did that:
<<Can you put a break point in the RegisterWindowClass method and check hInst value (is it like in LoadLibrary call?) and be sure that you get to return TRUE line? >>
I can propose to try GetModuleHandle instead of  AfxGetInstanceHandle() for the control registration. I cannot say I beleive that it will help.
0
 
LVL 33

Expert Comment

by:pgnatyuk
Comment Utility
http://www.ucancode.net/Visual_C_MFC_Example/Export-dialog-to-mfc-extension-dll.htm
This is a short article about the dialogs from a DLL - just to be sure that we didn't miss something and the problem is the custom control.
0
 

Author Comment

by:JasonMewes
Comment Utility
>>>> I cannot download your project. It says that it need 4 hours.
I have upploaded by code to rapidshare.de as well
http://rapidshare.de/files/47729376/CustumCtrl.zip.html

>>>> Can you put a break point in the RegisterWindowClass method and check hInst value (is it like in LoadLibrary call?) and be sure that you get to return TRUE line?
RegisterWindowClass seems to go okey, hInst value is ok and the function returns true.

>>>> AFX_MANAGE_STATE(AfxGetStaticModuleState());
You have this line in your functions?
I havent got AFX_MANAGE_STATE(AfxGetStaticModuleState()); in the code. But in any case I dont export any functions from my DLL due to the fact that its a satellite DLL used just for as a resourceDLL (see attached picture of my test project)

>>>> http://www.ucancode.net/Visual_C_MFC_Example/Export-dialog-to-mfc-extension-dll.htm
This is a short article about the dialogs from a DLL - just to be sure that we didn't miss something and the problem is the custom control.
I have read the article  nothing new

Its true like itsmeandenobodyelse says that CreateDialogIndirect fails se attached code snippet or step the project
You can see that it works fine by choosing About in the Help-menu.
The custom control now draw a ellipse

And failing by now choosing Switch to MyRes in the Help-menu.
Then choose About in MyRes in the Help in MyRes-menu
Now DoModal returns -1 because ::CreateDialogIndirect returns NULL in ther function CWnd::CreateDlgIndirect

// App command to run the dialog

void CMultiLangApp::OnAppAbout()

{

	CAboutDlg aboutDlg;

	aboutDlg.DoModal(); // calling CDialog::DoModal()

}
 
 

// the fucntioncalls to the error

INT_PTR CDialog::DoModal()

{

	&

	&

	&

	if (CreateDlgIndirect(lpDialogTemplate,	CWnd::FromHandle(hWndParent), hInst)) // calling CWnd::CreateDlgIndirect

}
 
 

BOOL CWnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate,

	CWnd* pParentWnd, HINSTANCE hInst)

{

	&

	&

	&

	hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,

		pParentWnd->GetSafeHwnd(), AfxDlgProc);

// returns NULL and The GetLastError() is 0 after CreateDialogIndirect.

}

Open in new window

Solution-Explorer.jpg
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
I compared the .rc files and resource.h of both resources and there were differences. You should try to have one resource.h for both .rc files.

Did you try to use the .rc defined in myres project in some stand-alone dialog project? Just to exclude the possibility that the about dialog wouldn't work there either.

Next you could do is to using identical .rc files where only the texts were differently. I feel the problems you have were due to some statically defined information where some pointers were stored which became invalid after loading the second rescource. If I was right, that could be go ok with identical resources or - as a quite new approach - to have an empty resource file firstly and load even the default language resource dynamically.

>>>> I havent got AFX_MANAGE_STATE(AfxGetStaticModuleState()); in the code. But in any case I dont export any functions from my DLL
I don't think the AFX_MANAGE_STATE is to support exported functions. AFAIK it is to change the global static information stored in the AFX framework to the new dll context. I don't know whether that is needed when using a resource dll. But it could be worth a trial.
0
 

Author Comment

by:JasonMewes
Comment Utility
>>>> I compared the .rc files and resource.h of both resources and there were differences. You should try to have one resource.h for both .rc files.

ok tried with only one resource.h, still the same error

>>>> Did you try to use the .rc defined in myres project in some stand-alone dialog project? Just to exclude the possibility that the about dialog wouldn't work there either.

Yes I have

>>>> Next you could do is to using identical .rc files where only the texts were differently.

ok I copied to resource.h .rc files so they are the same but still the same error

>>>> AFX_MANAGE_STATE
I don't know where I should try to put it in the code
0
 

Author Comment

by:JasonMewes
Comment Utility
I'm going on a vacation to Peru this night so I can't access Internet again before 2009-08-10
Thanks for the help so far
0
 

Expert Comment

by:haimen
Comment Utility
I had the same problem and found your quesion while looking for a solution.  Eventually I found that when I added the control to the dialog I used the wrong class name.  

Using the correct class name solved the problem.

Good luck!
0
 

Author Comment

by:JasonMewes
Comment Utility
Haimen, in what way do you mean used the wrong class name?
Did your program still compile, was is spelled wrong? The link to the satellite DLL is made up by a resource ID
0
 

Expert Comment

by:haimen
Comment Utility
When you place your custom control on the dialog you should examine the properties of this custom control (r-click + properties).
Now look for the "Class" property and make sure you enter the same exact name you've used for this control at the top of your "EllipseCtrl.h" (in your example it should be MFCBitmapViewerCtrl).
0
 

Author Comment

by:JasonMewes
Comment Utility
Ok, Now I have double checked and I did use the right class name
0
 

Author Comment

by:JasonMewes
Comment Utility
Please don't close this question - I havn't solved the problem yet
0
 

Author Comment

by:JasonMewes
Comment Utility
okey, if I replace my call to AfxGetInstanceHandle(); with GetModuleHandle("MyRes.dll");
for the HANDLE hInstance in the struct WNDCLASS that I use while calling AfxRegisterClass.

The call to AfxRegisterClass is done while registering the custom control.





  WNDCLASS wndcls;

  HINSTANCE hInst = GetModuleHandle("MyRes.dll");
 

  if (!(::GetClassInfo(hInst, BITMAPVIEWER_CLASSNAME, &wndcls)))

  {

      // otherwise we need to register a new class

      wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

      wndcls.lpfnWndProc      = ::DefWindowProc;

      wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;

      wndcls.hInstance        = hInst;

      wndcls.hIcon            = NULL;

      wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

      wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);

      wndcls.lpszMenuName     = NULL;

      wndcls.lpszClassName    = BITMAPVIEWER_CLASSNAME;
 

      if (!AfxRegisterClass(&wndcls))

      {

          AfxThrowResourceException();

          return FALSE;

      }

  }

  return TRUE;

Open in new window

0
 

Author Closing Comment

by:JasonMewes
Comment Utility
Didn't understand your proposal to try GetModuleHandle instead of AfxGetInstanceHandle - now I do
0
 
LVL 1

Expert Comment

by:thready
Comment Utility
Hi Jason,

Thanks for making that last post - it helped me a lot!  :-)  

Cheers,
Mike
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now