-
Notifications
You must be signed in to change notification settings - Fork 500
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
一个线程内不能创建多个 XAML Islands 窗口
- Loading branch information
Showing
17 changed files
with
326 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include "pch.h" | ||
#include "ToastPage.h" | ||
#if __has_include("ToastPage.g.cpp") | ||
#include "ToastPage.g.cpp" | ||
#endif | ||
|
||
namespace winrt::Magpie::App::implementation { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#pragma once | ||
#include "ToastPage.g.h" | ||
|
||
namespace winrt::Magpie::App::implementation { | ||
struct ToastPage : ToastPageT<ToastPage> { | ||
|
||
}; | ||
} | ||
|
||
namespace winrt::Magpie::App::factory_implementation { | ||
struct ToastPage : ToastPageT<ToastPage, implementation::ToastPage> { | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Magpie.App { | ||
[default_interface] | ||
runtimeclass ToastPage : Windows.UI.Xaml.Controls.Page { | ||
ToastPage(); | ||
|
||
// https://github.com/microsoft/microsoft-ui-xaml/issues/7579 | ||
void UnloadObject(Windows.UI.Xaml.DependencyObject object); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<Page x:Class="Magpie.App.ToastPage" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:local="using:Magpie.App" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls" | ||
mc:Ignorable="d"> | ||
<muxc:TeachingTip x:Name="MessageTeachingTip" | ||
PreferredPlacement="Center" | ||
ShouldConstrainToRootBounds="False"> | ||
<TextBlock x:Name="MessageTextBlock" | ||
Text="test测试测试测试测试测试测试" /> | ||
</muxc:TeachingTip> | ||
</Page> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#include "pch.h" | ||
#include "ToastService.h" | ||
#include "XamlHostingHelper.h" | ||
#include "CommonSharedConstants.h" | ||
#include "Utils.h" | ||
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h> | ||
|
||
using namespace winrt; | ||
using namespace Windows::UI::Xaml::Controls; | ||
using namespace Windows::UI::Xaml::Hosting; | ||
|
||
namespace winrt::Magpie::App { | ||
|
||
void ToastService::Initialize() noexcept { | ||
_toastThread = std::thread(std::bind_front(&ToastService::_ToastThreadProc, this)); | ||
} | ||
|
||
void ToastService::Uninitialize() noexcept { | ||
if (!_toastThread.joinable()) { | ||
return; | ||
} | ||
|
||
const HANDLE hToastThread = _toastThread.native_handle(); | ||
|
||
if (!wil::handle_wait(hToastThread, 0)) { | ||
const DWORD threadId = GetThreadId(hToastThread); | ||
|
||
// 持续尝试直到 _toastThread 创建了消息队列 | ||
while (!PostThreadMessage(threadId, CommonSharedConstants::WM_TOAST_QUIT, 0, 0)) { | ||
if (wil::handle_wait(hToastThread, 1)) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
_toastThread.join(); | ||
} | ||
|
||
void ToastService::_ToastThreadProc() noexcept { | ||
#ifdef _DEBUG | ||
SetThreadDescription(GetCurrentThread(), L"Toast 线程"); | ||
#endif | ||
|
||
winrt::init_apartment(winrt::apartment_type::single_threaded); | ||
|
||
static Utils::Ignore _ = [] { | ||
WNDCLASSEXW wcex{ | ||
.cbSize = sizeof(wcex), | ||
.lpfnWndProc = DefWindowProc, | ||
.hInstance = wil::GetModuleInstanceHandle(), | ||
.lpszClassName = CommonSharedConstants::TOAST_WINDOW_CLASS_NAME | ||
}; | ||
RegisterClassEx(&wcex); | ||
|
||
return Utils::Ignore(); | ||
}(); | ||
|
||
// 创建窗口失败也应进入消息循环。Win10 中关闭任意线程的 DesktopWindowXamlSource 都会使主线程会崩溃, | ||
// 在程序退出前,xamlSource 不能析构。见 https://github.com/microsoft/terminal/pull/15397 | ||
HWND hwndToast = CreateWindowEx( | ||
WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW, | ||
CommonSharedConstants::TOAST_WINDOW_CLASS_NAME, | ||
L"Toast", | ||
WS_POPUP | WS_VISIBLE, | ||
200, 200, 0, 0, | ||
NULL, | ||
NULL, | ||
wil::GetModuleInstanceHandle(), | ||
nullptr | ||
); | ||
|
||
// DesktopWindowXamlSource 在控件之前创建则无需调用 WindowsXamlManager::InitializeForCurrentThread | ||
DesktopWindowXamlSource xamlSource; | ||
com_ptr<IDesktopWindowXamlSourceNative2> xamlSourceNative2 = | ||
xamlSource.try_as<IDesktopWindowXamlSourceNative2>(); | ||
|
||
xamlSourceNative2->AttachToWindow(hwndToast); | ||
|
||
HWND hwndXamlIsland; | ||
xamlSourceNative2->get_WindowHandle(&hwndXamlIsland); | ||
SetWindowPos(hwndXamlIsland, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW); | ||
|
||
ToastPage toastPage; | ||
xamlSource.Content(toastPage); | ||
|
||
auto tt = toastPage.FindName(L"MessageTeachingTip").as<MUXC::TeachingTip>(); | ||
tt.IsOpen(true); | ||
|
||
MSG msg; | ||
while (GetMessage(&msg, nullptr, 0, 0)) { | ||
if (msg.message == CommonSharedConstants::WM_TOAST_QUIT) { | ||
DestroyWindow(hwndToast); | ||
break; | ||
} | ||
|
||
{ | ||
BOOL processed = FALSE; | ||
HRESULT hr = xamlSourceNative2->PreTranslateMessage(&msg, &processed); | ||
if (SUCCEEDED(hr) && processed) { | ||
continue; | ||
} | ||
} | ||
|
||
TranslateMessage(&msg); | ||
DispatchMessage(&msg); | ||
} | ||
|
||
// 必须手动重置 Content,否则会内存泄露 | ||
xamlSource.Content(nullptr); | ||
xamlSource.Close(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
#include <winrt/Magpie.App.h> | ||
|
||
namespace winrt::Magpie::App { | ||
|
||
class ToastService { | ||
public: | ||
static ToastService& Get() noexcept { | ||
static ToastService instance; | ||
return instance; | ||
} | ||
|
||
ToastService(const ToastService&) = delete; | ||
ToastService(ToastService&&) = delete; | ||
|
||
void Initialize() noexcept; | ||
|
||
void Uninitialize() noexcept; | ||
|
||
private: | ||
ToastService() = default; | ||
|
||
void _ToastThreadProc() noexcept; | ||
|
||
std::thread _toastThread; | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#include "pch.h" | ||
#include "XamlHostingHelper.h" | ||
#include <CoreWindow.h> | ||
#include "Win32Utils.h" | ||
|
||
using namespace winrt; | ||
using namespace Windows::UI::Xaml::Hosting; | ||
|
||
namespace winrt::Magpie::App { | ||
|
||
XamlHostingHelper::ManagerWrapper::ManagerWrapper() { | ||
_windowsXamlManager = WindowsXamlManager::InitializeForCurrentThread(); | ||
|
||
if (!Win32Utils::GetOSVersion().IsWin11()) { | ||
// Win10 中隐藏 DesktopWindowXamlSource 窗口 | ||
if (CoreWindow coreWindow = CoreWindow::GetForCurrentThread()) { | ||
HWND hwndDWXS; | ||
coreWindow.as<ICoreWindowInterop>()->get_WindowHandle(&hwndDWXS); | ||
ShowWindow(hwndDWXS, SW_HIDE); | ||
} | ||
} | ||
} | ||
|
||
XamlHostingHelper::ManagerWrapper::~ManagerWrapper() { | ||
if (!_windowsXamlManager) { | ||
return; | ||
} | ||
|
||
_windowsXamlManager.Close(); | ||
|
||
// 做最后的清理,见 | ||
// https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.hosting.windowsxamlmanager.close | ||
MSG msg; | ||
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { | ||
DispatchMessage(&msg); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.