diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 2713b29..0f98596 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 773aec9..d695adb 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -936,6 +936,16 @@ BOOL CMy2015RemoteDlg::OnInitDialog() AUTO_TICK(500); CDialogEx::OnInitDialog(); + // Grid 瀹瑰櫒 + int size = THIS_CFG.GetInt("settings", "VideoWallSize"); + size = max(size, 1); + if (size > 1) { + m_gridDlg = new CGridDialog(); + m_gridDlg->Create(IDD_GRID_DIALOG, GetDesktopWindow()); + m_gridDlg->ShowWindow(SW_HIDE); + m_gridDlg->SetGrid(size, size); + } + if (!IsPwdHashValid()) { THIS_CFG.SetStr("settings", "superAdmin", ""); THIS_CFG.SetStr("settings", "Password", ""); @@ -1366,6 +1376,7 @@ void CMy2015RemoteDlg::Release(){ Sleep(20); THIS_APP->Destroy(); + SAFE_DELETE(m_gridDlg); g_2015RemoteDlg = NULL; SetEvent(m_hExit); CloseHandle(m_hExit); diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index e106723..21c7b24 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -26,6 +26,7 @@ typedef struct DllInfo { ////////////////////////////////////////////////////////////////////////// #include #include +#include "CGridDialog.h" enum { MAP_NOTE, @@ -159,8 +160,19 @@ public: { CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)lParam; T* Dlg = new T(this, ContextObject->GetServer(), ContextObject); - Dlg->Create(id, GetDesktopWindow()); + BOOL isGrid = id == IDD_DIALOG_SCREEN_SPY; + BOOL ok = (isGrid&&m_gridDlg) ? m_gridDlg->HasSlot() : FALSE; + Dlg->Create(id, ok ? m_gridDlg : GetDesktopWindow()); Dlg->ShowWindow(Show); + if (ok) { + m_gridDlg->AddChild((CDialog*)Dlg); + LONG style = ::GetWindowLong(Dlg->GetSafeHwnd(), GWL_STYLE); + style &= ~(WS_CAPTION | WS_SIZEBOX); // 去掉标题栏和调整大小 + ::SetWindowLong(Dlg->GetSafeHwnd(), GWL_STYLE, style); + ::SetWindowPos(Dlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + m_gridDlg->ShowWindow(isGrid ? SW_SHOWMAXIMIZED : SW_HIDE); + } ContextObject->hWnd = Dlg->GetSafeHwnd(); ContextObject->hDlg = Dlg; @@ -197,7 +209,7 @@ public: CStatusBar m_StatusBar; //状态条 CTrueColorToolBar m_ToolBar; - + CGridDialog * m_gridDlg = NULL; std::vector m_DllList; NOTIFYICONDATA m_Nid; HANDLE m_hExit; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 63d9c36..2b8ae57 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -264,6 +264,7 @@ + @@ -334,6 +335,7 @@ + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index dbd610a..8b17897 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -52,6 +52,7 @@ + @@ -116,6 +117,7 @@ + diff --git a/server/2015Remote/CGridDialog.cpp b/server/2015Remote/CGridDialog.cpp new file mode 100644 index 0000000..213932c --- /dev/null +++ b/server/2015Remote/CGridDialog.cpp @@ -0,0 +1,229 @@ +#include "stdafx.h" +#include "afxdialogex.h" +#include "CGridDialog.h" +#include "Resource.h" + +BEGIN_MESSAGE_MAP(CGridDialog, CDialog) + ON_WM_SIZE() + ON_WM_LBUTTONDBLCLK() + ON_MESSAGE(WM_CHILD_CLOSED, &CGridDialog::OnChildClosed) +END_MESSAGE_MAP() + +CGridDialog::CGridDialog() : CDialog() +{ +} + +BOOL CGridDialog::OnInitDialog() +{ + m_hIcon = ::LoadIconA(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME)); + SetIcon(m_hIcon, FALSE); + + CDialog::OnInitDialog(); + return TRUE; +} + +void CGridDialog::SetGrid(int rows, int cols) +{ + m_rows = rows; + m_cols = cols; + m_max = rows * cols; + LayoutChildren(); +} + +BOOL CGridDialog::AddChild(CDialog* pDlg) +{ + if (!pDlg || !::IsWindow(pDlg->GetSafeHwnd()) || m_children.size() >= m_max) + return FALSE; + + pDlg->SetParent(this); + pDlg->ShowWindow(SW_SHOW); + + // 去掉标题栏和调整大小 + LONG style = ::GetWindowLong(pDlg->GetSafeHwnd(), GWL_STYLE); + style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SIZEBOX | WS_BORDER); + ::SetWindowLong(pDlg->GetSafeHwnd(), GWL_STYLE, style); + ::SetWindowPos(pDlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + + m_children.push_back(pDlg); + LayoutChildren(); + return TRUE; +} + +void CGridDialog::RemoveChild(CDialog* pDlg) +{ + auto it = std::find(m_children.begin(), m_children.end(), pDlg); + if (it != m_children.end()) + { + (*it)->ShowWindow(SW_HIDE); + (*it)->SetParent(nullptr); + m_children.erase(it); + + // 删除 m_origState 中对应条目 + auto itState = m_origState.find(pDlg); + if (itState != m_origState.end()) + m_origState.erase(itState); + + // 如果关闭的子窗口是当前最大化窗口,重置 m_pMaxChild + if (m_pMaxChild == pDlg) + m_pMaxChild = nullptr; + + LayoutChildren(); + } +} + +LRESULT CGridDialog::OnChildClosed(WPARAM wParam, LPARAM lParam) +{ + CDialog* pDlg = (CDialog*)wParam; + RemoveChild(pDlg); + return 0; +} + +void CGridDialog::LayoutChildren() +{ + if (m_children.size() == 0) { + // 恢复父窗口标题栏 + if (m_parentStyle != 0) + { + ::SetWindowLong(m_hWnd, GWL_STYLE, m_parentStyle); + ::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + m_parentStyle = 0; + } + ShowWindow(SW_HIDE); + return; + } + + if (m_rows <= 0 || m_cols <= 0 || m_children.empty() || m_pMaxChild != nullptr) + return; + + CRect rcClient; + GetClientRect(&rcClient); + + int w = rcClient.Width() / m_cols; + int h = rcClient.Height() / m_rows; + + for (size_t i = 0; i < m_children.size(); ++i) + { + int r = (int)i / m_cols; + int c = (int)i % m_cols; + + if (r >= m_rows) + break; // 超过网格范围 + + int x = c * w; + int y = r * h; + + m_children[i]->MoveWindow(x, y, w, h, TRUE); + m_children[i]->ShowWindow(SW_SHOW); + } +} + +void CGridDialog::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + if (m_pMaxChild == nullptr) { + LayoutChildren(); + } + else { + // 最大化状态下,保持铺满父对话框 + CRect rcClient; + GetClientRect(&rcClient); + m_pMaxChild->MoveWindow(rcClient, TRUE); + } +} + +void CGridDialog::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + // 如果当前有最大化的子窗口,双击任何地方都恢复 + if (m_pMaxChild != nullptr) + { + // 恢复子窗口样式和位置 + for (auto& kv : m_origState) + { + CDialog* dlg = kv.first; + const ChildState& state = kv.second; + + ::SetWindowLong(dlg->GetSafeHwnd(), GWL_STYLE, state.style); + ::SetWindowPos(dlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + + dlg->MoveWindow(state.rect, TRUE); + dlg->ShowWindow(SW_SHOW); + } + + // 恢复父窗口标题栏 + if (m_parentStyle != 0) + { + ::SetWindowLong(m_hWnd, GWL_STYLE, m_parentStyle); + ::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + m_parentStyle = 0; + } + + // 刷新父窗口 + m_pMaxChild = nullptr; + m_origState.clear(); + LayoutChildren(); + return; // 已处理,返回 + } + + // 没有最大化子窗口,则按原逻辑找到点击的子窗口进行最大化 + for (auto dlg : m_children) + { + CRect rc; + dlg->GetWindowRect(&rc); + ScreenToClient(&rc); + + if (rc.PtInRect(point)) + { + // 保存所有子窗口原始状态 + m_origState.clear(); + for (auto d : m_children) + { + ChildState state; + d->GetWindowRect(&state.rect); + ScreenToClient(&state.rect); + state.style = ::GetWindowLong(d->GetSafeHwnd(), GWL_STYLE); + m_origState[d] = state; + } + + // 最大化点击的子窗口 + LONG style = m_origState[dlg].style; + style |= (WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + ::SetWindowLong(dlg->GetSafeHwnd(), GWL_STYLE, style); + ::SetWindowPos(dlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + + // 隐藏父窗口标题栏 + if (m_parentStyle == 0) + m_parentStyle = ::GetWindowLong(m_hWnd, GWL_STYLE); + LONG parentStyle = m_parentStyle & ~(WS_CAPTION | WS_THICKFRAME); + ::SetWindowLong(m_hWnd, GWL_STYLE, parentStyle); + ::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + + // 全屏显示子窗口 + CRect rcClient; + GetClientRect(&rcClient); + dlg->MoveWindow(rcClient, TRUE); + m_pMaxChild = dlg; + + // 隐藏其他子窗口 + for (auto d : m_children) + if (d != dlg) d->ShowWindow(SW_HIDE); + + break; + } + } + + CDialog::OnLButtonDblClk(nFlags, point); +} + +BOOL CGridDialog::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) { + return TRUE;// 屏蔽Enter和ESC关闭对话 + } + return CDialog::PreTranslateMessage(pMsg); +} diff --git a/server/2015Remote/CGridDialog.h b/server/2015Remote/CGridDialog.h new file mode 100644 index 0000000..32cb0e1 --- /dev/null +++ b/server/2015Remote/CGridDialog.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include + +#define WM_CHILD_CLOSED (WM_USER + 100) + +class CGridDialog : public CDialog +{ +public: + CGridDialog(); + + BOOL AddChild(CDialog* pDlg); // 动态添加子对话框 + void RemoveChild(CDialog* pDlg); // 动态移除子对话框 + void SetGrid(int rows, int cols); // 设置行列数 + void LayoutChildren(); // 布局 + BOOL HasSlot() const { + return m_children.size() < m_max; + } + +protected: + virtual BOOL OnInitDialog(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + virtual BOOL PreTranslateMessage(MSG* pMsg); + afx_msg LRESULT OnChildClosed(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +private: + HICON m_hIcon; + int m_rows = 0; + int m_cols = 0; + int m_max = 0; + std::vector m_children; + + // 最大化相关 + CDialog* m_pMaxChild = nullptr; // 当前最大化的子对话框 + LONG m_parentStyle = 0; // 父窗口原始样式 + + struct ChildState { + CRect rect; // 原始位置 + LONG style; // 原始窗口样式 + }; + std::map m_origState; +}; diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index b45f1b2..54714cb 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -7,6 +7,7 @@ #include "afxdialogex.h" #include #include +#include "CGridDialog.h" // CScreenSpyDlg 瀵硅瘽妗 @@ -126,11 +127,26 @@ BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog) ON_WM_MOUSELEAVE() ON_WM_KILLFOCUS() ON_WM_SIZE() + ON_WM_LBUTTONDBLCLK() END_MESSAGE_MAP() // CScreenSpyDlg 娑堟伅澶勭悊绋嬪簭 +void CScreenSpyDlg::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + if (!m_bIsCtrl) { + CWnd* parent = GetParent(); + if (parent) { + // 閫氱煡鐖跺璇濇锛屼紶閫掔偣鍑荤偣 + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + GetParent()->ScreenToClient(&ptScreen); + GetParent()->SendMessage(WM_LBUTTONDBLCLK, nFlags, MAKELPARAM(ptScreen.x, ptScreen.y)); + } + } + CDialog::OnLButtonDblClk(nFlags, point); +} BOOL CScreenSpyDlg::OnInitDialog() { @@ -195,13 +211,19 @@ BOOL CScreenSpyDlg::OnInitDialog() VOID CScreenSpyDlg::OnClose() { CancelIO(); + // 鎭㈠榧犳爣鐘舵 + SetClassLongPtr(m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor(NULL, IDC_ARROW)); + // 閫氱煡鐖剁獥鍙 + CWnd* parent = GetParent(); + if (parent) + parent->SendMessage(WM_CHILD_CLOSED, (WPARAM)this, 0); + // 绛夊緟鏁版嵁澶勭悊瀹屾瘯 if (IsProcessing()) { ShowWindow(SW_HIDE); return; } - // 鎭㈠榧犳爣鐘舵 - SetClassLongPtr(m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor(NULL, IDC_ARROW)); + DialogBase::OnClose(); } diff --git a/server/2015Remote/ScreenSpyDlg.h b/server/2015Remote/ScreenSpyDlg.h index 06aa85d..5ad2a1e 100644 --- a/server/2015Remote/ScreenSpyDlg.h +++ b/server/2015Remote/ScreenSpyDlg.h @@ -120,4 +120,5 @@ public: afx_msg void OnPaint(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); virtual BOOL PreTranslateMessage(MSG* pMsg); + void OnLButtonDblClk(UINT nFlags, CPoint point); }; diff --git a/server/2015Remote/SettingDlg.cpp b/server/2015Remote/SettingDlg.cpp index ed99996..d6e8ceb 100644 --- a/server/2015Remote/SettingDlg.cpp +++ b/server/2015Remote/SettingDlg.cpp @@ -61,6 +61,7 @@ void CSettingDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_EDIT_FRP_TOKEN, m_EditFrpToken); DDX_Text(pDX, IDC_EDIT_FRP_TOKEN, m_sFrpToken); DDV_MaxChars(pDX, m_sFrpToken, 24); + DDX_Control(pDX, IDC_COMBO_VIDEO_WALL, m_ComboVideoWall); } BEGIN_MESSAGE_MAP(CSettingDlg, CDialog) @@ -143,6 +144,15 @@ BOOL CSettingDlg::OnInitDialog() m_nFrpPort = THIS_CFG.GetInt("frp", "server_port", 7000); m_sFrpToken = THIS_CFG.GetStr("frp", "token").c_str(); + int size = THIS_CFG.GetInt("settings", "VideoWallSize"); + m_ComboVideoWall.InsertString(0, "无"); + m_ComboVideoWall.InsertString(1, "2 x 2"); + m_ComboVideoWall.InsertString(2, "3 x 3"); + m_ComboVideoWall.InsertString(3, "4 x 4"); + m_ComboVideoWall.InsertString(4, "5 x 5"); + if (size < 1 || size > 5) size = 1; + m_ComboVideoWall.SetCurSel(size-1); + UpdateData(FALSE); return TRUE; @@ -174,6 +184,8 @@ void CSettingDlg::OnBnClickedButtonSettingapply() THIS_CFG.SetInt("frp", "server_port", m_nFrpPort); THIS_CFG.SetStr("frp", "token", m_sFrpToken.GetString()); + THIS_CFG.SetInt("settings", "VideoWallSize", m_ComboVideoWall.GetCurSel()+1); + m_ApplyButton.EnableWindow(FALSE); m_ApplyButton.ShowWindow(SW_HIDE); } diff --git a/server/2015Remote/SettingDlg.h b/server/2015Remote/SettingDlg.h index f655e9b..df49fe9 100644 --- a/server/2015Remote/SettingDlg.h +++ b/server/2015Remote/SettingDlg.h @@ -48,4 +48,5 @@ public: int m_nFrpPort; CEdit m_EditFrpToken; CString m_sFrpToken; + CComboBox m_ComboVideoWall; }; diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index b38b400..cdf1f50 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ