Solved

CPropertySheet created in DLL exported function gives messageboxes centred to desktop!

Posted on 2007-12-03
19
883 Views
Last Modified: 2013-12-03
Ah hello.

I have a simple DLL.  That DLL exports one function:

DLL_SPEC void ShowSheet()
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
      CMySheet dlg (_T(""));
      dlg.DoModal();
}

CMySheet is a CPropertySheet derived class that adds one CPropertyPage, a CMyPage object.  In that class, I have this code:

void CMyPage::OnBnClickedOk()
{
      AfxMessageBox ( _T("AfxMessageBox") );
      CWnd::MessageBox ( _T("CWnd::MessageBox") );
      ::MessageBox ( this->m_hWnd, _T("::MessageBox"), NULL, MB_ICONEXCLAMATION );
      ::MessageBox ( NULL, _T("::MessageBox, NULL parent"), NULL, MB_ICONEXCLAMATION );

}

I hvae created a simple test app that, for the moment, statically links to this DLL:

void CSheetDLLTestDlg::OnBnClickedShowsheet()
{
      ShowSheet();
}

The problem is that all of the calls within CMyPage::OnBnClickedOk() to display a message box result in the messagebox being centred to the desktop window, not the property sheet, nor the CSheetDLLTestDlg dialog.  When I create a normal CPropertySheet as part of an app (i.e. not created in a function loaded from a DLL) the messagebox calls centre to the sheet.

Can someone tell me why?

TIA
0
Comment
Question by:mrwad99
  • 7
  • 6
  • 4
  • +1
19 Comments
 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 20394762
Try giving the message box with the parent window handle not the Desktop handle ( which is null by default)
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20394766
I already do with this call:

::MessageBox ( this->m_hWnd, _T("::MessageBox"), NULL, MB_ICONEXCLAMATION );

and it makes no difference.
0
 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 20394806
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20394832
Interesting, but since I am on XP Pro, it should not be the problem.  I certainly don't want to have to make my own message boxes without an explanation as to the cause of the problem though :)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20397878
>>>>      CMySheet dlg (_T(""));
>>>>      dlg.DoModal();
>>>> When I create a normal CPropertySheet as part of an app

If you invoke the dialog from the dll, did you get a taskbar button for the app? If you start the taskmanager, can you find your sheet in the list of applications?

Maybe, the messagebox centers only relatively to an *application window*. And if it doesn't find one or if the 'application window' was not a direct parent of the message box, it centers to the desktop. It is a shot from the hip only, but I remembered my first lessons in Windows programming (actually it was Presentation Manager of OS/2) when I wanted to control the screen positions myself while my teacher said, it is the business of Windows to place new windows correctly and any controling from my side was not 'windows-like'.

Regards, Alex
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 20401524
Interesting.
I've just tried this but using a dialog in the dll not a propertysheet - bit less work for me ;-)
Same behaviour.  Working up the chain of calls I don't see any obvious way around it.
Sounds like this is by design (or a feature).

:-(
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 20401539
ps.
If you have a multi-monitor system it centers it on the monitor the dialog is on.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20402372
Alex

The only button I get in the taskbar is the one for the application that invokes the dialog through the DLL.  It is this that also appears in the task manager.

If I move the application window right to the top or bottom of the screen, then invoke the property sheet via the DLL, the messageboxes displayed are still right in the centre of the screen, not relative to the app at all.

Andy

Yeah, I have a dual display, and it does centre the messagebox on the monitor the app is on: I had noticed this too.

I guess this is one of Microsoft's "features" as you say Andy.  Oh well.  Interestingly, if I have an IE control on my dialog and display a messagebox via the JavaScript Alert() function call, that is centred to the IE control.  Maybe IE does something magic there...

I will close this if there are no more comments in the near future.

Thanks both :)
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 20402394
>>display a messagebox via the JavaScript Alert() function call, that is centred to the IE control.

Have you checked (Spy++) if it is a standard windows message box or some custom message box?
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 200 total points
ID: 20402486
>>>> The only button I get in the taskbar is the one for the
>>>> application that invokes the dialog through the DLL.
Is it an app with a top level window, a console prog, or a win32 prog without a toplevel window?

>>>> Maybe IE does something magic there...
You might consider making same magics by popping up a own message dialog. I mostly recognize after doing it my own way that I like the results better than before ;-) Sometimes it needs to reinvent a 'better wheel'.

Regards, Alex
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20402852
Andy, interestingly it is a standard dialog class (#32770 (Dialog)) according to Spy++: the same class as my main app window...

Alex, the main app is a dialog with a single top level window.  I may consider writing my own messagebox class, yes, but since MS managed to get around this with IE, surely we can do the same...just don't know how yet...
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20403415
>>>> but since MS managed to get around this with IE
I would strongly assume that they made their own solution as well or at least have better sources. The EU (European Union) court sentenced MS to pay a huge fine and to make known their internal interfaces. They accepted but I fear we have to wait some time before we know whether your issue was one of these hidden features.

>>>> AFX_MANAGE_STATE(AfxGetStaticModuleState());
I checked your above source again and read the docs for AfxGetStaticModuleState().

--------- excerpt of MSDN ------------------
AfxGetStaticModuleState  
AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( );

Return Value

A pointer to an AFX_MODULE_STATE structure.

Remarks

Call this function to set the module state before initialization and/or to restore the previous module state after cleanup. The AFX_MODULE_STATE structure contains global data for the module, that is, the portion of the module state that is pushed or popped.

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( ));

This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.
------------------ end excerpt ------------------------------------------------


If I read the above correctly, it sets (initializes) the static AFX resource template in the dll. Obviously, we have here a main difference to that when the app itself creates the dialog and calls DoModal. I wonder waht would happen if we could make a copy of the template used in the app rather than initializing with an empty one. Or I wonder what would happen if you pass the AFX_MODULE_STATE pointer youll get when calling AfxGetStaticModuleState in your app and pass that to the dll.

 DLL_SPEC void ShowSheet(void* p)
 {
      AFX_MANAGE_STATE((AFX_MODULE_STATE*)p);
      CMySheet dlg (_T(""));
      dlg.DoModal();
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
}

Regards, Alex
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20484276
OK, sorry about the delay.  Alex I tried your suggestion above and get the compiler error:

 '_ctlState' : redefinition; multiple initialization

This is due to the definition of the macros:

#define AFX_MANAGE_STATE_NO_INIT_MANAGED(p) AFX_MAINTAIN_STATE2 _ctlState(p); // <-------- PROBLEM

#define AFX_MANAGE_STATE(p) _AfxInitManaged(); AFX_MANAGE_STATE_NO_INIT_MANAGED(p)

Any other suggestions, or will I have to put this down as a "feature" ?

Thanks.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20484489
>>>> '_ctlState' : redefinition; multiple initialization

That most probably is caused as the _ctlState is a static instance that can be initialized only once.

But there is nothing what should you prevent from assigning.

So, instead of

   AFX_MANAGE_STATE(AfxGetStaticModuleState());

you may try

   _ctlState = AfxGetStaticModuleState();

in order to reset the static settings after the dialog has finished. The reason fo resetting is that the dll shouldn't free resources from the app what may lead to a crash.

Note, the above is only an attempt. My suggestion was to init the AFX (== MFC) control status instance with the same (static) value as the app. At least for the time the DoModal was running. In case the _ctlstate is not the only static, the attempt may fail or may cause other problems.  

Regards, Alex
0
 
LVL 19

Author Comment

by:mrwad99
ID: 20484532
Thanks, but that cannot be done as

 _ctlState = AfxGetStaticModuleState();

is saying

AFX_MAINTAIN_STATE2 = AFX_MODULE_STATE

which are two different types.

Can you please clarify what you are trying to get at with this too Alex?  I have re-re-read your comment and what you are saying is true, but I have not figured out what difference it should make...
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20486472
>>>> Can you please clarify what you are trying to get at with this

The AFX_MANAGE_STATE(p) does firstly  _AfxInitManaged(); and secondly AFX_MANAGE_STATE_NO_INIT_MANAGED(p).


The  AFX_MANAGE_STATE_NO_INIT_MANAGED(p) defines a variable of type AFX_MAINTAIN_STATE2 named '_ctlState' and passes the pointer you supplied by AfxGetStaticModuleState() tp the constructor of the
AFX_MAINTAIN_STATE2 struct/class.

I wanted to take the AfxGetStaticModuleState() from the app to be used in the dll as well. However, as the _ctlstate is a locally defined variable, the destructor of the struct/class was called when leaving the scope defined by the curly brackets. I think that the destructor will free resources associated to the AfxGetStaticModuleState. But that maybe is fatal as the app will do the same for the same pointer after exiting and most likely will crash because of that. That's why I tried to reassign the original AfxGetStaticModuleState but that doesn't work as the AFX_MAINTAIN_STATE2 has no appropriate assignment operator (only a constructor). It seems that the AFX guys actually try to prevent us from doing that (i. e. from initializing the AFX state with a remote static), so maybe we should give up ...  

If not giving up we could try to create the AFX_MAINTAIN_STATE2 at the heap and do *not* delete the pointer later, waht actually is *bad programming* though it could solve your problem.

 DLL_SPEC void ShowSheet(void* p)
 {
      _AfxInitManaged();
      AFX_MAINTAIN_STATE2 * p_ctlState =
          new AFX_MAINTAIN_STATE2 ( (AFX_MODULE_STATE*)p);
      CMySheet dlg (_T(""));
      dlg.DoModal();
      AFX_MANAGE_STATE_NO_INIT_MANAGED(AfxGetStaticModulState());
 }

The above should solve the compile issues (on cost of a memory leak). But it is only a rare chance that it does what we want.

Regards, Alex
0
 
LVL 44

Assisted Solution

by:AndyAinscow
AndyAinscow earned 50 total points
ID: 20486600
A complete alternative should the suggestion by Alex not bear fruit.

Make your own message box as a dialog.
Pass it the handle to the window you want it centered on.
In the OnInitDialog find the co-ordinates of this 'owner' and use MoveWindow or SetWindowPos to center the custom dialog on that window.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20486811
Maybe I'll find time to check what the called functions really were doing. Then, I may be able to give better advice than in the momemnt.

0
 
LVL 19

Author Comment

by:mrwad99
ID: 20500053
OK that does not work either,

CPropertyPage::CommonConstruct

fails as AfxGetResourceHandle() ASSERTS because afxCurrentResourceHandle is NULL.

Not to worry, I think we are playing with fire here so I will put it down to something that cannot be done.

Overall thanks for all the help given here :)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

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…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

743 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

15 Experts available now in Live!

Get 1:1 Help Now