Click here to Skip to main content
15,885,030 members
Articles / Desktop Programming / WTL

Don Kackman Multiple Monitors Classes Port to WTL

Rate me:
Please Sign up or sign in to vote.
4.78/5 (7 votes)
26 Apr 2009CPOL1 min read 25.1K   464   12  
Class wrappers around the Win32 multi-monitor API
// Monitor.h : implementation of the CMonitor class
//
/////////////////////////////////////////////////////////////////////////////

// David Campbell's article "How to Exploit Multiple Monitor Support in Memphis and Windows NT 5.0"
// is very helpful for multimonitor api calls
// http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0697/monitor/monitor.htm&nav=/msj/0697/newnav.htm

// Author: Donald Kackman
// Email:  don@itsEngineering.com
// Copyright 2002, Donald Kackman
// You may freely use or modify this code provided this copyright is included in all derived versions.
//
// Ported to WTL by Igor Vigdorchik

#include "stdafx.h"
#include "Monitor.h"
#include "Monitors.h"

CMonitor::CMonitor() : m_hMonitor(NULL) {}

CMonitor::CMonitor(const CMonitor& monitor)
{
	m_hMonitor = (HMONITOR)monitor;
}

void CMonitor::Attach(const HMONITOR hMonitor)
{
	ATLASSERT(CMonitors::IsMonitor(hMonitor));
	m_hMonitor = hMonitor;
}

HMONITOR CMonitor::Detach()
{
	HMONITOR hMonitor = m_hMonitor;
	m_hMonitor = NULL;

	return hMonitor;
}

// Creates an HDC for the monitor, it is up to the client to call DeleteDC.
// For normal multimonitor drawing it is not necessary to get a dc for each monitor. 
// Windows takes care of drawing correctly on all monitors, only very exacting applications would need a DC for each monitor
HDC CMonitor::CreateDC() const
{
	ATLASSERT(IsMonitor());

	CString name;
	GetName(name);

	// Create a dc for this display
	HDC hdc = ::CreateDC(name, name, NULL, NULL);
	ATLASSERT(hdc != NULL);

	// Set the viewport based on the monitor rect's relation to the primary monitor
	CRect rect;
	GetMonitorRect(&rect);

	::SetViewportOrgEx(hdc, -rect.left, -rect.top, NULL);
	::SetViewportExtEx(hdc, rect.Width(), rect.Height(), NULL);

	return hdc;
}

void CMonitor::ClipRectToMonitor(LPRECT lprc, const BOOL bUseWorkAreaRect) const
{
	// The work area is the monitor rect minus the start bar
	int w = lprc->right - lprc->left;
	int h = lprc->bottom - lprc->top;

	CRect rect;
	if (bUseWorkAreaRect)
		GetWorkAreaRect(&rect);
	else
		GetMonitorRect(&rect);

	lprc->left = max(rect.left, min(rect.right - w, lprc->left));
	lprc->top = max(rect.top, min(rect.bottom - h, lprc->top));
	lprc->right = lprc->left + w;
	lprc->bottom = lprc->top + h;
}

// These two center methods are adapted from David Campbell's MSJ article (see comment at the top of the header file)
void CMonitor::CenterRectToMonitor(LPRECT lprc, const BOOL bUseWorkAreaRect) const
{
	// The work area is the monitor rect minus the start bar
	int  w = lprc->right - lprc->left;
	int  h = lprc->bottom - lprc->top;

	CRect rect;
	if (bUseWorkAreaRect)
		GetWorkAreaRect(&rect);
	else
		GetMonitorRect(&rect);

	lprc->left = rect.left + (rect.Width() - w ) / 2;
	lprc->top = rect.top + (rect.Height() - h ) / 2;
	lprc->right	= lprc->left + w;
	lprc->bottom = lprc->top + h;
}

void CMonitor::CenterWindowToMonitor(CWindow* const pWnd, const BOOL bUseWorkAreaRect) const
{
	// The work area is the monitor rect minus the start bar
	ATLASSERT(IsMonitor());
	ATLASSERT(pWnd);
	ATLASSERT(::IsWindow(pWnd->m_hWnd));

	CRect rect;
	pWnd->GetWindowRect(&rect);
	CenterRectToMonitor(&rect, bUseWorkAreaRect);
	pWnd->SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

void CMonitor::GetMonitorRect(LPRECT lprc) const
{
	ATLASSERT(IsMonitor());

	MONITORINFO mi;
	RECT        rc;

	mi.cbSize = sizeof(mi);
	::GetMonitorInfo(m_hMonitor, &mi);
	rc = mi.rcMonitor;

	::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom);
}

void CMonitor::GetWorkAreaRect(LPRECT lprc) const
{
	ATLASSERT(IsMonitor());

	MONITORINFO mi;
	RECT        rc;

	mi.cbSize = sizeof(mi);
	::GetMonitorInfo(m_hMonitor, &mi);
	rc = mi.rcWork;

	::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom);
}

void CMonitor::GetName(CString& string) const
{
	ATLASSERT(IsMonitor());

	MONITORINFOEX mi;
	mi.cbSize = sizeof(mi);
	::GetMonitorInfo(m_hMonitor, &mi);

	string = mi.szDevice;
}

int CMonitor::GetBitsPerPixel() const
{
	HDC hdc = CreateDC();
	int ret = ::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES);
	::DeleteDC(hdc);

	return ret;
}

// Determines if the specified item on the monitor, these methods return true 
// if any part of the item intersects the monitor rect
BOOL CMonitor::IsOnMonitor(const POINT pt) const
{
	CRect rect;
	GetMonitorRect(rect);

	return rect.PtInRect(pt);
}

BOOL CMonitor::IsOnMonitor(const CWindow* pWnd) const
{
	CRect rect;
	GetMonitorRect(rect);

	ATLASSERT(::IsWindow(pWnd->m_hWnd));
	CRect wndRect;
	pWnd->GetWindowRect(&wndRect);

	return rect.IntersectRect(rect, wndRect);
}

BOOL CMonitor::IsOnMonitor(const LPRECT lprc) const
{
	CRect rect;
	GetMonitorRect(rect);

	return rect.IntersectRect(rect, lprc);
}

// Is the instance the primary monitor
BOOL CMonitor::IsPrimaryMonitor() const
{
	ATLASSERT(IsMonitor());

	MONITORINFO mi;

	mi.cbSize = sizeof(mi);
	::GetMonitorInfo(m_hMonitor, &mi);

	return mi.dwFlags == MONITORINFOF_PRIMARY;
}

// Is the instance currently attached to a valid monitor handle
BOOL CMonitor::IsMonitor() const 
{
	return CMonitors::IsMonitor(m_hMonitor);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions