XP系统下设置双显的过程
电脑:AUSUS K50I
显卡为NVIDIA N1-0P-GE
在桌面上右击,选属性。在弹出窗口中找到设置选项卡,会看到有两个显示器编号。点选2号显示器。在下面找到两个选项,先选择下面的扩展桌面到此监视器,然后再选上面的设置此显示器为主显示器。点下面的应用按钮,然后选1号显示器,把下面两个选项中的扩展桌面到此监视器这个选项取消选择,就可以了。
2、一些应用程序在双显时的特性
(1) PPT
把PPT拖到副显,此时按F5放映PPT。却是在主显示PPT全屏放映,而副显还是显示编辑状态的PPT。
(2) RDP
RDP7不支持双显。Win7 下的RDP才支持双显。
(3) 按Ptr Sc键,把桌面的屏幕保存到mspaint中,此时看到是两个屏幕的和。
长*宽是否2646*768 ,这个大小就是双显的大小
可以看到2646是主显的分辩率的宽+副显的分辨率的宽。(1280+1366)
Introduction
This has been an ongoing topic for a while and I keep on getting question(s) on how can we launch Windows or in our case application(s) in different screens. In the place that I currently work, City of Dreams, we have many different types of adapters for many A/V systems and the applications like Lucky Draw, Slot Results, etc. have to be automatically launched on the correct AV to have effects like Animation(s) on one type, random numbers on other, etc.
Launcher
Launched
The AllScreens
This is all it takes to get the information of all the screens currently hosted in the systemSystem.Windows.Forms.Screen
.
So to populate our dropdown; loop through the:
Screen[] scr = Screen.AllScreens
this.cmbDevices.Items.Clear();
foreach (System.Windows.Forms.Screen s in scr)
{
strDeviceName = s.DeviceName.Replace("\\\\.\\", "");
this.cmbDevices.Items.Add(strDeviceName);
// you can check the device is primary or not this way
if (s.Primary) this.cmbDevices.Items.Add(">" + strDeviceName);
else this.cmbDevices.Items.Add(strDeviceName);
}
this.cmbDevices.SelectedIndex = 0;
Launch
There are only two properties that have to be set correctly in order to ensure it is properly launched into the correct display. Form.StartPosition
& Form.Location
.
Screen[] scr = Screen.AllScreens
Form oForm = new Form()
oForm.Left = scr[0].Bounds.Width;
oForm.Top = scr[0].Bounds.Height;
oForm.StartPosition = FormStartPosition.Manual;
oForm.Location = scr[0].Bounds.Location;
oForm.Show();
Putting It All Together
Here we go, this is all it takes to launch your forms into user selected display.
public partial class frmMain : Form
{
Form[] aryForms = new Form[5]; // Allow 5 total forms.
int currentPointer = 0; //
Screen[] scr = Screen.AllScreens;
public frmMain()
{
InitializeComponent();
LoadScreen();
}
private void LoadScreen()
{
String strDeviceName = String.Empty;
this.cmbDevices.Items.Clear();
foreach (Screen s in scr)
{
strDeviceName = s.DeviceName.Replace("\\\\.\\", "");
this.cmbDevices.Items.Add(strDeviceName);
/* Enable this section, if you want to point to
user this is the default screen.
if (s.Primary) this.cmbDevices.Items.Add(">" + strDeviceName);
else this.cmbDevices.Items.Add(strDeviceName);
*/
}
this.cmbDevices.SelectedIndex = 0;
}
private void btnLaunchIn_Click(object sender, EventArgs e)
{
int intLaunchScreen = getScreenNumber(this.cmbDevices.SelectedItem.ToString());
if (currentPointer <= 4)
{
aryForms[currentPointer] = new frmLaunchedWindow();
aryForms[currentPointer].Text =
aryForms[currentPointer].Text + currentPointer;
aryForms[currentPointer].Left = scr[intLaunchScreen].Bounds.Width;
aryForms[currentPointer].Top = scr[intLaunchScreen].Bounds.Height;
aryForms[currentPointer].StartPosition = FormStartPosition.Manual;
aryForms[currentPointer].Location = scr[intLaunchScreen].Bounds.Location;
//Point p = new Point(scr[0].Bounds.Location.X, scr[0].Bounds.Location.Y);
//aryForms[currentPointer].Location = p;
aryForms[currentPointer].Show();
currentPointer += 1;
}
}
private int getScreenNumber(String DeviceID)
{
int i = 0;
foreach (Screen s in scr)
{
if (s.DeviceName == "\\\\.\\"+DeviceID) return i;
i += 1;
}
// if cannot find the device reset to the default 0
return 0;
}
}
二、Windows下的多显介绍
Positioning Objects on a Multiple Display Setup
The following sample code demonstrates how applications can correctly position objects on multiple displays. Note, do not assume that the RECT is based on the origin (0,0).
#include <windows.h>
#include "multimon.h"
#define MONITOR_CENTER 0x0001 // center rect to monitor
#define MONITOR_CLIP 0x0000 // clip rect to monitor
#define MONITOR_WORKAREA 0x0002 // use monitor work area
#define MONITOR_AREA 0x0000 // use monitor entire area
//
// ClipOrCenterRectToMonitor
//
// The most common problem apps have when running on a
// multimonitor system is that they "clip" or "pin" windows
// based on the SM_CXSCREEN and SM_CYSCREEN system metrics.
// Because of app compatibility reasons these system metrics
// return the size of the primary monitor.
//
// This shows how you use the multi-monitor functions
// to do the same thing.
//
void ClipOrCenterRectToMonitor(LPRECT prc, UINT flags)
{
HMONITOR hMonitor;
MONITORINFO mi;
RECT rc;
int w = prc->right - prc->left;
int h = prc->bottom - prc->top;
//
// get the nearest monitor to the passed rect.
//
hMonitor = MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST);
//
// get the work area or entire monitor rect.
//
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
if (flags & MONITOR_WORKAREA)
rc = mi.rcWork;
else
rc = mi.rcMonitor;
//
// center or clip the passed rect to the monitor rect
//
if (flags & MONITOR_CENTER)
{
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;
}
else
{
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;
}
}
void ClipOrCenterWindowToMonitor(HWND hwnd, UINT flags)
{
RECT rc;
GetWindowRect(hwnd, &rc);
ClipOrCenterRectToMonitor(&rc, flags);
SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
三、RepositioningWindows on Multiple Monitor Systems
参考代码:
http://download.youkuaiyun.com/detail/chenyujing1234/5218722
Introduction
On systems with more than one display, you can get into trouble because of compatibility issues for functions like:
SystemParametersInfo( SPI_GETWORKAREA, 0, &rc, 0 );//only primary Monitor
Here is a possible setup for two displays: the left (1) is the standard monitor, and the right (2) is the extension monitor, for instance, for less needed information like help, e-mail, or browsing.

Background
Last week, I got a problem of restoring a windowon a computer which had multiple monitors. I looked for some samples, but found no good ones, so I wrote some code to solve the issue. And, I want to demonstrate my new knowledge and publish it here.
But there are other setups possible; it might look strange, for instance, to have the right monitor as the primary one.This means that the coordinates of the left monitor have negative values.
The taskbar
The taskbar also needs some space, so it is better that this area wont be used to show windows. The taskbar can have different positions. This is illustrated from the standard position (1) up to three different positions (2)-(4).

Using the code
I packed all the interesting code in a designed class to concentrate(浓缩)it and for ease of use. Because of
#define COMPILE_MULTIMON_STUBS
, you got to pay some attention on how to use the class. If you find a better way, let me know it.
Now I have coded a global object, so you don't need an extra object, and the object is available if you include the files in your project.
//Fetch informations
int cnt ) gMonitor.GetCount();
int iMonitor = gMonitor.GetPrimary();
//test for repositioning
CRect rc;
GetWindowRect( rc );
iMonitor = gMonitor.GetNearestDisplay( rc ); //also overloaded for point
if( !gMonitor.EnsureInMonitor( rc, iMonitor ) )
MoveWindow( rc );
Points of interest
This code can help you for a better user experience with multiple monitor systems, because a window will be moved if it doesn't fit on one physical screen.
It gets real tricky. When the primary display is the right one (or the upper?), then the left (top) has negative values and sizing needs some extra lines of code.
Also, watch out for the taskbar area, which is another pitfall.
多 显 示 器 A P I 函 数
(四)实现多屏幕编程的组件设计 这个组件参考了网上的许多资料,这里先向那些无私的同行表示感谢,我做的工作只是将他们的成果进行了系统化的整理......
组件的设计流程如下:
(1).初始化程序 Syntax:: MScreenInfo();
Description : 部件构造函数,初始化部件,获取系统屏幕信息,设置部件属性。
(2). 获取指定屏幕的宽度
Syntax: Short GetScreenWidth( Short ScreenNo) ;
Input : ScreenNo -- 指定屏幕的序号,0 -- m_monitorNum-1; Return: Screen Width in Pixel;
Decription: 获取ScreenNo指定屏幕的宽度。
(3). 获取指定屏幕的高度
Syntax: Short GetScreenHeight( Short ScreenNo) ;
Input : ScreenNo -- 指定屏幕的序号,0 -- m_monitorNum-1; Return: Screen Height in Pixel;
Decription: 获取ScreenNo指定屏幕的高度。 程序流程图:
与图2相同,只是最后一步返回dm.dmPelsHeight.
(4). 获取指定屏幕的坐标原点-left Syntax: Short GetScreenLeft( Short ScreenNo) ;
Input : ScreenNo -- 指定屏幕的序号,0 -- m_monitorNum-1; Return: Screen Left in Pixel;
Decription: 获取ScreenNo指定屏幕的坐标原点-left。 程序流程图:与图2相同,只是最后一步返回dm.dmPosition.x.
(5). 获取指定屏幕的坐标原点-top Syntax: Short GetScreenLeft( Short ScreenNo) ;
Input : ScreenNo -- 指定屏幕的序号,0 -- m_monitorNum-1; Return: Screen Top in Pixel;
Decription: 获取ScreenNo指定屏幕的坐标原点-top。 程序流程图:与图2相同,只是最后一步返回dm.dmPosition.y.
(6). 获取主屏幕--Primary Screen
Syntax: Short GetPrimaryScreen();
Input: Null;
Return: Primary Screen No, 0 -- m_monitorNum - 1
Description: 获取主屏幕的序号。 程序流程:依次判断那一个屏幕的原点是(0, 0).
(五)组件开发的实现和主要代码
1 开发环境 操作系统: WindowsXP
编程环境: VC 6.0
2 组件接口如下
3 主要代码
// 获得显示器的数量
CMScreenInfoCtrl::CMScreenInfoCtrl()
{
InitializeIIDs(&IID_DMScreenInfo, &IID_DMScreenInfoEvents);
// 找出显示器的总数量
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;
// 总数量
}
// 获得显示区宽度
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;
}
// 设置显示区宽度
void CMScreenInfoCtrl::SetScreenWidth(short ScreenNo, short nNewValue)
{
SetModifiedFlag();
}
// 获得显示区宽度
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;
}
// 设置显示区高度
void CMScreenInfoCtrl::SetScreenHeight(short ScreenNo, short nNewValue)
{
SetModifiedFlag();
}
// 获得显示区Y坐标
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 ;
}
// 设置显示区Y坐标
void CMScreenInfoCtrl::SetScreenTop(short ScreenNo, short nNewValue)
{
SetModifiedFlag();
}
// 获得显示区X坐标
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 ;
}
// 设置显示区X坐标
void CMScreenInfoCtrl::SetScreenLeft(short ScreenNo, short nNewValue)
{
SetModifiedFlag();
}
// 获得主显示区
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;
}
// 设置主显示区
void CMScreenInfoCtrl::SetPrimaryScreen(short nNewValue)
{
SetModifiedFlag();
}