Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1198
  • Last Modified:

Dialog with custom control won't work with satellite DLL

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
JasonMewes
Asked:
JasonMewes
  • 12
  • 9
  • 4
  • +2
1 Solution
 
pgnatyukCommented:
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
 
itsmeandnobodyelseCommented:
>>>> HINSTANCE hInst = LoadLibrary(_T("myres.dll"));
>>>> AfxSetResourceHandle(hInst);

No more code?

How and when did you create a dialog and run it?
0
 
JasonMewesAuthor Commented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
JasonMewesAuthor Commented:
0
 
pgnatyukCommented:
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
 
JasonMewesAuthor Commented:
Yes it's works, so I have just one dialog with one custom object that doesn't work
0
 
pgnatyukCommented:
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
 
pgnatyukCommented:
BTW, you can just set break point on DoModal and debug - we will know what makes the trouble.
0
 
JasonMewesAuthor Commented:
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
 
pgnatyukCommented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
pgnatyukCommented:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
You have this line in your functions?
 
0
 
pgnatyukCommented:
You can call DWORD nErr = GetLastError() and see the error.
 
0
 
itsmeandnobodyelseCommented:
>>>> You can call DWORD nErr = GetLastError() and see the error.

The GetLastError() is 0 after CreateDialogIndirect.
0
 
pgnatyukCommented:
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
 
pgnatyukCommented:
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
 
JasonMewesAuthor Commented:
>>>> 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
 
itsmeandnobodyelseCommented:
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
 
JasonMewesAuthor Commented:
>>>> 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
 
JasonMewesAuthor Commented:
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
 
haimenCommented:
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
 
JasonMewesAuthor Commented:
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
 
haimenCommented:
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
 
JasonMewesAuthor Commented:
Ok, Now I have double checked and I did use the right class name
0
 
JasonMewesAuthor Commented:
Please don't close this question - I havn't solved the problem yet
0
 
JasonMewesAuthor Commented:
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
 
JasonMewesAuthor Commented:
Didn't understand your proposal to try GetModuleHandle instead of AfxGetInstanceHandle - now I do
0
 
threadyCommented:
Hi Jason,

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

Cheers,
Mike
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 12
  • 9
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now