Click here to Skip to main content
15,881,666 members
Articles / Desktop Programming / MFC

MFC Classes for Multiple Monitors

Rate me:
Please Sign up or sign in to vote.
4.93/5 (40 votes)
27 Aug 2003CPOL2 min read 252.6K   8.7K   106   51
Class wrappers around the Win32 multi-monitor API

Sample Image - multimon.jpg

Introduction

A while ago, I decided to write a screensaver application as a way to pick up MFC. After I got my first implementation up and running, I shipped it off to a friend. Well, the first thing he noted was a glaring bug: he uses multiple monitors and my screen saver only showed up on one.

After some scouring of the internet and research into MSDN, I was able to get the screensaver running on multiple monitors by using some API calls that were introduced with Windows 98/2000. This project is a couple of small MFC classes that wrap the multi-monitor API.

These classes can be safely used on Windows 95/NT4 as well. On those platforms, they just provide the properties of the one and only monitor.

Background

Everything you ever wanted to know about the API for multiple monitors is described in a very well written article by David Campbell in the June 1997 issue of MSJ.

The API itself is simple and straightforward. It has some new constants to pass to GetSystemMetrics and a couple methods to enumerate all of the monitors currently attached to the system and get the properties of a given monitor.

All of the types and functions are defined by the platform SDK in the file multimon.h. If you #define WINVER to be greater than 0x400, you don't need to link to multimon.h, as the API gets defined in windef.h for Windows 98 and later targeted builds. Multimon.h also provides some stub functions that allow calls to be safely made on Windows 95/NT4 machines. These wrappers interrogate the runtime OS and either make fall-through calls into the actual API or return the properties of the one (and only) monitor on those older platforms.

The multi monitor classes take care of including multimon.h correctly depending on the value of WINVER.

Using the Code

CMointor is a basic MFC class that allows you to safely use the multi-monitor API on any Win32 platform.

There are three classes in this library:

CMonitors represents the collection of monitors currently attached to the system and wraps the EnumDisplayMonitors API function.

C++
//CMonitors' interface
CMonitor GetMonitor( const int index ) const;
int GetCount() const; 

//returns the monitor closest to the specified item
static CMonitor GetNearestMonitor( const LPRECT lprc );
static CMonitor GetNearestMonitor( const POINT pt );
static CMonitor GetNearestMonitor( const CWnd* pWnd );

//is the specified item visible on any monitor
static BOOL IsOnScreen( const POINT pt );
static BOOL IsOnScreen( const CWnd* pWnd );
static BOOL IsOnScreen( const LPRECT lprc );

//returns the rectangle encompassing all monitors
static void GetVirtualDesktopRect( LPRECT lprc );

//determines whether the given handle is a valid monitor handle
static BOOL IsMonitor( const HMONITOR hMonitor );
static CMonitor GetPrimaryMonitor();
static BOOL AllMonitorsShareDisplayFormat();

static int GetMonitorCount();

CMonitor is a wrapper around an HMONITOR handle (returned from EnumDisplayMonitors) and the GetMonitorInfo function. With CMonitor, you can get at the characteristics of a given monitor.

C++
//The interface of CMonitor            
void Attach( const HMONITOR hMonitor );
HMONITOR Detach();

void ClipRectToMonitor( LPRECT lprc, 
                        const BOOL UseWorkAreaRect = FALSE ) const;
void CenterRectToMonitor( LPRECT lprc, 
                          const BOOL UseWorkAreaRect = FALSE ) const;
void CenterWindowToMonitor( CWnd* const pWnd,
                            const BOOL UseWorkAreaRect = FALSE ) const;

//creates a device context for the monitor - the client is responsible for DeleteDC
HDC CreateDC() const;

void GetMonitorRect( LPRECT lprc ) const;
//the work area is the monitor rect minus the start bar
void GetWorkAreaRect( LPRECT lprc ) const;

void GetName( CString& string ) const;

int GetBitsPerPixel() const;

//determines if the specified item on the monitor
BOOL IsOnMonitor( const POINT pt ) const;
BOOL IsOnMonitor( const CWnd* pWnd ) const;
BOOL IsOnMonitor( const LPRECT lprc ) const;

BOOL IsPrimaryMonitor() const;
BOOL IsMonitor() const;        

CMonitorDC is a CDC derived class that represents a monitor specific device context. I haven't really gone too far with this class but it seemed like a logical part of the library.

Known Limitations

CMonitor and CMonitors rely on the assumption that a monitor handle does not change. This has proved to be a safe assumption empirically but isn't necessarily a guarantee.

History

  • 02/20/2003 - Initial release
  • 08/25/2003 - Made changes to make compatible with VC6 environment

License

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


Written By
Team Leader Starkey Laboratories
United States United States
The first computer program I ever wrote was in BASIC on a TRS-80 Model I and it looked something like:
10 PRINT "Don is cool"
20 GOTO 10

It only went downhill from there.

Hey look, I've got a blog

Comments and Discussions

 
GeneralRe: Link errors when MFC statically linked Pin
kifaayet8-Oct-07 6:02
kifaayet8-Oct-07 6:02 
GeneralRE: Displaying on second monitor Pin
BK214-Oct-03 7:45
BK214-Oct-03 7:45 
GeneralRe: RE: Displaying on second monitor Pin
Don Kackman17-Oct-03 14:14
Don Kackman17-Oct-03 14:14 
GeneralRe: RE: Displaying on second monitor Pin
James Duy Trinh (VietDoor)9-Jun-05 20:02
James Duy Trinh (VietDoor)9-Jun-05 20:02 
GeneralCool Pin
NormDroid28-Aug-03 20:57
professionalNormDroid28-Aug-03 20:57 
GeneralRe: Cool Pin
Don Kackman29-Aug-03 4:00
Don Kackman29-Aug-03 4:00 
GeneralAdded VC6 project Pin
Don Kackman28-Aug-03 16:31
Don Kackman28-Aug-03 16:31 
GeneralMy expieriences with VC6 & this class Pin
figmo23-Aug-03 17:40
figmo23-Aug-03 17:40 
1. Running VC6 I get a naming conflict with the Platform SDK for your file "Monitor.h". There is already a file in the Platform SDK by that name. My solution was to just change the name of your files "Monitor.h" & "Monitor.cpp" to "MMontitor.h" and "MMonitor.cpp". Another solution would be to move the folder containing your class files to the top of the search order but, for other reasons, I was not able to do this.

2. Also - the CObArray class needs be linked in by including <afxcoll.h>. And the VC6 version of this class does not have a member function "GetCount()" as used by your code. References to this must be changed to "GetSize()".

3. And finally, a minor nuisance: you include the header file from your demo project in your class libraries so this must be commented out before it can be used.

Just some FYI's for fellow readers who may run into these problems.
GeneralRe: My expieriences with VC6 &amp; this class Pin
figmo23-Aug-03 17:59
figmo23-Aug-03 17:59 
GeneralRe: My expieriences with VC6 &amp; this class Pin
Don Kackman25-Aug-03 6:01
Don Kackman25-Aug-03 6:01 
Questioncan someone send me multimon.cpp ? Pin
cweng200312-Apr-03 11:51
cweng200312-Apr-03 11:51 
AnswerRe: can someone send me multimon.cpp ? Pin
Don Kackman14-Apr-03 5:28
Don Kackman14-Apr-03 5:28 
Generalproject workspace file does not exist Pin
cweng200312-Apr-03 11:36
cweng200312-Apr-03 11:36 
GeneralRe: project workspace file does not exist Pin
Don Kackman14-Apr-03 5:25
Don Kackman14-Apr-03 5:25 
GeneralRe: project workspace file does not exist Pin
Don Kackman14-Apr-03 6:13
Don Kackman14-Apr-03 6:13 
GeneralLinking error Pin
Anonymous6-Mar-03 6:11
Anonymous6-Mar-03 6:11 
GeneralRe: Linking error Pin
Don Kackman7-Mar-03 4:50
Don Kackman7-Mar-03 4:50 
GeneralRe: Linking error Pin
Anonymous9-Mar-03 22:28
Anonymous9-Mar-03 22:28 
GeneralRe: Linking error Pin
Donders67-Jul-05 1:58
Donders67-Jul-05 1:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.