Solved

Dialog with custom control won't work with satellite DLL

Posted on 2009-06-30
33
1,166 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 12
  • 9
  • 4
  • +2
33 Comments
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24746459
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
ID: 24747055
>>>> 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
ID: 24753340
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
Percona Monitoring and Management and Grafana

Proactive monitoring is vital to a highly-available environment. We have a quick start guide on Experts Exchange for Grafana users.

 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24754550
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
ID: 24754571
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
ID: 24754642
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
ID: 24754651
BTW, you can just set break point on DoModal and debug - we will know what makes the trouble.
0
 

Author Comment

by:JasonMewes
ID: 24754762
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
ID: 24755182
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
ID: 24755419
>>>> 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
ID: 24755494
AFX_MANAGE_STATE(AfxGetStaticModuleState());
You have this line in your functions?
 
0
 
LVL 33

Expert Comment

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

Expert Comment

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

The GetLastError() is 0 after CreateDialogIndirect.
0
 
LVL 33

Accepted Solution

by:
pgnatyuk earned 500 total points
ID: 24756213
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
ID: 24757222
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
ID: 24761221
>>>> 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
ID: 24761831
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
ID: 24762310
>>>> 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
ID: 24801947
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
ID: 25060944
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
ID: 25066502
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
ID: 25076074
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
ID: 25076469
Ok, Now I have double checked and I did use the right class name
0
 

Author Comment

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

Author Comment

by:JasonMewes
ID: 25196676
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
ID: 31598296
Didn't understand your proposal to try GetModuleHandle instead of AfxGetInstanceHandle - now I do
0
 
LVL 1

Expert Comment

by:thready
ID: 25450808
Hi Jason,

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

Cheers,
Mike
0

Featured Post

[Webinar] How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
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.
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
Suggested Courses

632 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