VC++编程实现多显示器控制(复制、横屏、纵屏,显示器个数)
生活随笔
收集整理的這篇文章主要介紹了
VC++编程实现多显示器控制(复制、横屏、纵屏,显示器个数)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近做了個三維的程序,部署到客戶機器上,客戶看了后,現場提出這樣的一個需求:程序能智能探測接入的顯示器個數,當有新的顯示器接入時,現有的只在一個顯示器上顯示的三維場景能投遞到新插入的顯示器上顯示。類似在桌面上點擊鼠標右鍵,選擇“顯示設置”菜單,彈出的如下界面:
VC++對話框工程代碼實現如下:
.h文件如下:
// displayOperDlg.h: 頭文件 //#pragma once #include<list> using std::list;// CDisplayOperDlg 對話框 class CDisplayOperDlg : public CDialogEx { // 構造 public:CDisplayOperDlg(CWnd* pParent = nullptr); // 標準構造函數// 對話框數據 #ifdef AFX_DESIGN_TIMEenum { IDD = IDD_DISPLAYOPER_DIALOG }; #endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持void GetAllMonitors();void SwitchPrimaryScreen(int newPrimary, int oldPrimary);void MoveOldPrimary(int newPrimary, int oldPrimary);void MoveNewPrimary(int newPrimary, int oldPrimary);void CommitChange();int GetPrimaryScreen();int SetPrimaryScreen(int num);int SetCloneView(int mode);int ChangeScreenOrientation(int num, int rotation); // 實現 protected:HICON m_hIcon;// 生成的消息映射函數virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP() public:afx_msg void OnCbnSelchangeCombo1();afx_msg void OnCbnDropdownCombo1();afx_msg void OnBnClickedButton1();afx_msg void OnBnClickedButton2();afx_msg void OnBnClickedOk();private:list<DISPLAY_DEVICE> dev_list;CComboBox* comboBox;list<DEVMODE>dev_mode_list;int PrimaryNum, selIndex, count1;int count{0}; };.cpp文件如下:
// displayOperDlg.cpp: 實現文件 //#include "pch.h" #include "framework.h" #include "displayOper.h" #include "displayOperDlg.h" #include "afxdialogex.h"#ifdef _DEBUG #define new DEBUG_NEW #endif// 用于應用程序“關于”菜單項的 CAboutDlg 對話框class CAboutDlg : public CDialogEx { public:CAboutDlg();// 對話框數據 #ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX }; #endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 實現 protected:DECLARE_MESSAGE_MAP() };CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { }void CAboutDlg::DoDataExchange(CDataExchange* pDX) {CDialogEx::DoDataExchange(pDX); }BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP()// CDisplayOperDlg 對話框CDisplayOperDlg::CDisplayOperDlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DISPLAYOPER_DIALOG, pParent) {m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }void CDisplayOperDlg::DoDataExchange(CDataExchange* pDX) {CDialogEx::DoDataExchange(pDX); }BEGIN_MESSAGE_MAP(CDisplayOperDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDOK, &CDisplayOperDlg::OnBnClickedOk)ON_CBN_SELCHANGE(IDC_COMBO1, &CDisplayOperDlg::OnCbnSelchangeCombo1)ON_CBN_DROPDOWN(IDC_COMBO1, &CDisplayOperDlg::OnCbnDropdownCombo1)ON_CBN_SELCHANGE(IDC_COMBO1, &CDisplayOperDlg::OnCbnSelchangeCombo1)ON_CBN_DROPDOWN(IDC_COMBO1, &CDisplayOperDlg::OnCbnDropdownCombo1)ON_BN_CLICKED(IDC_BUTTON1, &CDisplayOperDlg::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON2, &CDisplayOperDlg::OnBnClickedButton2)ON_BN_CLICKED(IDOK, &CDisplayOperDlg::OnBnClickedOk) END_MESSAGE_MAP()// CDisplayOperDlg 消息處理程序BOOL CDisplayOperDlg::OnInitDialog() {CDialogEx::OnInitDialog();// 將“關于...”菜單項添加到系統菜單中。// IDM_ABOUTBOX 必須在系統命令范圍內。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動// 執行此操作SetIcon(m_hIcon, TRUE); // 設置大圖標SetIcon(m_hIcon, FALSE); // 設置小圖標GetAllMonitors();CComboBox* comboBox = (CComboBox*)GetDlgItem(IDC_COMBO1);comboBox->ResetContent();for (int i = 0; i < dev_list.size(); i++){CString string1;//; = CString(i);string1.Format(_T("%d"), i + 1);//ZeroMemory(&string1, sizeof(string1));//sprintf(temp, "%d", i+1);comboBox->AddString(string1);}comboBox->SetCurSel(0);UpdateData(false);return TRUE; // 除非將焦點設置到控件,否則返回 TRUE }void CDisplayOperDlg::GetAllMonitors() {std::list<DISPLAY_DEVICE> devices;std::list<DEVMODE> modes; int devId = 0;bool ret = false;bool isPrimary = false;//list all DisplayDevices (Monitors)do{DISPLAY_DEVICE displayDevice;ZeroMemory(&displayDevice, sizeof(DISPLAY_DEVICE));displayDevice.cb = sizeof(displayDevice);ret = EnumDisplayDevices(NULL, devId, &displayDevice, 0);if (ret == true){if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP){devices.push_back(displayDevice);isPrimary = ((displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) == DISPLAY_DEVICE_PRIMARY_DEVICE);if (isPrimary)PrimaryNum = devId;}}devId++;} while (ret);dev_list = devices;std::list<DISPLAY_DEVICE>::iterator it;for (it = dev_list.begin(); it != dev_list.end(); it++){DEVMODE deviceMode;deviceMode.dmSize = sizeof(DEVMODE);deviceMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; // | DM_DISPLAYORIENTATION;EnumDisplaySettings(it->DeviceName, (int)ENUM_REGISTRY_SETTINGS, &deviceMode);modes.push_back(deviceMode);}dev_mode_list = modes;} void CDisplayOperDlg::OnSysCommand(UINT nID, LPARAM lParam) {if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);} }// 如果向對話框添加最小化按鈕,則需要下面的代碼 // 來繪制該圖標。 對于使用文檔/視圖模型的 MFC 應用程序, // 這將由框架自動完成。void CDisplayOperDlg::OnPaint() {if (IsIconic()){CPaintDC dc(this); // 用于繪制的設備上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使圖標在工作區矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 繪制圖標dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();} }//當用戶拖動最小化窗口時系統調用此函數取得光標 //顯示。 HCURSOR CDisplayOperDlg::OnQueryDragIcon() {return static_cast<HCURSOR>(m_hIcon); }void CDisplayOperDlg::SwitchPrimaryScreen(int newPrimary, int oldPrimary) {MoveNewPrimary(newPrimary, oldPrimary);MoveOldPrimary(newPrimary, oldPrimary);CommitChange(); }void CDisplayOperDlg::MoveOldPrimary(int newPrimary, int oldPrimary) {int index = 0;std::list<DISPLAY_DEVICE>::iterator it1;for (it1 = dev_list.begin(); it1 != dev_list.end(); it1++){if (index == oldPrimary)break;index++;}index = 0;std::list<DEVMODE>::iterator it2;for (it2 = dev_mode_list.begin(); it2 != dev_mode_list.end(); it2++){if (index == newPrimary)break;index++;}index = 0;std::list<DEVMODE>::iterator it3;for (it3 = dev_mode_list.begin(); it3 != dev_mode_list.end(); it3++){if (index == oldPrimary)break;index++;}it3->dmPosition.x = it2->dmPelsWidth;it3->dmPosition.y = 0;DEVMODE deviceMode = *it3;int ret = ChangeDisplaySettingsEx(it1->DeviceName, &deviceMode, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); }void CDisplayOperDlg::MoveNewPrimary(int newPrimary, int oldPrimary) {int index = 0;std::list<DISPLAY_DEVICE>::iterator it1;for (it1 = dev_list.begin(); it1 != dev_list.end(); it1++){if (index == newPrimary)break;index++;}index = 0;std::list<DEVMODE>::iterator it2;for (it2 = dev_mode_list.begin(); it2 != dev_mode_list.end(); it2++){if (index == newPrimary)break;index++;}it2->dmPosition.x = 0;it2->dmPosition.y = 0;DEVMODE deviceMode = *it2;int ret = ChangeDisplaySettingsEx(it1->DeviceName, &deviceMode, NULL, CDS_SET_PRIMARY | CDS_UPDATEREGISTRY | CDS_NORESET, NULL); }void CDisplayOperDlg::CommitChange() {ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL); }int CDisplayOperDlg::GetPrimaryScreen() {return PrimaryNum; }int CDisplayOperDlg::SetPrimaryScreen(int num) {int oldprimary = GetPrimaryScreen();int newPrimary = num;if ((num >= dev_list.size()) || (num < 0))return -1;if (oldprimary == newPrimary)return 0;SwitchPrimaryScreen(newPrimary, oldprimary);PrimaryNum = newPrimary;return oldprimary; }int CDisplayOperDlg::SetCloneView(int mode) {/*UINT32 PathArraySize = 0;UINT32 ModeArraySize = 0;DISPLAYCONFIG_PATH_INFO* PathArray;DISPLAYCONFIG_MODE_INFO* ModeArray;DISPLAYCONFIG_TOPOLOGY_ID CurrentTopology;//Determine the size of the path array that is required to hold all valid pathsGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &PathArraySize, &ModeArraySize); //retrieve the sizes of the DISPLAYCONFIG_PATH_INFO and DISPLAYCONFIG_MODE_INFO buffers that are required//Allocate memory for path and mode information arraysPathArray = (DISPLAYCONFIG_PATH_INFO*)malloc(PathArraySize * sizeof(DISPLAYCONFIG_PATH_INFO));memset(PathArray, 0, PathArraySize * sizeof(DISPLAYCONFIG_PATH_INFO));ModeArray = (DISPLAYCONFIG_MODE_INFO*)malloc(ModeArraySize * sizeof(DISPLAYCONFIG_MODE_INFO));ZeroMemory(ModeArray, ModeArraySize * sizeof(DISPLAYCONFIG_MODE_INFO));//Request all of the path informationLONG ret = QueryDisplayConfig(QDC_DATABASE_CURRENT,&PathArraySize, PathArray, &ModeArraySize, ModeArray, &CurrentTopology); //obtain the path and mode information for all posible paths// Above CurrentTopology variable will aquire the current display setting (ie Extend, Duplicate etc)free(PathArray);free(ModeArray);*///Set the new topology.SetDisplayConfig(0, NULL, 0, NULL, mode | SDC_APPLY); //change to the clone topologyreturn 0; }int CDisplayOperDlg::ChangeScreenOrientation(int num, int rotation) {int index = 0;std::list<DEVMODE>::iterator it;for (it = dev_mode_list.begin(); it != dev_mode_list.end(); it++){if (index == num)break;index++;}DWORD dwTemp = it->dmPelsHeight;switch (rotation){case 0:if (it->dmDisplayOrientation == DMDO_DEFAULT)it->dmDisplayOrientation = DMDO_90;else if (it->dmDisplayOrientation == DMDO_90)it->dmDisplayOrientation = DMDO_DEFAULT;it->dmPelsHeight = it->dmPelsWidth;it->dmPelsWidth = dwTemp;break;case 1:if (it->dmDisplayOrientation == DMDO_DEFAULT)it->dmDisplayOrientation = DMDO_90;else if (it->dmDisplayOrientation == DMDO_90)it->dmDisplayOrientation = DMDO_DEFAULT;it->dmPelsHeight = it->dmPelsWidth;it->dmPelsWidth = dwTemp;break;}DEVMODE deviceMode;ZeroMemory(&deviceMode, sizeof(deviceMode));deviceMode.dmSize = sizeof(deviceMode);deviceMode = *it;index = 0;std::list<DISPLAY_DEVICE>::iterator it1;for (it1 = dev_list.begin(); it1 != dev_list.end(); it1++){if (index == num)break;index++;}//long lRet = ChangeDisplaySettingsEx(it1->DeviceName, &deviceMode, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL);//CommitChange();long lRet = ChangeDisplaySettingsEx(it1->DeviceName, &deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);return lRet; }void CDisplayOperDlg::OnCbnSelchangeCombo1() {//取得選中的值CString selStr;int selIndex = comboBox->GetCurSel();//取得選中的索引comboBox->GetLBText(selIndex,selStr);MessageBox(selStr); }void CDisplayOperDlg::OnCbnDropdownCombo1() {GetAllMonitors();comboBox = (CComboBox*)GetDlgItem(IDC_COMBO1);comboBox->ResetContent();for (int i = 0; i < dev_list.size(); i++){CString string1;//; = CString(i);string1.Format(_T("%d"), i + 1);//ZeroMemory(&string1, sizeof(string1));//sprintf(temp, "%d", i+1);comboBox->AddString(string1);}UpdateData(false); }void CDisplayOperDlg::OnBnClickedButton1() {long lRet;selIndex = comboBox->GetCurSel();//取得選中的索引if (selIndex < 0)return;count1++;if (count1 % 2){lRet = ChangeScreenOrientation(selIndex, 1);}else{lRet = ChangeScreenOrientation(selIndex, 0);} }void CDisplayOperDlg::OnBnClickedButton2() {count++;if (count % 2){SetCloneView(SDC_TOPOLOGY_CLONE);GetDlgItem(IDC_BUTTON2)->SetWindowTextW(_T("恢復"));}else{SetCloneView(SDC_TOPOLOGY_EXTEND);GetDlgItem(IDC_BUTTON2)->SetWindowTextW(_T("屏幕復制"));} }void CDisplayOperDlg::OnBnClickedOk() {SetPrimaryScreen(selIndex);// // CDialogEx::OnOK(); }?參考鏈接:
《VC++實現Windows中雙顯示器(主屏、擴展屏)各種操作的源碼工程》
附上幾個有用的鏈接:
https://msdn.microsoft.com/en-us/library/ff569533(v=vs.85).aspx
?
https://msdn.microsoft.com/en-us/library/dd183413(VS.85).aspx
?
?
總結
以上是生活随笔為你收集整理的VC++编程实现多显示器控制(复制、横屏、纵屏,显示器个数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详细解释返利网怎么使用、怎么避免漏单、怎
- 下一篇: osgQt::GLWidget的坑