關於部落格
最會的事 就是這個不會和那個不會此網誌以 轉貼 文章為主
  • 224352

    累積人氣

  • 11

    今日人氣

    2

    追蹤人氣

多螢幕顯示器編程( 一 )

多螢幕顯示器編程( )

 

http://dalianit.com/edu/14229.html

Programming for Multiple Monitors in Windows 98
How to use the new Win32 API functions that enable your programs to take advantage of multiple monitors.

 

By Paul Modzelewski

 

One of the most eagerly anticipated (and long overdue) features of Windows 98 is support for multiple monitors. This feature allows you to add a second video card and monitor to your PC; your Windows virtual desktop will be extended to cover the new monitor. Until now this capability has been possible only through the use of a specialized video card.

 

Programmers, Web page authors, graphic artists, and power users are the most likely audience for this technology. Most existing programs require no changes to work with multiple monitors, but there are several new Win32 API functions related to multiple-monitor support. If you want your programs to detect and take advantage of multiple monitors, you will need to be familiar with these functions and how they work. In this article, I'll discuss installing multiple monitors on your PC and how to use the new API functions in your programs. The programming section assumes a basic understanding of the Win32 API and C/C++ programming. It is important to note that the information in this article pertains to a beta version of Windows 98 and is subject to change by the time Windows 98 is released.

 

Paul Modzelewski is a software engineer and cofounder of Iconoclast Software. He can be reached via e-mail at paul@moon.jic.com.

 

 

 

多螢幕顯示器編程( )

 

http://dalianit.com/edu/14230.html

Programming for Multiple Monitors in Windows 98
Installing Multiple Monitors

 

Continued from Introduction

 

Setting up multiple monitors is relatively easy, but there are a few ground rules. Both of your video cards must be on the PCI bus, and your secondary display must be one of the devices supported by Windows. Most popular brands of PCI display adapters are currently supported, and the list will surely expand by the time Windows 98 is released.

 

One minor issue in the installation process is that the newly added video card will become your primary display. The documentation states that this inconvenience stems from a limitation of the PCI bus. If you want your current video card to be your primary display, you will need to do some installation juggling. Just remember that any newly added display adapter will become your primary desktop.

 

Once you've installed a second monitor, the Display Properties control panel will contain a new Monitors tab (see Figure 1), which replaces the Settings tab. From the Monitors tab you can change the positioning of your monitors and the display settings of each individual display, such as resolution and number of colors. Windows uses the monitors' resolution and relative positioning to set up the virtual desktop and its coordinate system (see Figure 2). The top-left corner of the primary display is always position (0,0), with the x-coordinates increasing as you move right and the y-coordinates increasing as you move down. The coordinates of additional monitors are determined by their positions relative to the primary display. Since Windows 98 allows negative coordinates within the desktop window, your programs should not assume that a negative number is invalid when dealing with desktop coordinates.

 

Because Windows was originally designed to handle only one monitor, some applications will not behave correctly on a multiple-monitor system. While the problems are more often annoying than fatal, most applications will require some slight changes to operate optimally on a system with more than one monitor.

 

Next: New Multiple-Monitor Win32 API functions

 

多螢幕顯示器編程( )

 

Programming for Multiple Monitors in Windows 98
New Multiple-Monitor Win32 API functions

 

Continued from Installing Multiple Monitors

 

In order to give applications access to multiple-monitor information, Microsoft has added several new Win32 API functions and updated several existing functions. In addition to new functions, there is also a new type of handle, the HMONITOR, which represents a physical display device. In order to get and set the settings of a particular monitor, you first need to obtain an HMONITOR, which will always point to the same monitor.

 

The first of the new functions we will discuss is MonitorFromPoint, which has the following definition:

 

HMONITOR MonitorFromPoint(POINT pt,

 

DWORD dwFlags);

 

The returned HMONITOR is the monitor that contains the POINT passed to the function. If no monitor contains the specified point, then the return value of MonitorFromPoint is determined by dwFlags, for which there are three possible values: MONITOR_DEFAULTTONULL returns NULL if the point is not contained by any monitor, MONITOR_DEFAULTTOPRIMARY returns the primary display device, and MONITOR_DEFAULTTONEAREST returns the monitor closest to the point.

 

HMONITOR MonitorFromRect(LPRECT lprc,

 

DWORD dwFlags);

 

HMONITOR MonitorFromWindow(HWND hWnd,

 

DWORD dwFlags);

 

MonitorFromRect and MonitorFromWindow return the handle of the monitor that contains the largest portion of the specified rectangle or window. If no monitor contains the specified rectangle or window, the return value depends upon the value of the dwFlags field, which has the same possible values for these two functions as it does for MonitorFromPoint.

 

Once you have obtained an HMONITOR, you can use the function GetMonitorInfo to retrieve a MONITORINFO structure filled with data relevant to the specified monitor, as follows:

 

BOOL GetMonitorInfo( HMONITOR hmonitor, LPMONITORINFO lpmi);

 

typedef struct tagMONITORINFO

 

{

 

DWORD cbSize;

 

RECT rcMonitor;

 

RECT rcWork;

 

DWORD dwFlags;

 

} MONITORINFO, *LPMONITORINFO;

 

typedef struct tagMONITORINFOEXA

 

{

 

MONITORINFO;

 

TCHAR szDevice[CCHDEVICENAME];

 

} MONITORINFOEX, *LPMONITORINFOEX;

 

There are actually two versions of this structure, MONITORINFO and MONITORINFOEX. The cbSize member contains the size of the structure, and it is used by Windows to determine whether a structure is a MONITORINFO or MONITORINFOEX. After a successful call to GetMonitor, the rcMonitor member contains the rectangle of the monitor within the virtual desktop. The rcWork member contains the work area of the monitor within the virtual desktop. (A monitor's work area is the portion not covered by the taskbar.) The dwFlags member has only one possible value, MONITORINFOF_PRIMARY, which is set if the monitor is the primary display. The MONITORINFOEX structure has one additional parameter, szDevice, which contains the unique name of the device. The device name can be passed to other functions, such as ChangeDisplaySettingsEx, allowing the settings for each monitor to be changed independently.

 

Before you pass GetMonitorInfo a pointer to a MONITORINFO or MONITORINFOEX structure, you must set the cbSize member to the size of the structure so that Windows can determine which structure is being used. The following code sample shows how:

 

MONITORINFOEX mix;

 

mix.cbSize = sizeof(mix);

 

GetMonitorInfo(hMonitor,

 

(LPMONITORINFO)&mix);

 

Some changes were made to GetSystemMetrics to allow the use of multiple monitors. Passing SM_CXSCREEN and SM_CYSCREEN as parameters returns the x and y extents, respectively, of only the primary monitor. If you wish to get the x and y extents of the virtual desktop, use the new constants SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN; GetSystemMetrics will return the left and top coordinates of the virtual desktop, respectively. You can no longer assume the top-left corner of the desktop is (0,0), and the extents will do you no good if you don't know the origins. Passing the new constant SM_SAMEDISPLAYFORMAT to GetSystemMetrics will return TRUE if all of the monitors on the system have exactly the same color settings, FALSE otherwise. Use the constant SM_CMONITORS when you want to know how many monitors make up the virtual desktop. Note that this value includes only installed monitors that have been added to the desktop by the user.

 

The SystemParametersInfo function has also been changed slightly. The changes affect only the uiAction values SPI_GETWORKAREA and SPI_SETWORKAREA. Using the former always returns the work area of the primary monitor. If you want to get the work area of another monitor, you need to use GetMonitorInfo. Using SPI_SETWORKAREA sets the work area of the monitor that contains the RECT structure passed into the pvParam value.

 

EnumDisplayMonitors is a new function that allows an application to optimize its drawing code when a window is being partially displayed on multiple monitors that have different color-bit depths.

 

BOOL WINAPI EnumDisplayMonitors(

 

HDC hdc,

 

LPCRECT lprcClip,

 

MONITORENUMPROC lpfnEnum,

 

LPARAM dwData);

 

The MONITORENUMPROC callback is called for each monitor that intersects the visible region of hdc and the lprcClip parameter. If the lprcClip parameter is NULL, then no additional clipping is performed. The dwData parameter is for user-defined data and is passed through to the dwData parameter in the callback function. MONITORENUMPROC is a user-defined callback function that must have the following signature:

 

BOOL CALLBACK MonitorEnumProc(

 

HMONITOR hmonitor,

 

HDC hdcMonitor,

 

LPRC lprcMonitor,

 

DWORD dwData);

 

If the hdc passed to EnumDisplayMonitors was NULL, then hdcMonitor is NULL. Otherwise, hdcMonitor contains a valid device context whose color attributes match the display monitor defined by hmonitor. If hdcMonitor is NULL, then lprcMonitor is in virtual-desktop coordinates. It is important to note that no application needs to use EnumDisplayMonitors to handle monitors of differing bit depths, since Windows automatically dithers high-color images on lower-color devices. You should use this function only if you want to do custom dithering to ensure the best possible display. In order to help you understand exactly how EnumDisplayMonitors is used, I will present a couple of code snippets illustrating common usage scenarios.

 

One use for EnumDisplayMonitors is to make sure that images are drawn optimally on lower-color devices. The best way to do this is to change how your window's WndProc handles the WM_PAINT message.

 

case WM_PAINT:

 

HDC hdc;

 

hdc = BeginPaint(hWnd,

 

&paintStruct);

 

EnumDisplayMonitors(hdc, NULL, monitorEnumPaintProc, 0);

 

EndPaint(&paintStruct);

 

Inside your callback, you query the passed device context to determine its capabilities and display area and do your drawing accordingly.

 

You can also use EnumDisplayMonitors to query every monitor on the desktop. If the device context and RECT passed into EnumDisplayMonitors are both NULL, no clipping is performed and your callback function is called once for each monitor in the virtual desktop. The code in Figure 3 caches the work area of every monitor for later use. (Note that if your application actually did this, you would need to update the cached information when the WM_DISPLAYCHANGE message was received, since the values might change.)

 

Another way to query display devices is the EnumDisplayDevices function, which can query all devices available on the system, whether or not they're part of the virtual desktop.

 

BOOL WINAPI EnumDisplayDevices(

 

PVOID Unused,

 

DWORD iDevNum,

 

PDISPLAY_DEVICE lpDisplayDevice,

 

DWORD dwFlags);

 

Unused is reserved for future use and must be set to NULL. There are no valid values for dwFlags, so set it to 0. iDevNum is the index of the device you wish to query and is zero-based. If there is not a device available in the iDevNum position, EnumDisplayDevices returns FALSE. If there is a device in the position indicated by iDevNum, EnumDisplayDevices returns TRUE and fills in lpDisplayDevice. So to examine all devices on the system, you'd call EnumDisplayDevices for each possible index, starting with 0, until it returned FALSE. The lpDisplayDDevice parameter is a pointer to a DISPLAY_DEVICE structure, which is defined as follows:

 

typedef struct _DISPLAY_DEVICE {

 

DWORD cb;

 

BYTE DeviceName[32];

 

BYTE DeviceString[128];

 

DWORD StateFlags;

 

} DISPLAY_DEVICE, *PDISPLAY_DEVICE,

 

*LPDISPLAY_DEVICE;

 

The cb member contains the size of the structure in bytes. DeviceName is the same unique name returned by GetMonitorInfo in the szDevice member of the MONITORINFOEX structure. DeviceString is a user-friendly description of the enumerated device. Unfortunately, I was not able to find documentation on the possible values of StateFlag, but they seem self-explanatory. Here are their definitions as listed in the Win32 SDK:

 

#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

 

#define DISPLAY_DEVICE

 

_VGA_COMPATIBLE

 

0x00000010

 

Since EnumDisplayDevices allows you to query devices that aren't part of the desktop, your application can use monitors in an exclusive manner, without having to share the screen with the desktop. To do this, find a device that doesn't have the DISPLAY_DEVICE_ATTACHED_TO_DESKTOP bit set and call the Win32 API function CreateDC, passing the name returned in the DeviceName member of lpDisplayDevice. If you create a device context in this manner, you should delete it when you're done with it by calling DeleteDC.

 

Next: Other Issues

 

Published as Power Programming in the 4/7/98 issue of PC Magazine.

 

多螢幕顯示器編程( )

 

Programming for Multiple Monitors in Windows 98
Other Issues

 

Continued from New Multiple-Monitor Win32 API functions

 

If you use these new API functions to make your applications multiple monitor-friendly, what will happen on systems running a version of Windows that does not have the multimonitor functions? (Neither Windows 95 nor Windows NT 4.0 includes the multiple-monitor APIs.) They will crash, unless you do something about it. The solution is a new header file, Multimon.h, which uses GetProcAddress to determine whether the relevant functions are actually in the system DLLs. If they are not, it supplies default implementations of these functions. This header file actually contains source code, and if the COMPILE_MULTIMON_STUBS flag is set, the code will be compiled. This means that you should define COMPILE_MULTIMON_STUBS in one--and only one--source file that includes Multimon.h. You can include Multimon.h in as many source files as you want, but make sure that COMPILE_MULTIMON_STUBS is defined in only one. The end result of this process is a single executable file that will run on all versions of Win32.

 

There are also a few new rules you should follow if you want your programs to behave correctly on a multiple-monitor system. Remember that negative desktop coordinates are now valid, so don't assume otherwise. For example, don't hide your application by moving its window to a negative position. You should also take care when centering dialogs on a monitor. If you don't check which monitor your application is on, you may be centering your dialog on the wrong monitor.

 

Another potential pitfall is the incorrect casting of window message parameters that are window coordinates. Since negative coordinates used to be invalid, it didn't matter if you accidentally cast an integer position value to a DWORD.

 

If you follow sound coding practices in general, you should find that your application will require very little work to become multiple monitor-friendly. When Windows 98 is finally released, multiple-monitor systems will probably become fairly common. If you want to make your programs as high in quality as possible, or if you target a market where multiple monitors will be prevalent, add some multiple-monitor situations to your test plans.

 

Microsoft has done quite a good job of incorporating multiple-monitor support into an OS that wasn't designed for it. But applications written before multiple-monitor support was available may behave unreliably, especially when displayed on a monitor other than the primary monitor. My own experience has shown that while such problems can be frustrating, they can be worked out. Once you have adapted to the multi-monitor quirks of your applications, it's hard to go back to the confines of a single monitor. If you have an old 14-inch monitor sitting around, you may find it worthwhile to buy a cheap PCI video card and set up a second display.

 

Next: Figure 1: The Display Properties Control Panel

 

Published as Power Programming in the 4/7/98 issue of PC Magazine.

 

多螢幕顯示器編程( )

 

Programming for Multiple Monitors in Windows 98
Figure 1: The Display Properties Control Panel

 

Continued from Other Issues

 

Windows 98's Display Properties control panel contains a Monitor tab when multiple monitors have been set up.

 

 

Next: Figure 2: The Virtual Desktop

 

Published as Power Programming in the 4/7/98 issue of PC Magazine

 

多螢幕顯示器編程( )

 

Programming for Multiple Monitors in Windows 98
Figure 2: The Virtual Desktop

 

Continued from Figure 1: The Display Properties Control Panel

 

Windows uses the resolution of each monitor and the relative positioning of the monitors to set up the virtual desktop and its coordinate system.

 

 

Next: Figure 3: Cache the Work Area

 

Published as Power Programming in the 4/7/98 issue of PC Magazine

 

多螢幕顯示器編程( )

 

Programming for Multiple Monitors in Windows 98
Figure 3: Cache the Work Area

 

Continued from Figure 2: The Virtual Desktop

 

This code snippet caches the work area of every monitor for later use.

 

// global variables to store work area

 

int gCount;

 

LPRECT gpRectArray = NULL;

 

void CacheWorkAreas()

 

{

 

// set the counter to 0

 

gCount = 0;

 

// delete old array, since number of monitors may

 

// have changed

 

delete [] gpRectArray;

 

// allocate a new array sized to the number of monitors

 

gpRectArray = new RECT[GetSystemMetrics(SM_CMONITORS)];

 

EnumDisplayMonitors(NULL, NULL, monitorEnumInfoProc, 0);

 

}

 

// definition of callback function

 

BOOL CALLBACK monitorEnumProc(

 

HMONITORhmonitor,

 

HDChdcMonitor,

 

LPRClprcMonitor,

 

DWORDdwData)

 

{

 

相簿設定
標籤設定
相簿狀態