Windows Multi-display development Diary

Source: Internet
Author: User
Tags home screen

Integration Article address: http://www.cnblogs.com/wuchang/archive/2006/06/20/430766.html

Address: http://blog.sina.com.cn/s/blog_4078ccd60100049d.html thanks to the two gods for their selfless dedication ....

Http://www.microsoft.com/msj/0697/monitor/monitor.aspx


Over the past few days, I have studied the multi-display programming in windows and implemented the universal COM component that supports the 10-Display Mode in windows. Here I will make a summary and review, I hope I can give some inspiration and help to the developers in this regard:

(1) the principle of multi-monitor mode in Windows the new Microsoft operating system (Windows 98 \ Windows 2000 \ Windows XP) has built-in support for multi-monitor, that is, you can install Multiple display cards on a computer and connect them to multiple monitors. Then, the display areas of these displays are organized into a large virtual Windows desktop. There is a system taskbar at the bottom of each display area. We can add a desktop shortcut in any display area so that we can program with Visual C ++ In the first display area, at the same time, enable Internet Explorer in the second display area-no longer need to switch over. The principle of multi-monitor mode is actually very simple. It depends mainly on the operating system. For example, WINXP supports 10 monitors. The debugging and development environments used in this article are dominated by WINXP, the other principles are the same. Just debug them slowly. windows provides the following three functions:

1. larger Windows desktop: in Multi-monitor mode, you can combine the display areas of multiple monitors to Display Windows desktops, regardless of the size, physical location, resolution, and refresh frequency of these displays. When we run an application, the main window of the program can be located in the display area of any monitor, or across multiple display areas. We can also move a program window from one display area to another.

2. Screen Copy or remote display: We can make the two monitors display the same content. This feature is useful during training or demonstration to everyone. With this feature, technical support staff can also remotely monitor and debug applications.

3. multiple independent displays: in the preceding two modes, all display areas are part of Windows virtual desktops. However, in multiple independent display modes, the displays accessed by applications are not part of Windows virtual desktops. Assuming that the second display of the system is a high-resolution large-size display, we can use it for specialized display of CAD applications. By calling the new Windows API in the CAD application, we can use GDI to draw a picture on it. The display area of the independent monitor does not have any objects (taskbar and shortcuts) on the desktop. It is independent of Windows desktop. This can avoid any interference from Windows desktop to application output, and we do not have to worry about dragging other windows to the Independent display area accidentally, this method is like providing a dedicated monitor for the application.

(2) Understand virtual desktop and its coordinates. Since it is necessary to program and develop the multi-display mode, we must first understand the virtual desktop and Its Coordinates of windows. this is the basis of our programming and development. It is easy to understand everything and there is almost no difficulty.

In a single display system, the actual shape and size of the Windows desktop are the same as those of the display. In multi-monitor mode, each monitor is actually a "sub-window" of a large virtual desktop ".

We can adjust the size (resolution) and relative position of each display area through the Display Properties in the control panel, all of which are interconnected but not overlapped. In Figure 1, monitor 1 is the primary Monitor, and the role of the primary monitor is to determine the coordinates of the virtual desktop. Regardless of the location of the primary Monitor, the coordinates in the upper left corner of its display area are set to the zero point () of the virtual coordinates, and the coordinates in the lower right corner are (X-1, Y-1) (assuming that the resolution of the primary monitor is x Y), the coordinates of the remaining display areas are determined by the relative position of the primary Monitor and the primary monitor. Generally, the relative position of the display area in a virtual desktop is the same as that of the actual display. Because all display areas must be connected, a minimum rectangle containing all display areas can be used to represent the size of the virtual desktop. The rectangular boundary in Figure 1 represents the range of the virtual desktop.

Because the coordinate system in the virtual desktop must be continuous, the coordinates of the second display area are the continuation of the display area of the main monitor. Assuming that both displays use a resolution of 1024x768 and the second display is located on the right of the first display (main display), the coordinates of the second display area are from (, 0) to (2047,767 ).

However, not all display areas have the same resolution, and these display areas are not necessarily aligned with the bottom side. As shown in figure 1, the valid display area is a red, blue, and purple irregular area, while the yellow area is also part of the virtual desktop, however, it does not belong to any display area, which is also called an invalid area. Assume that the resolution of display 1 is 1024 × 768, that of display 2 is 800 × 600, and that of display 3 is 640 × 480. As shown in the position, the coordinates of display 1 are (0, 0) to (1023,767), and the coordinates of display 2 are (-800,168) to (-1,767 ), the coordinates of display 3 are (1663,479, 0) ). However, the invalid regions (-1,167) to (-1024,480) and (1663,767) to () cannot display any information, the system does not allow users to move their mouse over these two areas. Note that the invalid region is included in the virtual desktop, so the size of the virtual desktop in Figure 1 is from (-1663,767) ).

I used two monitors during programming and development. One was my notebook with a resolution of 1024 × 768 as the main monitor. The other was lazy, I directly found a small black and white display with a small nec12 inch screen, not to facilitate other operations. This NEC black and white screen supports a resolution of 800 × 600.

For example, if I directly set the extended desktop, both monitors can be used.

Pay attention to the differences between the primary and secondary displays. In fact, you can adjust the Primary and Secondary displays as needed.

(3) The system supports programming APIs

Microsoft provides some new API calls to support multi-monitor mode. Their functions are described as follows:

1. hmonitor monitorfrompoint (point PT, DWORD dwflags)

Monitorfrompoint returns a display handle containing a specific point (PT. If Pt does not belong to any monitor, the returned display handle is determined by the dwflags flag: NULL is returned for monitor_defaulttonull, and hmonitor handle representing the primary display is returned for monitor_defaulttoprimary, monitor_defaulttonearest returns the hmonitor handle of the display closest to the PT point. 2. hmonitor monitorfromrect (lpcrect
LPRC, DWORD dwflags)

Monitorfromrect returns the display handle containing the rectangle represented by LPRC; if more than one display area contains this rectangle, the display handle containing the largest part of the rectangle is returned; if the rectangle does not belong to any display area, the returned handle is determined by dwflags. The rule is the same as monitorfrompoint.

3. hmonitor monitorfromwindow (hwnd, DWORD dwflags)

Similar to monitorfromrect, the input is a handle hwnd representing the window rather than a pointer pointing to the rectangle.

4. bool getmonitorinfo (hmonitor, lpmonitorinfo lpmi)

Getmonitorinfo returns information about the display represented by hmonitor, which is stored in lpmi, a pointer to the monitorinfo structure. This information includes the size of the display area of the display in the rect structure (if the display is not the main display, the rect coordinates may be negative ), and the size of the display's work area in the rect structure. The work area is the remaining area in the display area except the system taskbar and the application shortcut bar, you can also determine whether the monitor is the primary monitor and return a flag.

5. bool enumdisplaymonitors (HDC, lpcrect lprcclip, monitorenumproc lpfnenum, lparam dwdata)

HDC is a handle that shows the device environment, and lprcclip is a pointer to a rectangular area. Intersection the rectangular area and the visible area in the device environment, and the obtained area may be distributed in the display area of multiple monitors, enumdisplaymonitors calls a monitorenumproc function once for each display area that contains an intersection. Dwdata is the data passed to the monitorenumproc function.

6. bool callback monitorenumproc (hmonitor, HDC hdcmonitor, LPRC lprcmonitor, DWORD dwdata)

Monitorenumproc is a callback function called by the enumdisplaymonitors function. Its content can be customized by users. Using these two functions, you can use different display features of each monitor when performing cross-display across multiple monitors.

Of course, not all plotting programs must call these two functions. In this case, assume that all displays use the same color resolution.

7. enumdisplaydevices (lpvoid lpreserved, int idevicenum, display_device × pdisplaydevice, DWORD dwflags)

Enumdisplaydevices lists information about a display device (with idevicenum as the serial number) in the system. Compared with getmonitorinfo, the display corresponding to getmonitorinfo must be part of the Windows virtual desktop, and enumdisplaydevices can list information of all the monitors installed on the system in standalone display mode. The returned information is stored in the display_device structure, including the display device name, description of the display device, and status of the display device.

In addition, some original API calls, such as systemparametersinfo and getsystemmetrics, also support the multi-monitor mode. For example, when getsystemmetrics is called, if sm_xvirtualscreen, sm_yvirtualscreen, sm_cxvirtualscreen, and sm_cyvirtualscreen are used, the coordinates in the upper left corner of the virtual desktop and the length and width of the whole desktop are obtained.

During programming, we should pay special attention to the changes in coordinates: first, the negative coordinates under a single monitor or Windows larger than sm_cxscreen and sm_cyscreen will be hidden, and these are legal in Multi-monitor mode. When determining the location of the application window and dialog box, select the correct display and the correct global coordinates (virtual desktop coordinates ). Finally, check the validity of these window coordinates Before restoring the originally stored windows.

These can be found on Microsoft's msdn. You need to take a closer look and try each API.

For details, refer to msnd's article "how to exploit multiple monitor support in Memphis and Windows NT 5.0.

 

(4) The component design for multi-screen programming references many materials on the Internet. I would like to express my gratitude to those selfless colleagues here, I just organized their results systematically ...... the component design process is as follows:

 

(1). initialize the program

Syntax: mscreeninfo ();

Description: A part constructor. It initializes the part, obtains the System screen information, and sets the part attributes.

 

 

 

(2). Get the width of the specified Screen

Syntax: Short getscreenwidth (short screenno );

Input: screenno -- specifies the serial number of the screen, 0 -- m_monitorNum-1;

Return: screen width in pixel;

Decription: gets the screen width specified by screenno.

 

 

 

(3). Get the height of the specified Screen

Syntax: Short getscreenheight (short screenno );

Input: screenno -- specifies the serial number of the screen, 0 -- m_monitorNum-1;

Return: screen height in pixel;

Decription: gets the screen height specified by screenno.

Program flowchart: Same as Figure 2, only the last step returns DM. dmpelsheight.

 

(4). Obtain the coordinate origin of the specified screen-left

Syntax: Short getscreenleft (short screenno );

Input: screenno -- specifies the serial number of the screen, 0 -- m_monitorNum-1;

Return: screen left in pixel;

Decription: gets the coordinate origin-left of the screen specified by screenno.

Program flowchart: Same as Figure 2, only the last step returns DM. dmposition. X.

 

(5). Obtain the coordinate origin of the specified screen-top

Syntax: Short getscreenleft (short screenno );

Input: screenno -- specifies the serial number of the screen, 0 -- m_monitorNum-1;

Return: screen top in pixel;

Decription: gets the coordinate origin-top of the screen specified by screenno.

Program flowchart: Same as Figure 2, only the last step returns DM. dmposition. Y.

 

(6). Obtain the home screen-primary screen

Syntax: Short getprimaryscreen ();

Input: NULL;

Return: primary screen no, 0 -- m_monitornum-1

Description: gets the serial number of the home screen.

Program process: Determine in sequence that the origin of the screen is (0, 0 ).

 

 

(5) Implementation of component development and main code 1 Development Environment Operating System: WindowsXP programming environment: VC 6.0 2 component interface:

 

3 main code

// Obtain the number of Displays

Cmscreeninfoctrl: cmscreeninfoctrl ()
{
Initializeiids (& iid_dmscreeninfo, & iid_dmscreeninfoevents );

// Find the total number of Displays
Int I;
Bool flag;
Display_device dd;

I = 0;
Flag = true;
Zeromemory (& DD, sizeof (dd ));
Dd. cb = sizeof (dd );
Do
{
Flag = enumdisplaydevices (null, I, & DD, 0 );
If (FLAG) I + = 1;
} While (FLAG );

M_monitornum = I; // total number
}

// Obtain the display area width

Short cmscreeninfoctrl: getscreenwidth (short screenno)
{
If (screenno <0 | screenno> = m_monitornum) return 0;

Bool flag;
Display_device dd;

Zeromemory (& DD, sizeof (dd ));
Dd. cb = sizeof (dd );
Flag = enumdisplaydevices (null, screenno, & DD, 0 );

If (! Flag) return 0;

Devmode DM;
Zeromemory (& DM, sizeof (DM ));
DM. dmsize = sizeof (DM );
Flag = enumdisplaysettings (char *) dd. devicename, enum_current_settings, & DM );

If (! Flag) return 0;

Return (short) DM. dmpelswidth;
}

// Set the display area width

Void cmscreeninfoctrl: setscreenwidth (short screenno, short nnewvalue)
{
Setmodifiedflag ();
}

// Obtain the display area width

Short cmscreeninfoctrl: getscreenheight (short screenno)
{
If (screenno <0 | screenno> = m_monitornum) return 0;

Bool flag;
Display_device dd;

Zeromemory (& DD, sizeof (dd ));
Dd. cb = sizeof (dd );
Flag = enumdisplaydevices (null, screenno, & DD, 0 );

If (! Flag) return 0;

Devmode DM;
Zeromemory (& DM, sizeof (DM ));
DM. dmsize = sizeof (DM );
Flag = enumdisplaysettings (char *) dd. devicename, enum_current_settings, & DM );

If (! Flag) return 0;

Return (short) DM. dmpelsheight;
}

// Set the display area height

Void cmscreeninfoctrl: setscreenheight (short screenno, short nnewvalue)
{
Setmodifiedflag ();
}

// Obtain the Y coordinate of the display area

Short cmscreeninfoctrl: getscreentop (short screenno)
{
If (screenno <0 | screenno> = m_monitornum) Return-1;

Bool flag;
Display_device dd;

Zeromemory (& DD, sizeof (dd ));
Dd. cb = sizeof (dd );
Flag = enumdisplaydevices (null, screenno, & DD, 0 );

If (! Flag) Return-1;

Devmode DM;
Zeromemory (& DM, sizeof (DM ));
DM. dmsize = sizeof (DM );
Flag = enumdisplaysettings (char *) dd. devicename, enum_current_settings, & DM );

If (! Flag) Return-1;

Return (short) DM. dmposition. Y;
}

// Set the Y coordinate of the display area

Void cmscreeninfoctrl: setscreentop (short screenno, short nnewvalue)
{
Setmodifiedflag ();
}

// Obtain the X coordinate of the display area

Short cmscreeninfoctrl: getscreenleft (short screenno)
{
If (screenno <0 | screenno> = m_monitornum) Return-1;

Bool flag;
Display_device dd;

Zeromemory (& DD, sizeof (dd ));
Dd. cb = sizeof (dd );
Flag = enumdisplaydevices (null, screenno, & DD, 0 );

If (! Flag) Return-1;

Devmode DM;
Zeromemory (& DM, sizeof (DM ));
DM. dmsize = sizeof (DM );
Flag = enumdisplaysettings (char *) dd. devicename, enum_current_settings, & DM );

If (! Flag) Return-1;

Return (short) DM. dmposition. X;
}

// Set the X coordinate of the display area

Void cmscreeninfoctrl: setscreenleft (short screenno, short nnewvalue)
{
Setmodifiedflag ();
}

// Obtain the primary display area

Short cmscreeninfoctrl: getprimaryscreen ()
{
// Todo: add your property handler here
If (m_monitornum <= 1) return 0;

// If the screen Top = 0 and left = 0, then, it's the primary screen
Short I;
For (I = 0; I <m_monitornum; I ++)
{
If (getscreentop (I) = 0 & getscreenleft (I) = 0) return I;
}
Return 0;
}

// Set the primary display area

Void cmscreeninfoctrl: setprimaryscreen (short nnewvalue)
{
Setmodifiedflag ();
}

This is basically the key code.

(3) component release

Directly compiled into the OCX component named mutlscreen. ocx

You can use regsvr32.exe for registration.

(6) application of the split-screen output component we use the simplest VB to compile a small program to implement 1. Create a VB project, reference the component, and create two forms: frmctl, and frmoutscreen, We output the frmoutscreen to the second screen. 2 The code used by the component is as follows: function initmotion () numscreen = frmctl. mscreeninfo1.monitornum
Primaryscreen = frmctl. mscreeninfo1.primaryscreen

Wscreen1 = frmctl. mscreeninfo1.screenwidth (0)
Hscreen1 = frmctl. mscreeninfo1.screenheight (0)
Topscreen1 = frmctl. mscreeninfo1.screentop (0)
Leftscreen1 = frmctl. mscreeninfo1.screenleft (0)

Wscreen2 = frmctl. mscreeninfo1.screenwidth (1)
Hscreen2 = frmctl. mscreeninfo1.screenheight (1)
Topscreen2 = frmctl. mscreeninfo1.screentop (1)
Leftscreen2 = frmctl. mscreeninfo1.screenleft (1)

End function 3 frmoutscreen code private sub form_load () frmoutscreen. Left = leftscreen2 * 15 + 1
Frmoutscreen. Top = 8frmoutscreen. windowstate = 2
Frmoutscreen. windowsmediaplayer1.left = 0
Frmoutscreen. windowsmediaplayer1.top = 0
Frmoutscreen. windowsmediaplayer1.width = frmmediaplay. Width
Frmoutscreen. windowsmediaplayer1.height = frmmediaplay. Height
Frmoutscreen. refreshend sub 4 can be compiled and run to achieve the output of frmoutscreen on the second monitor. You can add your Web component to implement the browser's output on the second screen. See my execution results below.

Well, that's all. To implement more complex functions, You Need To debug it yourself a little bit.

Http://blog.sina.com.cn/u/4078ccd60100049a

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.