基于WINDOWS 32API封装的显示器类: (2) 源文件
来源:互联网 发布:精准医学 大数据 编辑:程序博客网 时间:2024/06/08 19:27
1#include "stdafx.h"
2#include "monitor.h"
3#include <stack>
4#include <cassert>
5using namespace std;
6
7/***************************************************************************************
8 2009-12-5 当显示器不存在时,要删除窗口记录信息
9 2009-12-8 改为使用相对于父窗口的位置来恢复子窗口,这样当父窗口位置和大小变化时,
10 子窗口都能正确恢复
11****************************************************************************************/
12
13//CMonitor实现
14CMonitor::CMonitor(HMONITOR hMonitor, DWORD dwIndex):
15m_hMonitor(hMonitor),
16m_dwIndex(dwIndex)
17{
18 MONITORINFOEX mi;
19 mi.cbSize = sizeof( mi );
20 ::GetMonitorInfo( m_hMonitor, &mi );
21 m_strName = mi.szDevice;
22}
23
24//获取显示器的整个区域
25void CMonitor::GetMonitorRect(RECT& rect) const
26{
27 MONITORINFO mi;
28 RECT rc;
29 mi.cbSize = sizeof( mi );
30 ::GetMonitorInfo( m_hMonitor, &mi );
31 rc = mi.rcMonitor;
32
33 ::SetRect(&rect, rc.left, rc.top, rc.right, rc.bottom );
34}
35//获取显示器的工作区域
36void CMonitor::GetWorkAreaRect(RECT& rect) const
37{
38 MONITORINFO mi;
39 RECT rc;
40 mi.cbSize = sizeof( mi );
41 ::GetMonitorInfo( m_hMonitor, &mi );
42 rc = mi.rcWork;
43
44 ::SetRect(&rect, rc.left, rc.top, rc.right, rc.bottom );
45}
46//获取显示器的像素高度
47DWORD CMonitor::GetPixelHeight() const
48{
49 DEVMODE devmode;
50 devmode.dmSize = sizeof(DEVMODE);
51 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
52 return devmode.dmPelsHeight;
53}
54//获取显示器的像素宽度
55DWORD CMonitor::GetPixelWidth() const
56{
57 DEVMODE devmode;
58 devmode.dmSize = sizeof(DEVMODE);
59 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
60 return devmode.dmPelsWidth;
61}
62//获取显示器每单位像素的位数
63DWORD CMonitor::GetBitsPerPixel() const
64{
65 DEVMODE devmode;
66 devmode.dmSize = sizeof(DEVMODE);
67 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
68 return devmode.dmBitsPerPel;
69}
70//获取显示器的显示频率
71DWORD CMonitor::GetDisplayFrequency() const
72{
73 DEVMODE devmode;
74 devmode.dmSize = sizeof(DEVMODE);
75 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
76 return devmode.dmDisplayFrequency;
77}
78//获取显示器的左上角X位置
79DWORD CMonitor::GetMonitorLeft() const
80{
81 DEVMODE devmode;
82 devmode.dmSize = sizeof(DEVMODE);
83 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
84 return devmode.dmPosition.x;
85}
86//获取显示器的左上角Y位置
87DWORD CMonitor::GetMonitorTop() const
88{
89 DEVMODE devmode;
90 devmode.dmSize = sizeof(DEVMODE);
91 EnumDisplaySettings(m_strName.c_str(), ENUM_CURRENT_SETTINGS, &devmode);
92 return devmode.dmPosition.y;
93}
94//是否是主显示器
95bool CMonitor::IsPrimaryMonitor() const
96{
97 MONITORINFO mi;
98 mi.cbSize = sizeof( mi );
99 ::GetMonitorInfo( m_hMonitor, &mi );
100 return mi.dwFlags == MONITORINFOF_PRIMARY;
101}
102
103//获取某矩形相对于显示器居中后的区域
104void CMonitor::CenterRectToMonitor( LPRECT lprc, bool bWorkArea /*=false*/) const
105{
106 int w = lprc->right - lprc->left;
107 int h = lprc->bottom - lprc->top;
108
109 RECT rect;
110 if (bWorkArea)
111 GetWorkAreaRect(rect);
112 else
113 GetMonitorRect(rect);
114
115 lprc->left = rect.left + ( rect.right - rect.left - w ) / 2;
116 lprc->top = rect.top + ( rect.bottom - rect.top - h ) / 2;
117 lprc->right = lprc->left + w;
118 lprc->bottom = lprc->top + h;
119}
120
121//CMonitorManager 实现
122///< 单件定义宏
123SINGLETON_IMPLEMENT(CMonitorManager)
124
125CMonitorManager::CMonitorManager()
126{
127 UpdateMonitors();
128}
129
130CMonitorManager::~CMonitorManager()
131{
132 FreeMonitors();
133}
134
135//初始化系统当前拥有的显示器
136void CMonitorManager::UpdateMonitors()
137{
138 FreeMonitors();
139 ::EnumDisplayMonitors(NULL, NULL, AddMonitorsCallBack, (LPARAM)this);
140}
141
142void CMonitorManager::FreeMonitors()
143{
144 for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin(); iter!=m_vec_monitor.end();)
145 {
146 delete (*iter); iter = m_vec_monitor.erase(iter);
147 }
148}
149//获取系统当前显示器的个数
150DWORD CMonitorManager::GetCount()
151{
152 return m_vec_monitor.size();
153}
154//根据索引获取某个显示器
155CMonitor* CMonitorManager::GetMonitor(DWORD dwIndex)
156{
157 assert(dwIndex > 0);
158 if (dwIndex > m_vec_monitor.size()) return NULL;
159 return m_vec_monitor[dwIndex-1];
160}
161//获取主显示器
162CMonitor* CMonitorManager::GetPrimaryMonitor()
163{
164 for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin();iter!=m_vec_monitor.end();++iter)
165 {
166 if ((*iter)->IsPrimaryMonitor()) return (*iter);
167 }
168 return NULL;
169}
170//获取相对某矩形最近的显示器
171CMonitor* CMonitorManager::GetNearestMonitor(const RECT& rect)
172{
173 HMONITOR hMonitor = ::MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
174 assert(hMonitor);
175 return FindMonitor(hMonitor);
176}
177//获取相对某点最近的显示器
178CMonitor* CMonitorManager::GetNearestMonitor(const POINT& pt)
179{
180 HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
181 assert(hMonitor);
182 return FindMonitor(hMonitor);
183}
184//获取相对某窗口最近的显示器
185CMonitor* CMonitorManager::GetNearestMonitor(HWND hWnd)
186{
187 HMONITOR hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
188 assert(hMonitor);
189 return FindMonitor(hMonitor);
190}
191//根据某句柄获取显示器
192CMonitor* CMonitorManager::FindMonitor(HMONITOR hMonitor)
193{
194 for (vector<CMonitor*>::iterator iter=m_vec_monitor.begin(); iter!=m_vec_monitor.end();++iter)
195 {
196 if ((*iter)->m_hMonitor == hMonitor) return (*iter);
197 }
198 return NULL;
199}
200//WIN32回调API,在这个回调函数内实现初始化,当前有多少个显示器,就回调多少次
201BOOL CALLBACK CMonitorManager::AddMonitorsCallBack(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,
202 LPARAM dwData)
203{
204 CMonitorManager* pMonitorManger = (CMonitorManager*)dwData;
205 int nIndex = pMonitorManger->m_vec_monitor.size();
206 CMonitor* pMonitor = new CMonitor(hMonitor, ++nIndex);
207 pMonitorManger->m_vec_monitor.push_back(pMonitor);
208 return TRUE;
209}
210
211//获取虚拟桌面(也就是由当前所有显示器组成的一个桌面)的区域大小
212void CMonitorManager::GetVirtualDesktopRect(RECT& rect)
213{
214 ::SetRect(&rect,::GetSystemMetrics( SM_XVIRTUALSCREEN ),::GetSystemMetrics( SM_YVIRTUALSCREEN ),
215 ::GetSystemMetrics( SM_CXVIRTUALSCREEN ),::GetSystemMetrics( SM_CYVIRTUALSCREEN ));
216}
217//获取某矩形相对于虚拟桌面居中后的区域
218void CMonitorManager::CenterWindowToAll(RECT& rect, bool bUseWorkArea /* = false */)
219{
220 RECT rcAll, rcWork;
221 int iWidth, iHeight;
222 if (bUseWorkArea)
223 {
224 GetPrimaryMonitor()->GetWorkAreaRect(rcWork);
225 GetVirtualDesktopRect(rcAll);
226 iWidth = rect.right-rect.left, iHeight = rect.bottom-rect.top;
227 rect.left = rcWork.left + (rcAll.right-rcAll.left-iWidth)/2;
228 rect.top = rcWork.top + (rcAll.bottom-rcAll.top-iHeight)/2;
229 rect.right = rect.left + iWidth;
230 rect.bottom = rect.top + iHeight;
231 }
232 else
233 {
234 GetVirtualDesktopRect(rcAll);
235 iWidth = rect.right-rect.left, iHeight = rect.bottom-rect.top;
236 rect.left = rcAll.left + (rcAll.right-rcAll.left-iWidth)/2;
237 rect.top = rcAll.top + (rcAll.bottom-rcAll.top-iHeight)/2;
238 rect.right = rect.left + iWidth;
239 rect.bottom = rect.top + iHeight;
240 }
241}
242/**
243 @brief 居中窗口
244 @param hWnd 窗口句柄
245 @param iMonitorIndex 显示器索引,其参数意义如下:
246 1)<0--则表示在整个桌面居中 2)0--则在当前显示器居中 3)>=1--则表示在其它显示器居中
247 @param bUseWorkArea 是否在对应显示器工作区中居中: true在显示器工作区居中,false在显示器桌面居中
248*/
249void CMonitorManager::CenterWindow(HWND hWnd,int iMonitorIndex /* = 0 */, bool bUseWorkArea /* = false*/)
250{
251 RECT rect;
252 ::GetWindowRect(hWnd, &rect );
253 if (0 > iMonitorIndex )
254 {
255 CenterWindowToAll(rect, bUseWorkArea);
256 }
257 else if (0 == iMonitorIndex)
258 {
259 CMonitorManager::GetNearestMonitor(hWnd)->CenterRectToMonitor(&rect,bUseWorkArea);
260 }
261 else
262 {
263 CMonitor* pMonitor = CMonitorManager::GetMonitor(iMonitorIndex);
264 if (!pMonitor) return;
265 pMonitor->CenterRectToMonitor(&rect, bUseWorkArea);
266 }
267 ::SetWindowPos(hWnd, NULL, rect.left, rect.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
268}
269
270/**
271 @brief 单显示器全屏
272 @param hWnd 被全屏的窗口
273 @param bFullScreen 是否全屏: true表示全屏,false表示恢复
274 @param iMonitorIndex 显示器索引,其参数意义如下:
275 1)<0--则表示在整个桌面全屏 2)0--则在当前显示器全屏 3)>=1--则表示在其它显示器全屏
276 * 彻底实现全屏,包括去除边框样式,只留客户区
277 @return true表示操作成功,已经全屏或恢复;false表示操作失败,没有全屏或恢复
278 * FullScreenWindow(hWnd,true,iMonitorIndex)和FullScreenWindow(hWnd,false)要成对调用用于全屏和恢复
279*/
280bool CMonitorManager::FullScreenWindow(HWND hWnd, bool bFullScreen, int iMonitorIndex /*= 0*/)
281{
282 if (!hWnd||!IsWindow(hWnd)) return false;
283
284 stack<HWND> WndStack;
285 HWND hParent;
286 map<HWND, WndInfo>::iterator iter;
287
288 long lOldStyle, lNewStyle;
289 long lOldExStyle, lNewExStyle;
290 RECT rcNew, rcOld, rcMonitor;
291 lNewStyle = lOldStyle = GetWindowLong(hWnd, GWL_STYLE);
292 lOldExStyle = lNewExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
293
294 if (bFullScreen)
295 {
296 GetWindowRect(hWnd, &rcOld);
297 hParent = GetParent(hWnd);
298 if (hParent && (lOldStyle&WS_CHILD))
299 {
300 ScreenToClient(hParent, rcOld);
301 }
302 m_map_wnd.insert(make_pair(hWnd, WndInfo(lOldStyle, lOldExStyle, rcOld, false)));
303 }
304 if (lOldStyle & WS_CHILD)
305 {
306 for (HWND hTempParent = GetParent(hWnd); hTempParent; )
307 {
308 hParent = hTempParent; hTempParent = GetParent(hParent);
309 WndStack.push(hParent);
310 lOldStyle = GetWindowLong(hParent, GWL_STYLE);
311 if (bFullScreen)
312 {
313 GetWindowRect(hParent, &rcOld);
314 lOldExStyle = GetWindowLong(hParent, GWL_EXSTYLE);
315 if (hTempParent && (lOldStyle&WS_CHILD))
316 {
317 ::ScreenToClient(hTempParent, rcOld);
318 }
319 m_map_wnd.insert(make_pair(hParent, WndInfo(lOldStyle, lOldExStyle, rcOld, false)));
320 }
321 if (lOldStyle&WS_POPUP || lOldStyle&WS_OVERLAPPED) break;
322 }
323 }
324 else //弹出式或重叠窗口
325 {
326 if (bFullScreen)
327 {
328 if (lOldStyle & WS_CAPTION) lNewStyle &= ~WS_CAPTION;
329 if (lOldStyle & WS_DLGFRAME) lNewStyle &= ~WS_DLGFRAME;
330 if (lOldStyle & WS_THICKFRAME) lNewStyle &= ~WS_THICKFRAME;
331 if (lOldStyle & WS_BORDER) lNewStyle &= ~WS_BORDER;
332 if ((lOldExStyle & WS_EX_DLGMODALFRAME)) lNewExStyle &= ~WS_EX_DLGMODALFRAME;
333 if (lOldExStyle & WS_EX_WINDOWEDGE) lNewExStyle &= ~WS_EX_WINDOWEDGE;
334 if (lOldExStyle != lNewExStyle) SetWindowLong(hWnd, GWL_EXSTYLE, lNewExStyle);
335 if (lOldStyle != lNewStyle) SetWindowLong(hWnd, GWL_STYLE, lNewStyle);
336 }
337 }
338 //逐层全屏或恢复其父窗口
339 if (bFullScreen)
340 {
341 if (0 > iMonitorIndex)
342 {
343 GetVirtualDesktopRect(rcMonitor);
344 }
345 else if (0 == iMonitorIndex)
346 {
347 GetNearestMonitor(hWnd)->GetMonitorRect(rcMonitor);
348 }
349 else
350 {
351 CMonitor* pMonitor = GetMonitor(iMonitorIndex);
352 if (!pMonitor)
353 {
354 m_map_wnd.erase(hWnd); return false;
355 }
356 pMonitor->GetMonitorRect(rcMonitor);
357 }
358 rcNew = rcMonitor;
359 }
360 for (; !WndStack.empty(); WndStack.pop())
361 {
362 hParent = WndStack.top();
363 iter = m_map_wnd.find(hParent);
364 if (bFullScreen)
365 {
366 if (iter != m_map_wnd.end() && (*iter).second._bFull) continue;
367 lOldStyle = lNewStyle = GetWindowLong(hParent,GWL_STYLE);
368 lOldExStyle = lNewExStyle = GetWindowLong(hParent, GWL_EXSTYLE);
369 if (lOldStyle & WS_CAPTION) lNewStyle &= ~WS_CAPTION;
370 if (lOldStyle & WS_BORDER) lNewStyle &= ~WS_BORDER;
371 if (lOldStyle & WS_DLGFRAME) lNewStyle &= ~WS_DLGFRAME;
372 if (lOldStyle & WS_THICKFRAME) lNewStyle &= ~WS_THICKFRAME;
373 if (lOldExStyle & WS_EX_DLGMODALFRAME) lNewExStyle &= ~WS_EX_DLGMODALFRAME;
374 if (lOldExStyle & WS_EX_WINDOWEDGE) lNewExStyle &= ~WS_EX_WINDOWEDGE;
375 if (lOldExStyle != lNewExStyle) SetWindowLong(hParent, GWL_EXSTYLE, lNewExStyle);
376 if (lOldStyle != lNewStyle) SetWindowLong(hParent, GWL_STYLE, lNewStyle);
377 if (lOldStyle & WS_CHILD)
378 {
379 ScreenToClient(hParent, rcNew);
380 }
381 SetWindowPos(hParent, 0, rcNew.left,rcNew.top,rcNew.right-rcNew.left,rcNew.bottom-rcNew.top,
382 SWP_SHOWWINDOW|SWP_NOZORDER|SWP_FRAMECHANGED);
383 (*iter).second._bFull = true;
384 }
385 else
386 {
387 if (iter == m_map_wnd.end() || !(*iter).second._bFull) continue;
388 WndInfo& wndinfo = (*iter).second; wndinfo._bFull = false;
389 rcOld = wndinfo._rcWnd;
390 SetWindowLong(hParent, GWL_STYLE, wndinfo._lStyle);
391 SetWindowLong(hParent, GWL_EXSTYLE, wndinfo._lExStyle);
392 SetWindowPos(hParent, 0, rcOld.left,rcOld.top,rcOld.right-rcOld.left,rcOld.bottom-rcOld.top,
393 SWP_SHOWWINDOW|SWP_NOZORDER);
394 m_map_wnd.erase(iter);
395 }
396 }
397 //全屏或恢复本窗口
398 hParent = GetParent(hWnd); iter = m_map_wnd.find(hWnd);
399 if (bFullScreen)
400 {
401 if (iter != m_map_wnd.end() && (*iter).second._bFull) return true;
402 lOldStyle = GetWindowLong(hWnd, GWL_STYLE);
403 if (hParent && (lOldStyle & WS_CHILD))
404 {
405 for(HWND hChild = ::GetTopWindow(hParent); hChild; hChild = ::GetNextWindow(hChild, GW_HWNDNEXT))
406 {
407 if (hChild != hWnd) ::ShowWindow(hChild, SW_HIDE);
408 }
409 ScreenToClient(hParent, rcNew);
410 }
411 SetWindowPos(hWnd, 0, rcNew.left,rcNew.top,rcNew.right-rcNew.left,rcNew.bottom-rcNew.top,
412 SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOZORDER);
413 (*iter).second._bFull = true;
414 }
415 else
416 {
417 if (iter == m_map_wnd.end() || !(*iter).second._bFull) return true;
418 WndInfo& wndinfo = (*iter).second; wndinfo._bFull = false;
419 rcOld = wndinfo._rcWnd;
420 SetWindowLong(hWnd, GWL_STYLE, wndinfo._lStyle);
421 SetWindowLong(hWnd, GWL_EXSTYLE, wndinfo._lExStyle);
422 if (hParent && (wndinfo._lStyle & WS_CHILD))
423 {
424 for(HWND hChild = ::GetTopWindow(hParent); hChild; hChild = ::GetNextWindow(hChild, GW_HWNDNEXT))
425 {
426 ::ShowWindow(hChild, SW_SHOWNORMAL);
427 }
428 }
429 SetWindowPos(hWnd, 0, rcOld.left,rcOld.top,rcOld.right-rcOld.left,rcOld.bottom-rcOld.top,
430 SWP_SHOWWINDOW|SWP_NOZORDER);
431 m_map_wnd.erase(iter);
432 }
433 return true;
434}
435
436/**
437 @brief 双显示器全屏
438 @param hWndFirst 在显示器1全屏的窗口句柄
439 @param hWndSecond 在显示器2全屏的窗口句柄
440 @return true表示全屏都成功,false表示至少有一个全屏失败
441*/
442bool CMonitorManager::FullScreenWindow(HWND hWndFirst, HWND hWndSecond)
443{
444 if (!hWndFirst || !IsWindow(hWndFirst) ) return false;
445 if (!hWndSecond || !IsWindow(hWndSecond)) return false;
446
447 RECT rcOld;
448 long lStyle, lExStyle;
449 HWND hFirstParent = 0, hSecondParent = 0, hTempParent;
450 bool bFullMainWnd = true;
451 for (hTempParent = GetParent(hWndFirst); hTempParent; )
452 {
453 hFirstParent = hTempParent; hTempParent = GetParent(hFirstParent);
454 if (hTempParent && (GetWindowLong(hFirstParent, GWL_STYLE)&WS_POPUP))
455 {
456 bFullMainWnd = false;
457 }
458 }
459 for (hTempParent = GetParent(hWndSecond); hTempParent; )
460 {
461 hSecondParent = hTempParent; hTempParent = GetParent(hSecondParent);
462 if (hTempParent && (GetWindowLong(hSecondParent, GWL_STYLE)&WS_POPUP))
463 {
464 bFullMainWnd = false;
465 }
466 }
467 if (hFirstParent && hSecondParent)
468 {
469 if (hSecondParent == hFirstParent && bFullMainWnd)
470 {
471 HWND hWnds[] = {hWndFirst, hWndSecond};
472 for (int i = 0; i < 2; ++i)
473 {
474 GetWindowRect(hWnds[i], &rcOld);
475 ScreenToClient(hFirstParent, rcOld);
476 lStyle = GetWindowLong(hWnds[i], GWL_STYLE);
477 lExStyle = GetWindowLong(hWnds[i], GWL_EXSTYLE);
478 m_map_wnd.insert(make_pair(hWnds[i], WndInfo(lStyle, lExStyle, rcOld, false)));
479 }
480 if (!FullScreenWindow(hFirstParent, true, -1)) return false;
481 }
482 }
483 if (!FullScreenWindow(hWndFirst, true, 1)) return false;
484 if (!FullScreenWindow(hWndSecond, true, 2)) return false;
485 ShowWindow(hWndFirst, SW_SHOWNORMAL); ShowWindow(hWndSecond, SW_SHOWNORMAL);
486 return true;
487}
- 基于WINDOWS 32API封装的显示器类: (2) 源文件
- 基于WINDOWS 32API封装的显示器类: (1) 头文件
- 基于LeanCloud平台的REST API封装
- 重温WIN32 API ------ 最简单的Windows窗口封装类
- 基于Android系统Api封装常用工具类
- 基于Android系统Api封装常用工具类
- windows socket api 封装
- windows API 封装
- 利用windows API更改显示器的分辨率和更改双屏的显示模式
- 【windows API】以像素为单位显示视屏显示器的宽度和高度
- YTKRequest - 基于 AFNetworking 封装的一套 High Level 的 API
- 基于Windows API的Socket程序技术
- Windows下基于API的串口程序
- .NET下基于API封装的DirectUIHWND窗体访问
- 基于自己封装的微信api操作案例
- c#收发串口数据的源码(封装了windows api的类)
- c#收发串口数据的源码(封装了windows api的类)
- 基于WDF的PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)
- 查看C程序进程死锁
- android View中如何判断长按事件
- 基于WINDOWS 32API封装的显示器类: (1) 头文件
- 漫谈.NET开发中的字符串编码
- LAH 笔记 cron
- 基于WINDOWS 32API封装的显示器类: (2) 源文件
- Qt 4使用MySQL的中文问题解决方法
- 用汇编的眼光看c++(之模板函数)
- 软件质量概述4 什么时候进行质量保证工作
- 2015
- struts2+jquery实现动态添加下拉框
- Jquery Ajax读取XML文档实现联动下拉框实例
- 《Linux那些事儿之我是USB》我是U盘(13)设备花名册
- ASP.NET+ExtJs4.0+表单提交submit,上传图片到服务器