Introduction
I'm working on a project that needs to be debugged on a dual monitor system. Fortunately, I have such a system at work. While dragging the application window to the secondary monitor for the umpteenth billion time, I thought to myself that it would be really cool if I could get the application to display itself on the secondary monitor automatically while running in debug mode.
The Code
All of the work we need to do is in the application's .CPP and .H files. To start things off, add the following code to your application's .H file:
class CSecondaryDebugApp : public CWinApp
{
private:
CRect m_secondaryRect;
void UseSecondaryMonitor();
...
};
That code simply defines a member variable that receives the secondary monitor's rectangle, and the function prototype for the code that actually does the work of finding your secondary monitor.
Next, we have to add some code to OnInitInstance()
:
BOOL CSecondaryDebugApp::InitInstance()
{
#ifdef _DEBUG
UseSecondaryMonitor();
if (m_secondaryRect.Width() + m_secondaryRect.Height() == 0)
{
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
}
else
{
m_pMainWnd->MoveWindow(m_secondaryRect, TRUE);
}
#else
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
#endif
m_pMainWnd->UpdateWindow();
return TRUE;
}
Here, we call our monitor finding method, and then react based on what the method found.
Finally, we add the meat of the code to the end of our .CPP file:
CRect secondaryRect(0,0,0,0);
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,
HDC hdc1,
LPRECT lprcMonitor,
LPARAM data)
{
RECT rc = *lprcMonitor;
MONITORINFOEX mInfo;
mInfo.cbSize = sizeof(mInfo);
::GetMonitorInfo(hMonitor, &mInfo);
if (mInfo.dwFlags != MONITORINFOF_PRIMARY)
{
secondaryRect = mInfo.rcWork;
return 0;
}
return 1;
}
void CSecondaryDebugApp::UseSecondaryMonitor()
{
m_secondaryRect.SetRect(0,0,0,0);
::EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
m_secondaryRect = secondaryRect;
}
The UseSecondaryMonitor()
function simply initializes the member rectangle, enumerates the available monitors, and sets the member rectangle variable. Of course, you could choose to put these three lines of code into the OnInitInstance()
function, but that's not how *I* chose do it.
The callback function checks the dwFlags
field of the MONITORINFOEX
structure to see if this is not the primary monitor, and if it isn't, it grabs the work rectangle (the rectangle available to the application) and returns 0 to stop the enumeration (remember, this example is only looking for the first secondary monitor on your system).
End Result
When you compile the program with debug info, running the program will cause the program to display itself on the secondary monitor. You could easily expand this concept to release versions that will re-display themselves on whatever monitor they were last displayed on.
Have fun.
Disclaimers
This article is meant to illustrate how to find a secondary monitor on your system using the EnumerateDisplayMonitors()
and GetMonitorInfo()
functions. As usual, the bulk of the info I found came from MSDN. Most of my articles are ripped directly out of a project I'm working on, so along with the "how" aspects, you usually get a real life example of why I developed the code.
I don't expect many here would have the same requirements that I do, and I can't be expected to divine everyone's needs in advance. Since you're all programmers (or at least claim to be), I leave it to you to adapt this code to your own project.
Finally, if this article inspires you to more fully investigate multiple monitor systems (one user here has six monitors on three different video cards in one box), by all means, write an article about it!