Sometimes, you need to activate a particular document window in the MDI application. It has nothing in common with opening the same document. You need it when an event happens, or user changed something somewhere and you need to notify him that one of the opened documents received changes or finished computation or whatever I can’t even imagine. In this case, you need a way to pop the random document…
Introduction
In the text below, you can find a weird code that was written while sequentially approaching the working solution. The code below contains only code that illustrates the technology, no error handling or complete function code provided.
Background
In my case, I required documents which represents a filesystem folders which cannot be opened, changes since they were opened and, of course they must not be opened more than once. Don't ask me why I have to use an MDI (multiple document interface) MFC application for this purpose.
Using the Code
A long time ago, I got some experience in writing MFC applications. Windows was young and made first steps as a 32-bit operating system at that time. Moreover, most of my applications were SDI (single document interface) or dialog based. And I was more or less calm and happy that time.
However, returns to our muttons MDI application. For my task, I have to use MDI interface and, after some iterations, I felt the need to activate the opened document when user did some action. I began with the document lookup (the easiest part):
POSITION pos = pApp->GetFirstDocTemplatePosition();
CDocTemplate* pDocTmpl = pApp->GetNextDocTemplate(pos);
POSITION posD = pDocTmpl->GetFirstDocPosition();
while (posD != NULL)
{
CDocument* pDoc = pDocTmpl->GetNextDoc(posD);
if (pDoc->GetTitle().CompareNoCase(path) == 0)
{
POSITION posW = pDoc->GetFirstViewPosition();
while (posW != NULL)
{
CView* pView = pDoc->GetNextView(posW);
if (pView && ::IsWindow(pView->GetSafeHwnd()))
{
It is easy to identify that you need, but the next steps were not easy to me. My first view activation code is shown below:
CWnd* pWnd = pView->SetActiveWindow();
pView->FlashWindow(TRUE);
pView->SetFocus();
Very naive, isn't' it? However, it doesn't have any visible effect on the application, because there is no easy way to impress the window at the bottom of the deep windows stack.
The next approach was found on Stack overflow (C++, MFC MDI, activate specific tab). It contains the code below:
CMDIChildWnd* pChild = (CMDIChildWnd*)pMainFrame->GetActiveFrame();
if (pChild && ::IsWindow(pChild->GetSafeHwnd()) && pChild->IsChild(pView))
{
pChild->SetActiveView(pView, TRUE);
}
This code is better than the previous one, it works when the document is selected :-).
After some investigations with Microsoft Spy++ (by default, Visual Studio runs a 32 bit Microsoft Spy++) tool, I discovered that we've got a stack of Windows which produced the unreadable amount of messages and there is no use to touch this stack of windows...
Finally, I was able to find the code at the CMDIFrameWnd Class | Microsoft Learn page I need and it looks like:
CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
CMDIChildWnd* child = pMainFrame->MDIGetActive();
do
{
CString str;
child->GetWindowText(str);
if (str == path)
{
child->MDIActivate(); break;
}
child = (CMDIChildWnd*)child->GetWindow(GW_HWNDNEXT);
} while (child);
And it works!
Points of Interest
I have no words to express my impression.
History
- 8th December, 2022: Initial version