http://download.csdn.net/detail/finerpfw/9260539
一、多屏显示器的获取
1. 先将模板示例程序文件夹中的User32.Lib文件拷贝至程序文件夹中
2. 在用于检测显示器名称的.cpp中添加如下头文件
3. 添加检测显示器代码:
void CSHView::OnButton2()
{
// TODO: Add your control notification handlercode here
//获得显示屏的名称
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 ++;
} while (flag);
}
通过调试时查看dd.DeviceName中的显示器名称。一般看到的显示器名称为
“\\.\DISPLAY1”第二个显示名称为“\\.\DISPLAY2”。
但对应到程序中设置的名称时String cstrDeviceName=“\\\\.\\DISPLAY1”。
VC程序中“\”需用“\\”表示。
4. 双屏显示代码
voidCSHView::OnButton1()
{
// TODO: Add your control notification handlercode here
CString cstrDeviceName="\\\\.\\DISPLAY2"; //显示器名称“\\\\.\\DISPLAY1”由OnButton2()中的DISPLAY_DEVICEdd得到,调试时查看dd.DeviceName的显示器名称
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
devMode.dmDriverExtra = sizeof(DEVMODE);
int nRet = EnumDisplaySettings(cstrDeviceName,ENUM_CURRENT_SETTINGS,&devMode);
if(nRet)
{
int x, y, cx, cy;
x = devMode.dmPosition.x;
y = devMode.dmPosition.y;
cx = devMode.dmPelsWidth;
cy = devMode.dmPelsHeight;
g_pDlgShow=new CDialog1;
g_pDlgShow->Create(IDD_DIALOG1);
g_pDlgShow->ShowWindow(SW_SHOW);
g_pDlgShow->SetWindowPos(&wndTop,x, y, cx, cy, SWP_SHOWWINDOW);
g_pDlgShow->ShowWindow(SW_SHOWMAXIMIZED);
}
}
5. 实际显示器号,跟电脑设置有关
如图:说明主显示屏的编号为:"\\\\.\\DISPLAY2"。
副显示屏的编号为:"\\\\.\\DISPLAY1"。
本文下载 地址 :http://download.csdn.net/download/finerpfw/9260539
上面文章错误纠正:http://cauchy.blog.163.com/blog/static/175272539201251991510720/
二、VC多屏幕显示
由于工程需要在多个显示器上显示不同类容,故查找了一些资料来满足这个功能。在VC中分为三步来操作:检测显示器个数;读取屏幕分辨率和其他参数;设置程序的显示坐标。
第一步:检测屏幕个数
网上查找到的通用方法有两个:EnumDisplayDevicess和GetSystemMetrics,下面分别介绍一下:
A。EnumDisplayDevices(百度百科连接:http://baike.baidu.com/view/1080527.htm?fr=ala0_1,MSDN连接:http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx)
函数功能:该函数可得到系统中显示设备的信息。
函数原型:BOOL EnumDisplayDevices(PVOID Unused, DWORD iDevNum, PDISPLAY_DEVICE lpDisplayDevice,
DWORD dwFlags);
其中第一个参数和最后一个参数现在都还没用到,主要是第二个参数和第三个,这里简要介绍一下
iDevNum:指定感兴趣的显示设备的索引值,操作系统通过索引值确定每一个显示设备。索引值是连续的整数。从0开始,例如:如果一个系统有三个显示设备,那么它们的索引值为0、1、2。
lpdisplayDevice:DISPLAY_DEVICE结构的指针,该结构检索由iDevNum指定的显示设备的信息,在调用EnumDisplayDevices之前,必须以字节为单位把DISPLAY_DEVICE结构中cb元素初始化为DISPLAY_DEVICE结构的大小。
示例代码:
INT iNumber=0;
BOOL bFlag=TRUE;
DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
DEVMODE devMode;
ZeroMemory(&devMode,sizeof(devMode));
devMode.dmSize=sizeof(devMode);
do
{
bFlag = EnumDisplayDevices(NULL, iNumber, &dd, 0);
bFlag=bFlag&&EnumDisplaySettings(dd.DeviceName,ENUM_CURRENT_SETTINGS,&devMode);
if (bFlag)
iNumber += 1;
} while (bFlag);
其中iNumber中就为系统所带显示器的数量,网上很多地方都没有红色这一行,这样检测的结果并不准确,我用的笔记本不管是不是有外接显示器,检测出的数字始终为5,查看了这篇日志(http://hi.baidu.com/lin65505578/item/ffa9c32598b14fc3a5275add)后添加了红色语句后,运行结果就正常了。猜想EnumDisplayDevices只是检测系统中存在的显示设备,并不一定是当前一定在用的设备。添加设置语句后,就可以检测到正在使用的设备了。
B.int WINAPI GetSystemMetrics( __in int nIndex)
(MSDN连接:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v=vs.85).aspx)
用于得到被定义的系统数据或者系统配置信息,百度百科上的资料较老,不全面。
只要设置nIndex为SM_CMONITORS即可,MSDN的解释为:The number of display monitors on a desktop.
示例代码:
INT iNumber=GetSystemMetrics(SM_CMONITORS);
CString csNum;
csNum.Format(_T("%d"),iNumber);
MessageBox(csNum,_T("显示器数量"),MB_OK);
相比A中的设置,这个简单多了,推荐使用此函数。
第二步,读取显示器参数及其他参数
该过程使用前面的两个API函数:EnumDisplayDevices和EnumDisplaySettings。
//初始化
BOOL bFlag;
DISPLAY_DEVICE dd;
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
DEVMODE devMode;
ZeroMemory(&devMode,sizeof(devMode));
devMode.dmSize=sizeof(devMode);
bFlag=EnumDisplayDevices(BULL,iNumber,&dd,0);
if(bFlag)
return FLASE;
bFlag=EnumDisplayDevices(dd.DeviceName,ENUM_CURRENT_SETTINGS,&devMode);
iNumber为要查询的显示器编号,从0开始,主屏为0,然后1,2,3....一直下去。查询为EnumDisplaySettings(),查询的数据存储在devMode中,常用的为dmPosition(为当前显示器的坐标位置),dmPelsWidth,dmPelsHeight(为当前显示器的分辨率),其余根据自己需要参见MSDN(http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx).
第三步:设置当前程序的显示位置
在前两步的基础上,根据自己的需要来设置当前程序的显示坐标(ps:如果对系统虚拟坐标不了解的可以去查看一下相关资料)
示例代码:
CRect reTemp;
reTemp.BottomRight()=CPoint(devMode.dmPelsWidth+devMode.dmPosition.x,devMode.dmPelsHeight);
reTemp.TopLeft()=CPoint(devMode.dmPosition.x,devMode.dmPosition.y);
MoveWindow(&reTemp);
这段代码添加在MFC程序中的OnInitDialog()中,这样程序一开始运行就可以在你想要显示的屏幕中运行.
三、其他封装多屏显示控制调用:
http://squallblog.blog.163.com/blog/static/1750938952012115112524980/
VC实现多屏显示(原创)
直接贴源码吧,vc2008调试通过。只贴多屏显示相关操作类。
h文件如下:
/**********************************************
Copyright(c) 欧博科技软件部
文件名称:SquallMultiScreen.h
文件描述:多屏显示操作类
当前版本:1.0 v
作 者:Squall(朱一)
完成日期:2012-12-4
说明:
1、此类只适用于单卡双屏的控制(目前绝大多数A卡、N卡都是双屏显卡);
2、双屏显卡包括一个主屏,一个副屏;可配置不同分辨率,可配置不同的位置关系;
3、该类通过推算虚拟屏与主屏的位置关系,查找出副屏的坐标;
***********************************************/
#pragma once
class CSquallMultiScreen
{
private:
CRect m_MainScreen; //主屏
CRect m_VirtualScreen; //虚拟屏(主屏和副屏的外接矩形)
public:
CSquallMultiScreen(void);
~CSquallMultiScreen(void);
longGetScreenCount(); //获取屏幕数量
CRectGetVirtualScreenRect(void); //返回虚拟屏尺寸
CRect GetMainScreenRect(void); //返回主屏尺寸
CRect GetSecondaryScreenRect(void); //返回副屏尺寸
//显示窗体(将窗体移动至主屏或副屏的某个位置)
void DisplayWindow( HWND hWnd, int x, int y, BOOL IsMainScreen = TRUE);
};
cpp文件如下:
#include"StdAfx.h"
#include "SquallMultiScreen.h"
CSquallMultiScreen::CSquallMultiScreen(void)
{
m_MainScreen.left = 0;
m_MainScreen.top = 0;
m_MainScreen.right = ::GetSystemMetrics(SM_CXSCREEN);
m_MainScreen.bottom = ::GetSystemMetrics(SM_CYSCREEN);
m_VirtualScreen.left= ::GetSystemMetrics(SM_XVIRTUALSCREEN);
m_VirtualScreen.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
m_VirtualScreen.right = m_VirtualScreen.left +::GetSystemMetrics(SM_CXVIRTUALSCREEN);
m_VirtualScreen.bottom = m_VirtualScreen.top +::GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
CSquallMultiScreen::~CSquallMultiScreen()
{
}
longCSquallMultiScreen::GetScreenCount()
{
return ::GetSystemMetrics(SM_CMONITORS);
}
CRectCSquallMultiScreen::GetVirtualScreenRect(void)
{
return m_VirtualScreen;
}
CRectCSquallMultiScreen::GetMainScreenRect(void)
{
return m_MainScreen;
}
CRectCSquallMultiScreen::GetSecondaryScreenRect(void)
{
if ( GetScreenCount() > 1 )
{
//用MainScreen和VirtualScreen的矩形中心点坐标来比较。判断8个方位的关系。
CPoint mc =m_MainScreen.CenterPoint(); //MainCenter
CPoint vc = m_VirtualScreen.CenterPoint(); //VirtualCenter
CPoint TestPoint;
ASSERT(!(vc.x == mc.x && vc.y == mc.y) );
if ( vc.x ==mc.x && vc.y < mc.y ) //正上
{
TestPoint.SetPoint( vc.x, m_VirtualScreen.top );
}
if ( vc.x> mc.x && vc.y < mc.y ) //右上
{
TestPoint.SetPoint( m_VirtualScreen.right,m_VirtualScreen.top );
}
if ( vc.x> mc.x && vc.y == mc.y ) //正右
{
TestPoint.SetPoint( m_VirtualScreen.right, vc.y );
}
if ( vc.x> mc.x && vc.y > mc.y ) //右下
{
TestPoint.SetPoint( m_VirtualScreen.right,m_VirtualScreen.bottom );
}
if ( vc.x ==mc.x && vc.y > mc.y ) //正下
{
TestPoint.SetPoint( vc.x, m_VirtualScreen.bottom );
}
if ( vc.x< mc.x && vc.y > mc.y ) //左下
{
TestPoint.SetPoint( m_VirtualScreen.left,m_VirtualScreen.bottom );
}
if ( vc.x< mc.x && vc.y == mc.y ) //正左
{
TestPoint.SetPoint( m_VirtualScreen.left, vc.y );
}
if ( vc.x< mc.x && vc.y < mc.y ) //左上
{
TestPoint.SetPoint( m_VirtualScreen.left, m_VirtualScreen.top);
}
MONITORINFO mi;
memset( &mi, 0, sizeof(MONITORINFO) );
mi.cbSize = sizeof(MONITORINFO);
HMONITORhScreen = MonitorFromPoint( TestPoint, MONITOR_DEFAULTTONEAREST );
GetMonitorInfo( hScreen, &mi );
ASSERT( mi.dwFlags == 0 );
returnCRect( mi.rcMonitor );
}
else
{
return CRect(0,0,0,0);
}
}
voidCSquallMultiScreen::DisplayWindow( HWND hWnd, int x, int y, BOOL IsMainScreen )
{
ASSERT( hWnd );
long nLeft =0,nTop = 0;
if ( IsMainScreen)
{
nLeft = x;
nTop = y;
}
else
{
if ( GetScreenCount() > 1 )
{
CRect SecRect = GetSecondaryScreenRect();
nLeft= SecRect.left + x;
nTop = SecRect.top + y;
}
else
{
nLeft = x;
nTop = y;
}
}
::SetWindowPos(hWnd, NULL, nLeft, nTop, NULL, NULL, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER);
}
以上是实现类。具体的使用非常简单,如果显示模态对话框,在对话框初始化函数中进行位置调整;如果显示非模态对话框,在Create函数后调整位置。