Win32程序多显示器情况下显示窗口

近来在做多显示器下显示窗口到特定显示器上,并且有F11切换全屏和非全屏的功能。现总结如下:


1、先来看如何解决多显示器显示特定窗口的问题。

我们分如下几步走:

第一步,创建一个win32窗口。创建一个窗口是有套路可循的,我将代码贴出来,并加以注释了。

第二步,找出所有的显示器,然后将窗口显示在特定的显示器上。

	HINSTANCE _hInst;					// 当前实例
	TCHAR* szTitle;					// 标题栏文本
	TCHAR* szWindowClass;			// 主窗口类名

	//生成的窗口句柄
	HWND _hWnd;

	UINT width;

	UINT height;

	int startx;

	int starty;

	vector<ALLMONITORINFO> mInfo;

	BOOL Create(WNDPROC proc)
	{
		//如果已经创建了一个窗口那么不再重复创建
		if (_hWnd != NULL)
			return FALSE;

		//返回模块的句柄
		_hInst = GetModuleHandle(NULL);

		/*--------------注册一个窗口类------------------------*/
		WNDCLASSEX wcex;
		memset(&wcex, 0, sizeof(wcex));

		wcex.cbSize = sizeof(WNDCLASSEX);
		wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;

		//设置其回调函数
		if (proc != NULL)
			wcex.lpfnWndProc = proc;
		else
			wcex.lpfnWndProc = this->MyWndProc;
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = _hInst;

		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
		//wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_WIN01);//不要菜单栏
		wcex.lpszClassName = szWindowClass;//主窗口类名
		//注册窗口类,这个是必须的,要不然下面的CreateWindow函数总返回NULL
		ATOM atom = RegisterClassEx(&wcex);
		/*-----------------------------------------------*/


		/*--------------获取所有显示器信息------------------------*/
		mInfo.clear();
		//get number of monitors
		mInfo.reserve(GetSystemMetrics(SM_CMONITORS));
		//这个函数很重要,然后回调函数MonitorEnumProc是获取所有显示器信息的重要函数。
		EnumDisplayMonitors(NULL, NULL, this->MonitorEnumProc, reinterpret_cast<LPARAM>(&mInfo));

		//如果只有一个显示器的话,那就在这唯一的显示器上显示窗口
		if (mInfo.size() == 1)
		{
			RECT rect = mInfo[0].rect;
			width = rect.right - rect.left;
			height = rect.bottom - rect.top;
			startx = rect.left;
			starty = rect.top;
		}
		for (int i = 0; i < mInfo.size(); i++)
		{
			//如果有多个显示器的话,就在第一个非主屏的显示器上显示。
			if (!mInfo[i].isPrimary)
			{
				RECT rect = mInfo[0].rect;
				width = rect.right - rect.left;
				height = rect.bottom - rect.top;
				startx = rect.left;
				starty = rect.top;
				break;
			}
		}
		/*-----------------------------------------------*/


		_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
			startx,starty, width, height, NULL, NULL, _hInst, NULL);

		if (!_hWnd)
		{
			return FALSE;
		}
		//ToggleFullScreen();

		ShowWindow(_hWnd,  SW_SHOW);
		UpdateWindow(_hWnd);
	
		return TRUE;
	}

关于ALLMONITORINFO结构体定义,如下:

struct ALLMONITORINFO
{
	HMONITOR hMonitor;
	RECT     rect;
	bool     isPrimary;
};


回调函数MonitorEnumProc的定义如下:

BOOL CALLBACK MonitorEnumProc(__in  HMONITOR hMonitor, __in  HDC hdcMonitor, __in  LPRECT lprcMonitor, __in  LPARAM dwData)
	{
		vector<ALLMONITORINFO>& infoArray = *reinterpret_cast<vector<ALLMONITORINFO>* >(dwData);

		ALLMONITORINFO monitorInfo;
		monitorInfo.hMonitor = hMonitor;
		monitorInfo.rect = *lprcMonitor;

		HMONITOR priMonitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
		if (priMonitor == hMonitor)
			monitorInfo.isPrimary = true;
		else
			monitorInfo.isPrimary = false;
		
		infoArray.push_back(monitorInfo);
		return TRUE;
	}

2、然后是全屏和非全屏切换的问题。

在网上搜索的时候,给出的答案很多是说用ChangeDisplaySettings这个函数。但是经测试,这个函数不起作用。好象是微软已经摒弃了这个方法了,在新的系统上已经不起作用了,取而代之的是SetWindowLong这个函数。

代码如下所示:

	void ToggleFullScreen(int width, int height, int startx, int starty)
	{
		if(isFullScreen)
		{

			SetWindowLong(_hWnd, GWL_STYLE, GetWindowLong(_hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW);

			//GWL_EXSTYLE  extended style扩展格式。WS_EX_WINDOWEDGE  使得窗口显示,并不覆盖下面的任务栏。
			SetWindowLong(_hWnd, GWL_EXSTYLE, GetWindowLong(_hWnd, GWL_EXSTYLE) | WS_EX_WINDOWEDGE);

			//SetWindowPos(_hWnd, NULL, startx, starty, width, height, SWP_SHOWWINDOW);// SWP_FRAMECHANGED);
		}
		else
		{
			LONG curWinStyle = GetWindowLong(_hWnd, GWL_STYLE);
			curWinStyle = curWinStyle & ~WS_OVERLAPPEDWINDOW;
			SetWindowLong(_hWnd, GWL_STYLE, curWinStyle | WS_POPUP);
			MoveWindow(_hWnd, startx, starty, width, height, TRUE);
		}
		isFullScreen = !isFullScreen;
	}



  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值