| MonitorFromPoint | Determines the monitor that contains a specific point. |
| MonitorFromRect | Determines the monitor that contains the largest piece of the rectangle. |
| MonitorFromWindow | Determines the monitor that a window belongs to (which monitor contains the majority of the window). |
| GetMonitorInfo | Gets metric information for a particular monitor. |
| ChangeDisplaySettingsEx | Same as ChangeDisplaySettings except that it allows the caller to specify the device. |
| EnumDisplayMonitors | Returns info about multiple video devices that an application may overlap. A monitor need not be part of the Windows virtual desktop. |
| EnumDisplayDevices | Allows you to determine the actual list of devices available on a given machine. You can enumerate the devices and get a DC for any monitor on the system that Windows supports. This allows an application to work with a dedicated display device without sharing the screen with other applications. (This is used, for example, by the Control Panel.) |
| SystemParametersInfo and GetSystemMetrics | These APIs were updated slightly to include support for multiple monitors, and CreateDC was updated to take a display name in the \\.\DisplayX, where X is a number. This can be used in conjunction with EnumDisplayDevices to get DCs for specific monitors. |
Figure 5 Multimon.h
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
//=============================================================================
//
// MULTIMON
// stub module that "stubs" multiple monitor APIs on pre-Memphis Win32 OSes
//
// By using this header your code will work unchanged on Win95,
// you will get back correct values from GetSystemMetrics() for new metrics
// and the new APIs will act like only one display is present.
//
// exactly one source must include this with COMPILE_MULTIMON_STUBS defined
//
//=============================================================================
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
//
// if we are building on Win95/NT4 headers we need to declare this stuff ourselves
//
#ifndef SM_CMONITORS
#define SM_XVIRTUALSCREEN 76
#define SM_YVIRTUALSCREEN 77
#define SM_CXVIRTUALSCREEN 78
#define SM_CYVIRTUALSCREEN 79
#define SM_CMONITORS 80
#define SM_SAMEDISPLAYFORMAT 81
DECLARE_HANDLE(HMONITOR);
#define MONITOR_DEFAULTTONULL 0x00000000
#define MONITOR_DEFAULTTOPRIMARY 0x00000001
#define MONITOR_DEFAULTTONEAREST 0x00000002
#define MONITORINFOF_PRIMARY 0x00000001
typedef struct tagMONITORINFO
{
DWORD cbSize;
RECT rcMonitor;
RECT rcWork;
DWORD dwFlags;
} MONITORINFO, *LPMONITORINFO;
#define CCHDEVICENAME 32
#ifdef __cplusplus
typedef struct tagMONITORINFOEX : public tagMONITORINFO
{
TCHAR szDevice[CCHDEVICENAME];
} MONITORINFOEX, *LPMONITORINFOEX;
#else
typedef struct
{
MONITORINFO;
TCHAR szDevice[CCHDEVICENAME];
} MONITORINFOEX, *LPMONITORINFOEX;
#endif
typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM);
#endif // SM_CMONITORS
#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
typedef struct {
DWORD cb;
CHAR DeviceName[32];
CHAR DeviceString[128];
DWORD StateFlags;
} DISPLAY_DEVICE;
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008
#endif
#define DISPLAY_DEVICE_VGA 0x00000010
#ifndef ENUM_CURRENT_SETTINGS
#define ENUM_CURRENT_SETTINGS ((DWORD)-1)
#define ENUM_REGISTRY_SETTINGS ((DWORD)-2)
#endif
#undef GetMonitorInfo
#undef GetSystemMetrics
#undef MonitorFromWindow
#undef MonitorFromRect
#undef MonitorFromPoint
#undef EnumDisplayMonitors
#undef EnumDisplayDevices
//
// define this to compile the stubs
// otherwise you get the declarations
//
#ifdef COMPILE_MULTIMON_STUBS
//---------------------------------------------------------------------------
//
// Implement the API stubs.
//
//---------------------------------------------------------------------------
int (WINAPI* g_pfnGetSystemMetrics)(int);
HMONITOR (WINAPI* g_pfnMonitorFromWindow)(HWND, BOOL);
HMONITOR (WINAPI* g_pfnMonitorFromRect)(LPCRECT, BOOL);
HMONITOR (WINAPI* g_pfnMonitorFromPoint)(POINT, BOOL);
BOOL (WINAPI* g_pfnGetMonitorInfo)(HMONITOR, LPMONITORINFO);
BOOL (WINAPI* g_pfnEnumDisplayMonitors)(HDC, LPCRECT,
MONITORENUMPROC, LPARAM);
BOOL (WINAPI *g_pfnEnumDisplayDevices)(LPVOID, int,
DISPLAY_DEVICE *,DWORD);
BOOL InitMultipleMonitorStubs(void)
{
HMODULE hUser32;
static BOOL fInitDone;
if (fInitDone)
{
return g_pfnGetMonitorInfo != NULL;
}
if ((hUser32 = GetModuleHandle(TEXT("USER32"))) &&
(*(FARPROC*)&g_pfnGetSystemMetrics = GetProcAddress(hUser32,"GetSystemMetrics")) &&
(*(FARPROC*)&g_pfnMonitorFromWindow = GetProcAddress(hUser32,"MonitorFromWindow")) &&
(*(FARPROC*)&g_pfnMonitorFromRect = GetProcAddress(hUser32,"MonitorFromRect")) &&
(*(FARPROC*)&g_pfnMonitorFromPoint = GetProcAddress(hUser32,"MonitorFromPoint")) &&
(*(FARPROC*)&g_pfnEnumDisplayMonitors = GetProcAddress(hUser32,"EnumDisplayMonitors")) &&
#ifdef UNICODE
(*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoW")) &&
(*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesW")) &&
#else
(*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoA")) &&
(*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesA")) &&
#endif
(GetSystemMetrics(SM_CXVIRTUALSCREEN) >= GetSystemMetrics(SM_CXSCREEN)) &&
(GetSystemMetrics(SM_CYVIRTUALSCREEN) >= GetSystemMetrics(SM_CYSCREEN)) )
{
fInitDone = TRUE;
return TRUE;
}
else
{
g_pfnGetSystemMetrics = NULL;
g_pfnMonitorFromWindow = NULL;
g_pfnMonitorFromRect = NULL;
g_pfnMonitorFromPoint = NULL;
g_pfnGetMonitorInfo = NULL;
g_pfnEnumDisplayMonitors = NULL;
g_pfnEnumDisplayDevices = NULL;
fInitDone = TRUE;
return FALSE;
}
}
//---------------------------------------------------------------------------
//
// "stubbed" implementations of Monitor APIs that work with the primary // display
//
//---------------------------------------------------------------------------
int WINAPI
xGetSystemMetrics(int nIndex)
{
if (InitMultipleMonitorStubs())
return g_pfnGetSystemMetrics(nIndex);
switch (nIndex)
{
case SM_CMONITORS:
case SM_SAMEDISPLAYFORMAT:
return 1;
case SM_XVIRTUALSCREEN:
case SM_YVIRTUALSCREEN:
return 0;
case SM_CXVIRTUALSCREEN:
nIndex = SM_CXSCREEN;
break;
case SM_CYVIRTUALSCREEN:
nIndex = SM_CYSCREEN;
break;
}
return GetSystemMetrics(nIndex);
}
#define xPRIMARY_MONITOR ((HMONITOR)0x42)
HMONITOR WINAPI
xMonitorFromRect(LPCRECT lprcScreenCoords, UINT uFlags)
{
if (InitMultipleMonitorStubs())
return g_pfnMonitorFromRect(lprcScreenCoords, uFlags);
if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) ||
((lprcScreenCoords->right > 0) &&
(lprcScreenCoords->bottom > 0) &&
(lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) &&
(lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN))))
{
return xPRIMARY_MONITOR;
}
return NULL;
}
HMONITOR WINAPI
xMonitorFromWindow(HWND hWnd, UINT uFlags)
{
RECT rc;
if (InitMultipleMonitorStubs())
return g_pfnMonitorFromWindow(hWnd, uFlags);
if (uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST))
return xPRIMARY_MONITOR;
if (GetWindowRect(hWnd, &rc))
return xMonitorFromRect(&rc, uFlags);
return NULL;
}
HMONITOR WINAPI
xMonitorFromPoint(POINT ptScreenCoords, UINT uFlags)
{
if (InitMultipleMonitorStubs())
return g_pfnMonitorFromPoint(ptScreenCoords, uFlags);
if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) ||
((ptScreenCoords.x >= 0) &&
(ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) &&
(ptScreenCoords.y >= 0) &&
(ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN))))
{
return xPRIMARY_MONITOR;
}
return NULL;
}
BOOL WINAPI
xGetMonitorInfo(HMONITOR hMonitor, LPMONITORINFO lpMonitorInfo)
{
RECT rcWork;
if (InitMultipleMonitorStubs())
return g_pfnGetMonitorInfo(hMonitor, lpMonitorInfo);
if ((hMonitor == xPRIMARY_MONITOR) && lpMonitorInfo &&
(lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) &&
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0))
{
lpMonitorInfo->rcMonitor.left = 0;
lpMonitorInfo->rcMonitor.top = 0;
lpMonitorInfo->rcMonitor.right = GetSystemMetrics(SM_CXSCREEN);
lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN);
lpMonitorInfo->rcWork = rcWork;
lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY;
if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEX))
lstrcpy(((MONITORINFOEX*)lpMonitorInfo)->szDevice,
TEXT("DISPLAY"));
return TRUE;
}
return FALSE;
}
BOOL WINAPI
xEnumDisplayMonitors(
HDC hdc,
LPCRECT lprcIntersect,
MONITORENUMPROC lpfnEnumProc,
LPARAM lData)
{
RECT rcCallback, rcLimit;
if (InitMultipleMonitorStubs())
return g_pfnEnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc,
lData);
if (!lpfnEnumProc)
return FALSE;
rcLimit.left = 0;
rcLimit.top = 0;
rcLimit.right = GetSystemMetrics(SM_CXSCREEN);
rcLimit.bottom = GetSystemMetrics(SM_CYSCREEN);
if (hdc)
{
RECT rcClip;
HWND hWnd;
if ((hWnd = WindowFromDC(hdc)) == NULL)
return FALSE;
switch (GetClipBox(hdc, &rcClip))
{
default:
MapWindowPoints(NULL, hWnd, (LPPOINT)&rcLimit, 2);
if (IntersectRect(&rcCallback, &rcClip, &rcLimit))
break;
//fall thru
case NULLREGION:
return TRUE;
case ERROR:
return FALSE;
}
rcLimit = rcCallback;
}
if (!lprcIntersect ||
IntersectRect(&rcCallback, lprcIntersect, &rcLimit))
{
lpfnEnumProc(xPRIMARY_MONITOR, hdc, &rcCallback, lData);
}
return TRUE;
}
BOOL WINAPI
xEnumDisplayDevices(LPVOID lpReserved, int iDeviceNum,
DISPLAY_DEVICE * pDisplayDevice, DWORD dwFlags)
{
if (InitMultipleMonitorStubs())
return g_pfnEnumDisplayDevices(lpReserved, iDeviceNum,
pDisplayDevice, dwFlags);
return FALSE;
}
#undef xPRIMARY_MONITOR
#undef COMPILE_MULTIMON_STUBS
#else // COMPILE_MULTIMON_STUBS
extern int WINAPI xGetSystemMetrics(int);
extern HMONITOR WINAPI xMonitorFromWindow(HWND, UINT);
extern HMONITOR WINAPI xMonitorFromRect(LPCRECT, UINT);
extern HMONITOR WINAPI xMonitorFromPoint(POINT, UINT);
extern BOOL WINAPI xGetMonitorInfo(HMONITOR, LPMONITORINFO);
extern BOOL WINAPI xEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC,
LPARAM);
extern BOOL WINAPI xEnumDisplayDevices(LPVOID, int, DISPLAY_DEVICE *,DWORD);
#endif // COMPILE_MULTIMON_STUBS
//
// build defines that replace the regular APIs with our versions
//
#define GetSystemMetrics xGetSystemMetrics
#define MonitorFromWindow xMonitorFromWindow
#define MonitorFromRect xMonitorFromRect
#define MonitorFromPoint xMonitorFromPoint
#define GetMonitorInfo xGetMonitorInfo
#define EnumDisplayMonitors xEnumDisplayMonitors
#define EnumDisplayDevices xEnumDisplayDevices
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) */
Figure 7 GetMonitorInfo
BOOL GetMonitorInfo(
HMONITOR hmonitor, // the monitor to get the info for
LPMONITORINFO lpmi // the location of a MONITORINFO struct to receive the info
);
typedef struct tagMONITORINFO
{
DWORD cbSize;
RECT rcMonitor;
RECT rcWork;
DWORD dwFlags;
} MONITORINFO, *LPMONITORINFO;
typedef struct tagMONITORINFOEXA
{
MONITORINFO;
TCHAR szDevice[CCHDEVICENAME];
} MONITORINFOEX, *LPMONITORINFOEX;
Figure 8 CenterWindowNew Function
void CenterWindowNew(HWND hWnd)
{
HMONITOR hMonitor;
MONITORINFO mi;
RECT rcWnd;
RECT rcMon;
GetWindowRect(hWnd, &rcWnd);
hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
rcMon = mi.rcMonitor;
// Since we could no longer assume where the origin is, and because we
// have to calculate the monitor dimensions the equation is:
// Note that if rcMon.left and rcMon.top were 0, this
// simplifies to the above.
rcWnd.left = rcMon.left + ((rcMon.right - rcMon.left) -
(rcWnd.right - rcWnd.left)) / 2;
rcWnd.top = rcMon.top + ((rcMon.bottom - rcMon.top) -
(rcWnd.bottom - rcWnd.top)) / 2;
SetWindowPos(hWnd, NULL, rcWnd.left, rcWnd.top,
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
Figure 10 TestMM Sample Program
TestMM.c
/*---------------------------------------------------------------------------*\
| TestMM.c : A test sample that calls new Multi monitor APIs and |
| displays the results in a simple window. |
| |
\*---------------------------------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include "multimon.h"
#include "mmhelp.h"
#include "testmm.rc"
//
// normally you just include "multimon.h" (like above)
// but one C file needs to define COMPILE_MULTIMON_STUBS
// so the compatibility stubs will be defined
//
#define COMPILE_MULTIMON_STUBS
#include "multimon.h"
/*---------------------------------------------------------------------------*\
\*---------------------------------------------------------------------------*/
static char szAppName[]="TestMM";
static HINSTANCE hInstApp;
static HWND hwndApp;
/*---------------------------------------------------------------------------*\
\*---------------------------------------------------------------------------*/
LONG CALLBACK AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
int ErrMsg (LPSTR sz,...);
void AppSetText(LPSTR sz,...);
void AppPrint(LPSTR sz,...);
void GetOptimalDIBFormat(HDC hdc, BITMAPINFOHEADER *pbi);
/*---------------------------------------------------------------------------*\
\*---------------------------------------------------------------------------*/
void TestEnumDisplayDevices()
{
DWORD i;
DISPLAY_DEVICE dd;
DEVMODE dm;
AppPrint("");
AppPrint("EnumDisplayDevices:");
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
__try
{
for(i=0; EnumDisplayDevices(NULL, i, &dd, 0); i++)
{
AppPrint("Device %d:", i);
AppPrint(" DeviceName: '%s'", dd.DeviceName);
AppPrint(" DeviceString: '%s'", dd.DeviceString);
AppPrint(" StateFlags: %s%s%s%s",
((dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ? "desktop " : ""),
((dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE ) ? "primary " : ""),
((dd.StateFlags & DISPLAY_DEVICE_VGA ) ? "vga " : ""),
((dd.StateFlags & DISPLAY_DEVICE_MULTI_DRIVER ) ? "multi " : ""),
((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ) ? "mirror " : "") );
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm);
AppPrint(" Current Settings %dx%dx%d", dm.dmPelsWidth,
dm.dmPelsHeight,dm.dmBitsPerPel);
EnumDisplaySettings(dd.DeviceName, ENUM_REGISTRY_SETTINGS, &dm);
AppPrint(" Registry Settings %dx%dx%d",dm.dmPelsWidth,
dm.dmPelsHeight,dm.dmBitsPerPel);
}
}
__except(1)
{
AppPrint("EnumDisplayDevices faulted!");
}
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
BOOL CALLBACK CallbackNull(HMONITOR hMonitor,HDC hdc, LPRECT prc, LPARAM lParam)
{
return TRUE;
}
BOOL CALLBACK CallbackWindow(HMONITOR hMonitor,HDC hdc, LPRECT prc,
LPARAM lParam)
{
return TRUE;
}
BOOL CALLBACK CallbackRect(HMONITOR hMonitor,HDC hdc, LPRECT prc, LPARAM lParam)
{
return TRUE;
}
BOOL CALLBACK CallbackScreen(HMONITOR hMonitor,HDC hdc,LPRECT prc,LPARAM lParam)
{
MONITORINFOEX mix;
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
mix.cbSize = sizeof(mix);
GetMonitorInfo(hMonitor, (MONITORINFO*)&mix);
AppPrint("Monitor %08X", hMonitor);
AppPrint(" szDevice = '%s'", (LPSTR)mix.szDevice);
AppPrint(" rcMonitor = [%d,%d,%d,%d]", mi.rcMonitor);
AppPrint(" rcWork = [%d,%d,%d,%d]", mi.rcWork);
AppPrint(" dwFlags = %08X", mi.dwFlags);
if (hdc)
{
struct {
BITMAPINFOHEADER bi;
DWORD ct[256];
} dib;
GetOptimalDIBFormat(hdc, &dib.bi);
AppPrint(" VREFRESH = %d", GetDeviceCaps(hdc, VREFRESH ));
AppPrint(" DESKTOPVERTRES = %d", GetDeviceCaps(hdc, DESKTOPVERTRES ));
AppPrint(" DESKTOPHORZRES = %d", GetDeviceCaps(hdc, DESKTOPHORZRES ));
AppPrint(" BLTALIGNMENT = %d", GetDeviceCaps(hdc, BLTALIGNMENT ));
AppPrint(" HORZRES = %d", GetDeviceCaps(hdc, HORZRES ));
AppPrint(" VERTRES = %d", GetDeviceCaps(hdc, VERTRES ));
AppPrint(" PALETTE = %s",
(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? "Yes" : "No");
AppPrint(" BITSPIXEL = %d",
GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES));
if (dib.bi.biCompression == BI_BITFIELDS)
{
if (dib.ct[0] == 0xF800 &&
dib.ct[1] == 0x07E0 &&
dib.ct[2] == 0x001F )
{
AppPrint(" FORMAT = 565");
}
if (dib.ct[0] == 0x7C00 &&
dib.ct[1] == 0x03E0 &&
dib.ct[2] == 0x001F )
{
AppPrint(" FORMAT = 555");
}
if (dib.ct[0] == 0xFF0000 &&
dib.ct[1] == 0x00FF00 &&
dib.ct[2] == 0x0000FF )
{
AppPrint(" FORMAT = BGR");
}
if (dib.ct[0] == 0x0000FF &&
dib.ct[1] == 0x00FF00 &&
dib.ct[2] == 0xFF0000 )
{
AppPrint(" FORMAT = RGB");
}
}
}
return TRUE;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void TestEnumDisplayMonitors()
{
HDC hdc;
RECT rc;
AppPrint("");
AppPrint("EnumDisplayMonitors");
EnumDisplayMonitors(NULL, NULL, CallbackNull, 42);
hdc = GetDC(NULL);
EnumDisplayMonitors(hdc, NULL, CallbackScreen, 42);
ReleaseDC(NULL,hdc);
hdc = GetDC(hwndApp);
EnumDisplayMonitors(hdc, NULL, CallbackWindow, 42);
ReleaseDC(hwndApp,hdc);
GetWindowRect(hwndApp, &rc);
EnumDisplayMonitors(NULL, &rc, CallbackRect, 42);
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void DoTestMM(HWND hwnd, LPARAM lParam)
{
HDC hdc;
RECT rc;
static HMONITOR hMonitorMe;
HMONITOR hMonitor;
hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
if (hMonitorMe == hMonitor && lParam)
return;
hMonitorMe = hMonitor;
AppPrint(NULL);
if (hMonitor)
{
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, (MONITORINFO*)&mi);
AppSetText(mi.szDevice);
AppPrint("My Window is on hMonitor %08X",hMonitor);
}
else
{
AppSetText(NULL);
AppPrint("My Window is not visible");
}
AppPrint("");
AppPrint("SM_CMONITORS is %d", GetSystemMetrics(SM_CMONITORS));
AppPrint("SM_SAMEDISPLAYFORMAT is %d",
GetSystemMetrics(SM_SAMEDISPLAYFORMAT));
AppPrint("SM_XVIRTUALSCREEN is %d", GetSystemMetrics(SM_XVIRTUALSCREEN));
AppPrint("SM_YVIRTUALSCREEN is %d", GetSystemMetrics(SM_YVIRTUALSCREEN));
AppPrint("SM_CXVIRTUALSCREEN is %d", GetSystemMetrics(SM_CXVIRTUALSCREEN));
AppPrint("SM_CYVIRTUALSCREEN is %d", GetSystemMetrics(SM_CYVIRTUALSCREEN));
hdc = GetDC(NULL);
GetClipBox(hdc, &rc);
AppPrint("GetClipBox of GetDC(NULL) = [%d,%d,%d,%d]", rc);
ReleaseDC(NULL, hdc);
hdc = GetDC(GetDesktopWindow());
GetClipBox(hdc, &rc);
AppPrint("GetClipBox of GetDC(desktop) = [%d,%d,%d,%d]", rc);
ReleaseDC(GetDesktopWindow(), hdc);
GetWindowRect(GetDesktopWindow(), &rc);
AppPrint("GetWindowRect of desktop = [%d,%d,%d,%d]", rc);
TestEnumDisplayMonitors();
TestEnumDisplayDevices();
}
/*----------------------------------------------------------------------------*\
| AppInit( hInst, hPrev) |
\*----------------------------------------------------------------------------*/
BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw,LPSTR szCmdLine)
{
WNDCLASS cls;
int dx,dy;
/* Save instance handle for DialogBoxs */
hInstApp = hInst;
if (!hPrev)
{
/*
* Register a class for the main application window
*/
cls.hCursor = LoadCursor(NULL,IDC_ARROW);
cls.hIcon = LoadIcon(hInst,"AppIcon");
cls.lpszMenuName = "AppMenu";
cls.lpszClassName = szAppName;
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
cls.hInstance = hInst;
cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
cls.lpfnWndProc = (WNDPROC)AppWndProc;
cls.cbWndExtra = 0;
cls.cbClsExtra = 0;
if (!RegisterClass(&cls))
return FALSE;
}
dx = GetSystemMetrics (SM_CXSCREEN) / 2;
dy = GetSystemMetrics (SM_CYSCREEN) / 2;
hwndApp = CreateWindow (szAppName, // Class name
szAppName, // Caption
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0,
dx,dy, // Size
(HWND)NULL, // Parent window (no parent)
(HMENU)NULL, // use class menu
hInst, // handle to window instance
(LPSTR)NULL // no params to pass on
);
ShowWindow(hwndApp,sw);
return TRUE;
}
/*----------------------------------------------------------------------------*\
| AppWndProc( hwnd, uiMessage, wParam, lParam ) |
| |
| Description: |
| The window proc for the app's main (tiled) window. This processes all |
| of the parent window's messages. |
| |
\*----------------------------------------------------------------------------*/
LONG FAR PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
HWND hwndC;
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_TEST_CENTERTOMONITOR:
CenterWindowToMonitor(hwnd, hwnd, FALSE);
break;
case ID_TEST_CENTERTOWORKAREA:
CenterWindowToMonitor(hwnd, hwnd, TRUE);
break;
case ID_TEST_CLIPTOMONITOR:
ClipWindowToMonitor(hwnd, hwnd, FALSE);
break;
case ID_TEST_CLIPTOWORKAREA:
ClipWindowToMonitor(hwnd, hwnd, TRUE);
break;
case ID_TEST_RUNNOTEPAD:
ShellExecute(hwnd,"open","notepad.exe",NULL,NULL,SW_SHOWNORMAL );
break;
}
break;
case WM_KEYUP:
if (wParam == VK_F5)
DoTestMM(hwnd, 0);
break;
case WM_WINDOWPOSCHANGED:
DoTestMM(hwnd, 1);
break;
case WM_SETTINGCHANGE:
case WM_DISPLAYCHANGE:
DoTestMM(hwnd, 0);
break;
case WM_SIZE:
if (hwndC = GetWindow(hwnd, GW_CHILD))
MoveWindow(hwndC, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}
/*----------------------------------------------------------------------------*\
| ErrMsg - Opens a Message box with a error message in it. The user can |
| select the OK button to continue |
\*----------------------------------------------------------------------------*/
int ErrMsg (LPSTR sz,...)
{
char ach[128];
wvsprintf (ach,sz,(LPSTR)(&sz+1)); /* Format the string */
MessageBox(hwndApp,ach,szAppName,MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
return FALSE;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void AppSetText(LPSTR sz,...)
{
char ach[128];
lstrcpy(ach, szAppName);
if (sz != NULL && *sz != 0)
{
lstrcat(ach, " - ");
wvsprintf (ach+lstrlen(ach),sz,(LPSTR)(&sz+1)); /* Format the string */
}
SetWindowText(hwndApp, ach);
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
void AppPrint(LPSTR sz,...)
{
HWND hwndE = GetWindow(hwndApp, GW_CHILD);
char ach[128];
if (hwndE == NULL)
{
RECT rc;
GetClientRect(hwndApp, &rc);
hwndE = CreateWindow ("Edit", "", WS_VISIBLE | WS_CHILD | ES_MULTILINE |
ES_READONLY | WS_VSCROLL | ES_AUTOVSCROLL,
0, 0, rc.right, rc.bottom, hwndApp, (HMENU)-1,
hInstApp, NULL);
SetWindowFont(hwndE, GetStockObject(ANSI_FIXED_FONT), TRUE);
}
if (sz == NULL)
{
Edit_SetSel(hwndE, 0, (UINT)-1);
Edit_ReplaceSel(hwndE, "");
}
else
{
wvsprintf (ach,sz,(LPSTR)(&sz+1)); /* Format the string */
lstrcat(ach, "\r\n");
Edit_SetSel(hwndE, (UINT)-1, (UINT)-1);
Edit_ReplaceSel(hwndE, ach);
}
}
/*----------------------------------------------------------------------------*\
| WinMain( hInst, hPrev, lpszCmdLine, cmdShow ) |
\*----------------------------------------------------------------------------*/
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
MSG msg;
DWORD dw=0;
/* Call initialization procedure */
if (!AppInit(hInst,hPrev,sw,szCmdLine))
return FALSE;
/*
* Polling messages from event queue
*/
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
WaitMessage();
}
}
return msg.wParam;
}
//
// GetOptimalDIBFormat
//
// get the optimal DIB format for a display device.
// the optimal DIB format is the format that exactly
// matches the format of the device, this is very important
// when dealing with 16bpp modes, you need to know
// what bitfields to use (555 or 565 for example)
//
// you normaly use this function to get the best
// format to pass to CreateDIBSection()
//
// Input
// hdc device to get the optimal format for.
// pbi pointer to a bitmapinfo + color table
// (room for 256 colors are assumed)
//
// Output
// pbi contains optimal DIB format, in the <= 8bpp case
// the color table will contain the system palette
// in the >=16bpp case the "color table" will contain
// the correct bit fields (see BI_BITFIELDS for more info)
//
// Notes
// if you are going to use this function on a 8bpp device
// you should make sure the colortable contains a indentity
// palette for optimal blt'ing
//
void GetOptimalDIBFormat(HDC hdc, BITMAPINFOHEADER *pbi)
{
HBITMAP hbm;
hbm = CreateCompatibleBitmap(hdc, 1, 1);
ZeroMemory(pbi, sizeof(BITMAPINFOHEADER));
pbi->biSize = sizeof(BITMAPINFOHEADER);
pbi->biBitCount = 0;
// first call will fill in the optimal biBitCount
GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)pbi, DIB_RGB_COLORS);
// second call will get the optimal color table, or the optimal bitfields
GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)pbi, DIB_RGB_COLORS);
DeleteObject(hbm);
}
TestMM.RC
#include <windows.h>
#define ID_TEST_CENTERTOMONITOR 100
#define ID_TEST_CENTERTOWORKAREA 101
#define ID_TEST_CLIPTOMONITOR 102
#define ID_TEST_CLIPTOWORKAREA 103
#define ID_TEST_RUNNOTEPAD 104
#ifdef RC_INVOKED
AppMenu MENU DISCARDABLE
BEGIN
POPUP "Test"
BEGIN
MENUITEM "Center to monitor", ID_TEST_CENTERTOMONITOR
MENUITEM "Center to work area", ID_TEST_CENTERTOWORKAREA
MENUITEM "Clip to monitor", ID_TEST_CLIPTOMONITOR
MENUITEM "Clip to work area.", ID_TEST_CLIPTOWORKAREA
MENUITEM "Run NOTEPAD.EXE", ID_TEST_RUNNOTEPAD
END
END
#endif
MMHelp.C
/*----------------------------------------------------------------------------*\
| MMHELP.C - routines to help a app be multimonitor aware
\*----------------------------------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include "multimon.h"
//
// GetMonitorRect
//
// gets the "screen" or work area of the monitor that the passed
// window is on. this is used for apps that want to clip or
// center windows.
//
// the most common problem apps have with multimonitor systems is
// when they use GetSystemMetrics(SM_C?SCREEN) to center or clip a
// window to keep it on screen. If you do this on a multimonitor
// system the window we be restricted to the primary monitor.
//
// this is a example of how you used the new Win32 multimonitor APIs
// to do the same thing.
//
void GetMonitorRect(HWND hwnd, LPRECT prc, BOOL fWork)
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
if (fWork)
*prc = mi.rcWork;
else
*prc = mi.rcMonitor;
}
//
// ClipRectToMonitor
//
// uses GetMonitorRect to clip a rect to the monitor that
// the passed window is on.
//
void ClipRectToMonitor(HWND hwnd, RECT *prc, BOOL fWork)
{
RECT rc;
int w = prc->right - prc->left;
int h = prc->bottom - prc->top;
if (hwnd != NULL)
{
GetMonitorRect(hwnd, &rc, fWork);
}
else
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST), &mi);
if (fWork)
rc = mi.rcWork;
else
rc = mi.rcMonitor;
}
prc->left = max(rc.left, min(rc.right-w, prc->left));
prc->top = max(rc.top, min(rc.bottom-h, prc->top));
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
//
// CenterRectToMonitor
//
// uses GetMonitorRect to center a rect to the monitor that
// the passed window is on.
//
void CenterRectToMonitor(HWND hwnd, RECT *prc, BOOL fWork)
{
RECT rc;
int w = prc->right - prc->left;
int h = prc->bottom - prc->top;
GetMonitorRect(hwnd, &rc, fWork);
prc->left = rc.left + (rc.right - rc.left - w) / 2;
prc->top = rc.top + (rc.bottom - rc.top - h) / 2;
prc->right = prc->left + w;
prc->bottom = prc->top + h;
}
//
// CenterWindowToMonitor
//
void CenterWindowToMonitor(HWND hwndP, HWND hwnd, BOOL fWork)
{
RECT rc;
GetWindowRect(hwnd, &rc);
CenterRectToMonitor(hwndP, &rc, fWork);
SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
//
// ClipWindowToMonitor
//
void ClipWindowToMonitor(HWND hwndP, HWND hwnd, BOOL fWork)
{
RECT rc;
GetWindowRect(hwnd, &rc);
ClipRectToMonitor(hwndP, &rc, fWork);
SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
//
// IsWindowOnScreen
//
BOOL IsWindowOnScreen(HWND hwnd)
{
HDC hdc;
RECT rc;
BOOL f;
GetWindowRect(hwnd, &rc);
hdc = GetDC(NULL);
f = RectVisible(hdc, &rc);
ReleaseDC(NULL, hdc);
return f;
}
//
// MakeSureWindowIsVisible
//
void MakeSureWindowIsVisible(HWND hwnd)
{
if (!IsWindowOnScreen(hwnd))
{
ClipWindowToMonitor(hwnd, hwnd, TRUE);
}
}