Click here to Skip to main content
16,020,669 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I am working on unit test with MFC. My software is a SDI.

I have 2 threads : the first one is the graphic thread and the second one a unit test procedure which reproduce a user behavior. It is working well when there isn't modal dialog, I use SendMessage (to simulate click on button, or change text, etc.) which is blocking until the message has been treated so I haven't any sync issue.

But when the button opens a Modal CDialog I can't use SendMessage because the unit test thread is going to be blocked as long as the modal dialog is opened. So I use PostMessage and Sleep. And now my problem is to get the pointer of the current opened CDialog.

What I have tried:

Here is the code of the unit test

C++
bool UnitTestBoite()
{
   // Here I am in unit test thread
   CFrameWnd *pMainFrame = (CFrameWnd *)AfxGetMainWnd();
   // Post Message to notify the button ID_INSERER_BOITE is clicked
   pMainFrame->PostMessageW(WM_COMMAND, MAKELONG(ID_INSERER_BOITE, 0), 0);
   // In the handler of ID_INSERER_BOITE
   // there is something like CDialog dlg(pMainFrame, IDD_BASE_BOITE); dlg.DoModal();
   Sleep(1000);
   UINT myModalTemplateId = IDD_BASE_BOITE;
   ...


To get modal dialog pointer I tried :
C++
CWnd* pChild = pMainFrame->GetWindow(GW_CHILD);
while (pChild != nullptr)
{
    // Retrieve template ID
    UINT nResourceId = GetWindowLong(pChild->GetSafeHwnd(), GWL_ID);
    if (nResourceId == myModalTemplateId )
        break;
    pChild = pChild->GetWindow(GW_HWNDNEXT);
}
if (pChild == nullptr)
    return false;

or
C++
HWND hwndForeGround = ::GetForegroundWindow();
// Retrieve template ID
UINT nResourceId = GetWindowLong(hwndForeGround, GWL_ID);
if (nResourceId != myModalTemplateId )
   return false;

or
C++
CWnd *pModal = pMainFrame_->GetForegroundWindow();
  // Retrieve template ID
  UINT nResourceId = GetWindowLong(pModal->GetSafeHwnd(), GWL_ID);
  if (nResourceId != myModalTemplateId )
     return false;

None of these code snippet worked... The last solution I have thought was to make all my CDialog classes inherits from a custom class and register all opened CDialog, but it is a bit invasive... Is there an "elegant" means to do that ?

Thank for reading, Lucas.
Posted
Updated 5-Mar-16 6:49am

1 solution

Your first attempt will not work because , you looking for a modal dialog , which has a style of WS_POPUP
A popup window can not contain a style of WS_CHILD

Folowing code will not return dialog template ID (for popup windows), it returns control ID for child windows (including dialog template ID of child dialogs)
That field is used for menu resource ID for popup windows , so if your modal dialog has not got any menu then that function will return 0

GetWindowLong(hwndForeGround, GWL_ID);


GetLastActivePopup function (Windows)[^] can be used to get last popup window but you still can not idetify that dialog by Template ID , even if you will find a CDialog class

you will already use this for testing purpose ,you can compare window title to ensure that you found the dialog you looking for

following code should help

C++
CFrameWnd *pMainFrame = (CFrameWnd *)AfxGetMainWnd();
if(pMainFrame)
{
	CWnd *pWnd = pMainFrame->GetLastActivePopup();
	if(pWnd)
	{
		if(pWnd->IsKindOf(RUNTIME_CLASS(CDialog)))
		{
			CDialog *pDialog = reinterpret_cast<cdialog*>(pWnd);
			if(pDialog)
			{
				CString strTitle;
				pDialog->GetWindowText(strTitle);
				
				if(strTitle.CompareNoCase(_T("My Dialog")) == 0)
				{
					//we found dialog ,dismiss it
					pDialog->EndDialog(0);	
				}
			}
		}
	}
}
 
Share this answer
 
Comments
lsarie 7-Mar-16 3:48am    
Unfortunately pWnd->IsKindOf(RUNTIME_CLASS(CDialog)) doesn't return true...

Thank for the reply
Serkan Onat 7-Mar-16 6:28am    
you probably calling this before dialog appears

i have tried that code via a simple SDI app with about dialog (created by project wizard) and that worked

please check what CWnd *pWnd = pMainFrame->GetLastActivePopup(); returns against CFrameWnd *pMainFrame

if they are same then you definitely calling that earlier , while dialog does not exist
lsarie 7-Mar-16 8:25am    
No the CDialog is opened when it is called.

But when I force with the debugger to pass the line if(pWnd->IsKindOf(RUNTIME_CLASS(CDialog))) the title returned by GetWindowText is correct, dialog returned by GetLastActivePopup is good .

So the problem is with pWnd->IsKindOf() where inside there is a call to GetRuntimeClass() that that return CWnd instead of CDialog...
My base class has DECLARE_DYNAMIC(MyClassDlg) in the header and IMPLEMENT_DYNAMIC(MyClassDlg, CDialog) in the cpp, I don't understand why GetRuntimeClass() returns CWnd and not MyClassDlg...

Thank you for your help ! I am still seeking the solution

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900