#include "win32_window.h" #include #include "resource.h" #define IDR_PAUSE 12 #define IDR_START 13 namespace { constexpr const wchar_t kWindowClassName[] = L"O2OA"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); FreeLibrary(user32_module); } } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = { static_cast(origin.x), static_cast(origin.y) }; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } return OnCreate(); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } HMENU hmenu; LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { //NOTIFYICONDATA nid; // UINT WM_TASKBARCREATED; // POINT pt; //int xx; //WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated")); switch (message) { case WM_USER: //if (lparam == WM_LBUTTONDOWN) { // Shell_NotifyIcon(NIM_DELETE, &m_trayIcon); // ShowWindow(hwnd, SW_SHOWNORMAL); //} // 双击恢复主界面窗口 if (lparam == WM_LBUTTONDBLCLK) { SetForegroundWindow(hwnd); ShowWindow(hwnd, SW_SHOWNORMAL); } // 右键显示菜单 if (lparam == WM_RBUTTONDOWN) { POINT pt; int xx; GetCursorPos(&pt); ::SetForegroundWindow(hwnd); //EnableMenuItem(hmenu, IDR_PAUSE, MF_GRAYED); xx = TrackPopupMenu(hmenu, TPM_RETURNCMD, pt.x, pt.y, NULL, hwnd, NULL); if (xx == IDR_PAUSE) {// 恢复主界面窗口 SetForegroundWindow(hwnd); ShowWindow(hwnd, SW_SHOWNORMAL); } if (xx == IDR_START) {// 退出程序 Win32Window::quitAndDestroy(hwnd); } if (xx == 0) PostMessage(hwnd, WM_LBUTTONDOWN, NULL, NULL); } return 0; case WM_DESTROY: printf("dddd WM_DESTROY 这里好像执行不到 "); Win32Window::quitAndDestroy(hwnd); //window_handle_ = nullptr; //Destroy(); //if (quit_on_close_) { // Shell_NotifyIcon(NIM_DELETE, &nid); // PostQuitMessage(0); //} return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { if (wparam == SIZE_MINIMIZED) { printf("ssssss WM_SIZE 最小化到托盘"); Win32Window::AddTrayIcon(hwnd); } RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; } //if (message == WM_TASKBARCREATED) { // SendMessage(hwnd, WM_CREATE, wparam, lparam); //} return DefWindowProc(window_handle_, message, wparam, lparam); } // 退出程序 删除托盘图标 void Win32Window::quitAndDestroy(HWND hwnd) { window_handle_ = nullptr; Destroy(); if (quit_on_close_) { Shell_NotifyIcon(NIM_DELETE, &m_trayIcon); PostQuitMessage(0); } } // 添加托盘图标 void Win32Window::AddTrayIcon(HWND hwnd) { memset(&m_trayIcon, 0, sizeof(NOTIFYICONDATA)); m_trayIcon.cbSize = sizeof(NOTIFYICONDATA); //m_trayIcon.hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); //m_trayIcon.hWnd = m_hWnd; //m_trayIcon.cbSize = sizeof(m_trayIcon); m_trayIcon.hWnd = hwnd; //m_trayIcon.uID = 0; m_trayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; m_trayIcon.uCallbackMessage = WM_USER; m_trayIcon.hIcon = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_APP_ICON)); lstrcpy(m_trayIcon.szTip, kWindowClassName); Shell_NotifyIcon(NIM_ADD, &m_trayIcon); hmenu = CreatePopupMenu();// AppendMenu(hmenu, MF_STRING, IDR_PAUSE, L"打开"); AppendMenu(hmenu, MF_STRING, IDR_START, L"退出"); ShowWindow(hwnd, SW_HIDE); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. }