Skip to content

Commit 536935a

Browse files
committed
fix: 修复关闭主窗口时崩溃的问题
1 parent a8508cb commit 536935a

File tree

2 files changed

+34
-32
lines changed

2 files changed

+34
-32
lines changed

‎src/Magpie/MainWindow.cpp‎

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "CaptionButtonsControl.h"
1212
#include "TitleBarControl.h"
1313

14+
using namespace winrt;
1415
using namespace winrt::Magpie::implementation;
1516

1617
namespace Magpie {
@@ -44,9 +45,9 @@ bool MainWindow::Create() noexcept {
4445
return false;
4546
}
4647

47-
_Content(winrt::make_self<winrt::Magpie::implementation::RootPage>());
48+
_Content(make_self<RootPage>());
4849

49-
_appThemeChangedRevoker = App::Get().ThemeChanged(winrt::auto_revoke, [this](bool) { _UpdateTheme(); });
50+
_appThemeChangedRevoker = App::Get().ThemeChanged(auto_revoke, [this](bool) { _UpdateTheme(); });
5051
_UpdateTheme();
5152

5253
_SetInitialMaximized(AppSettings::Get().IsMainWindowMaximized());
@@ -59,7 +60,7 @@ bool MainWindow::Create() noexcept {
5960
(sizeToSet.cx == 0 ? (SWP_NOMOVE | SWP_NOSIZE) : 0) | SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS);
6061

6162
// Xaml 控件加载完成后显示主窗口
62-
Content()->Loaded([this](winrt::IInspectable const&, winrt::RoutedEventArgs const&) {
63+
Content()->Loaded([this](winrt::IInspectable const&, RoutedEventArgs const&) {
6364
if (AppSettings::Get().IsMainWindowMaximized()) {
6465
// ShowWindow(Handle(), SW_SHOWMAXIMIZED) 会显示错误的动画。因此我们以窗口化显示,
6566
// 但位置和大小都和最大化相同,显示完毕后将状态设为最大化。
@@ -119,7 +120,7 @@ bool MainWindow::Create() noexcept {
119120
hInstance,
120121
this
121122
);
122-
SetLayeredWindowAttributes(_hwndTitleBar, 0, 255, LWA_ALPHA);
123+
SetLayeredWindowAttributes(_hwndTitleBar.get(), 0, 255, LWA_ALPHA);
123124

124125
if (Win32Helper::GetOSVersion().IsWin11()) {
125126
// 如果鼠标正位于一个按钮上,贴靠布局弹窗会出现在按钮下方。我们利用这个特性来修正贴靠布局弹窗的位置。
@@ -131,7 +132,7 @@ bool MainWindow::Create() noexcept {
131132
L"",
132133
WS_VISIBLE | WS_CHILD | WS_DISABLED | BS_OWNERDRAW,
133134
0, 0, 0, 0,
134-
_hwndTitleBar,
135+
_hwndTitleBar.get(),
135136
NULL,
136137
hInstance,
137138
NULL
@@ -141,7 +142,7 @@ bool MainWindow::Create() noexcept {
141142
ChangeWindowMessageFilterEx(Handle(), WM_GETTITLEBARINFOEX, MSGFLT_ALLOW, nullptr);
142143
}
143144

144-
Content()->TitleBar().SizeChanged([this](winrt::IInspectable const&, winrt::SizeChangedEventArgs const&) {
145+
Content()->TitleBar().SizeChanged([this](winrt::IInspectable const&, SizeChangedEventArgs const&) {
145146
_ResizeTitleBarWindow();
146147
});
147148

@@ -186,7 +187,7 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
186187

187188
// 在标题栏上按下右键,在其他地方释放也会收到此消息。确保只有在标题栏上释放时才显示菜单
188189
RECT titleBarRect;
189-
GetWindowRect(_hwndTitleBar, &titleBarRect);
190+
GetWindowRect(_hwndTitleBar.get(), &titleBarRect);
190191
if (!PtInRect(&titleBarRect, cursorPt)) {
191192
break;
192193
}
@@ -242,7 +243,8 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
242243
{
243244
AppSettings::Get().Save();
244245
_appThemeChangedRevoker.Revoke();
245-
_hwndTitleBar = NULL;
246+
// 标题栏窗口经常使用 Content(),确保在关闭 DWXS 前销毁
247+
_hwndTitleBar.reset();
246248
_trackingMouse = false;
247249

248250
// 不显示托盘图标时关闭主窗口应退出
@@ -260,8 +262,8 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
260262
}
261263

262264
std::pair<POINT, SIZE> MainWindow::_CreateWindow() noexcept {
263-
const winrt::Point& windowCenter = AppSettings::Get().MainWindowCenter();
264-
winrt::Size windowSizeInDips = AppSettings::Get().MainWindowSizeInDips();
265+
const Point& windowCenter = AppSettings::Get().MainWindowCenter();
266+
Size windowSizeInDips = AppSettings::Get().MainWindowSizeInDips();
265267

266268
POINT windowPos = { CW_USEDEFAULT,CW_USEDEFAULT };
267269
SIZE windowSize{};
@@ -280,7 +282,7 @@ std::pair<POINT, SIZE> MainWindow::_CreateWindow() noexcept {
280282
GetDpiForMonitor(hMon, MDT_EFFECTIVE_DPI, &dpi, &dpi);
281283

282284
const float dpiFactor = dpi / float(USER_DEFAULT_SCREEN_DPI);
283-
const winrt::Size windowSizeInPixels = {
285+
const Size windowSizeInPixels = {
284286
windowSizeInDips.Width * dpiFactor,
285287
windowSizeInDips.Height * dpiFactor
286288
};
@@ -330,7 +332,7 @@ std::pair<POINT, SIZE> MainWindow::_CreateWindow() noexcept {
330332
GetMonitorInfo(hMon, &mi);
331333

332334
const float dpiFactor = CurrentDpi() / float(USER_DEFAULT_SCREEN_DPI);
333-
const winrt::Size workingAreaSizeInDips = {
335+
const Size workingAreaSizeInDips = {
334336
(mi.rcWork.right - mi.rcWork.left) / dpiFactor,
335337
(mi.rcWork.bottom - mi.rcWork.top) / dpiFactor
336338
};
@@ -340,7 +342,7 @@ std::pair<POINT, SIZE> MainWindow::_CreateWindow() noexcept {
340342
windowSizeInDips.Width > workingAreaSizeInDips.Width ||
341343
windowSizeInDips.Height > workingAreaSizeInDips.Height) {
342344
// 默认尺寸
343-
static constexpr winrt::Size DEFAULT_SIZE{ 980.0f, 690.0f };
345+
static constexpr Size DEFAULT_SIZE{ 980.0f, 690.0f };
344346

345347
windowSizeInDips = DEFAULT_SIZE;
346348

@@ -380,7 +382,7 @@ LRESULT MainWindow::_TitleBarWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
380382
if (msg == WM_NCCREATE) {
381383
MainWindow* that = (MainWindow*)(((CREATESTRUCT*)lParam)->lpCreateParams);
382384
assert(that && !that->_hwndTitleBar);
383-
that->_hwndTitleBar = hWnd;
385+
that->_hwndTitleBar.reset(hWnd);
384386
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)that);
385387
} else if (MainWindow* that = (MainWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA)) {
386388
return that->_TitleBarMessageHandler(msg, wParam, lParam);
@@ -399,10 +401,10 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
399401
case WM_NCHITTEST:
400402
{
401403
POINT cursorPos{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
402-
ScreenToClient(_hwndTitleBar, &cursorPos);
404+
ScreenToClient(_hwndTitleBar.get(), &cursorPos);
403405

404406
RECT titleBarClientRect;
405-
GetClientRect(_hwndTitleBar, &titleBarClientRect);
407+
GetClientRect(_hwndTitleBar.get(), &titleBarClientRect);
406408
if (!PtInRect(&titleBarClientRect, cursorPos)) {
407409
// 先检查鼠标是否在窗口内。在标题栏按钮上按下鼠标时我们会捕获光标,从而收到 WM_MOUSEMOVE 和 WM_LBUTTONUP 消息。
408410
// 它们使用 WM_NCHITTEST 测试鼠标位于哪个区域
@@ -423,7 +425,7 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
423425
}
424426
}
425427

426-
static const winrt::Size buttonSizeInDips = [this]() {
428+
static const Size buttonSizeInDips = [this]() {
427429
return Content()->TitleBar().CaptionButtons().CaptionButtonSize();
428430
}();
429431

@@ -453,8 +455,8 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
453455
case WM_MOUSEMOVE:
454456
{
455457
POINT cursorPos{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
456-
ClientToScreen(_hwndTitleBar, &cursorPos);
457-
wParam = SendMessage(_hwndTitleBar, WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
458+
ClientToScreen(_hwndTitleBar.get(), &cursorPos);
459+
wParam = SendMessage(_hwndTitleBar.get(), WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
458460
}
459461
[[fallthrough]];
460462
case WM_NCMOUSEMOVE:
@@ -485,7 +487,7 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
485487
TRACKMOUSEEVENT ev{};
486488
ev.cbSize = sizeof(TRACKMOUSEEVENT);
487489
ev.dwFlags = TME_LEAVE | TME_NONCLIENT;
488-
ev.hwndTrack = _hwndTitleBar;
490+
ev.hwndTrack = _hwndTitleBar.get();
489491
ev.dwHoverTime = HOVER_DEFAULT; // 不关心 HOVER 消息
490492
TrackMouseEvent(&ev);
491493
_trackingMouse = true;
@@ -507,11 +509,11 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
507509
GetCursorPos(&cursorPos);
508510
// 先检查鼠标是否在主窗口上,如果正在显示文字提示,会返回 _hwndTitleBar
509511
HWND hwndUnderCursor = WindowFromPoint(cursorPos);
510-
if (hwndUnderCursor != Handle() && hwndUnderCursor != _hwndTitleBar) {
512+
if (hwndUnderCursor != Handle() && hwndUnderCursor != _hwndTitleBar.get()) {
511513
Content()->TitleBar().CaptionButtons().LeaveButtons();
512514
} else {
513515
// 然后检查鼠标在标题栏上的位置
514-
LRESULT hit = SendMessage(_hwndTitleBar, WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
516+
LRESULT hit = SendMessage(_hwndTitleBar.get(), WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
515517
if (hit != HTMINBUTTON && hit != HTMAXBUTTON && hit != HTCLOSE) {
516518
Content()->TitleBar().CaptionButtons().LeaveButtons();
517519
}
@@ -539,7 +541,7 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
539541
Content()->TitleBar().CaptionButtons().PressButton((CaptionButton)wParam);
540542
// 在标题栏按钮上按下左键后我们便捕获光标,这样才能在释放时得到通知。注意捕获光标后
541543
// 便不会再收到 NC 族消息,这就是为什么我们要处理 WM_MOUSEMOVE 和 WM_LBUTTONUP
542-
SetCapture(_hwndTitleBar);
544+
SetCapture(_hwndTitleBar.get());
543545
break;
544546
}
545547
return 0;
@@ -550,8 +552,8 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
550552
ReleaseCapture();
551553

552554
POINT cursorPos{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
553-
ClientToScreen(_hwndTitleBar, &cursorPos);
554-
wParam = SendMessage(_hwndTitleBar, WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
555+
ClientToScreen(_hwndTitleBar.get(), &cursorPos);
556+
wParam = SendMessage(_hwndTitleBar.get(), WM_NCHITTEST, 0, MAKELPARAM(cursorPos.x, cursorPos.y));
555557
}
556558
[[fallthrough]];
557559
case WM_NCLBUTTONUP:
@@ -586,18 +588,18 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
586588
return SendMessage(Handle(), msg, wParam, lParam);
587589
}
588590

589-
return DefWindowProc(_hwndTitleBar, msg, wParam, lParam);
591+
return DefWindowProc(_hwndTitleBar.get(), msg, wParam, lParam);
590592
}
591593

592594
void MainWindow::_ResizeTitleBarWindow() noexcept {
593-
if (!_hwndTitleBar) {
595+
if (!_hwndTitleBar.get()) {
594596
return;
595597
}
596598

597599
TitleBarControl& titleBar = Content()->TitleBar();
598600

599601
// 获取标题栏的边��矩形
600-
winrt::Rect rect{0.0f, 0.0f, (float)titleBar.ActualWidth(), (float)titleBar.ActualHeight()};
602+
Rect rect{0.0f, 0.0f, (float)titleBar.ActualWidth(), (float)titleBar.ActualHeight()};
601603
rect = titleBar.TransformToVisual(*Content()).TransformBounds(rect);
602604

603605
const float dpiScale = CurrentDpi() / float(USER_DEFAULT_SCREEN_DPI);
@@ -607,7 +609,7 @@ void MainWindow::_ResizeTitleBarWindow() noexcept {
607609
RECT clientRect;
608610
GetClientRect(Handle(), &clientRect);
609611
SetWindowPos(
610-
_hwndTitleBar,
612+
_hwndTitleBar.get(),
611613
HWND_TOP,
612614
0,
613615
0,
@@ -628,8 +630,8 @@ void MainWindow::_ResizeTitleBarWindow() noexcept {
628630
}
629631

630632
// 设置标题栏窗口的最大化样式,这样才能展示正确的文字提示
631-
LONG_PTR style = GetWindowLongPtr(_hwndTitleBar, GWL_STYLE);
632-
SetWindowLongPtr(_hwndTitleBar, GWL_STYLE,
633+
LONG_PTR style = GetWindowLongPtr(_hwndTitleBar.get(), GWL_STYLE);
634+
SetWindowLongPtr(_hwndTitleBar.get(), GWL_STYLE,
633635
_IsMaximized() ? style | WS_MAXIMIZE : style & ~WS_MAXIMIZE);
634636
}
635637

‎src/Magpie/MainWindow.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class MainWindow : public XamlWindowT<MainWindow, winrt::com_ptr<winrt::Magpie::
2929

3030
MultithreadEvent<bool>::EventRevoker _appThemeChangedRevoker;
3131

32-
HWND _hwndTitleBar = NULL;
32+
wil::unique_hwnd _hwndTitleBar;
3333
HWND _hwndMaximizeButton = NULL;
3434
bool _trackingMouse = false;
3535
};

0 commit comments

Comments
 (0)