CppXAML
Loading...
Searching...
No Matches
XamlWindow.h
Go to the documentation of this file.
1#pragma once
2#include <winrt/base.h>
3#include <winrt/Windows.UI.Xaml.h>
4#include <winrt/Windows.UI.Xaml.Hosting.h>
5#include <Windows.UI.Xaml.Hosting.DesktopWindowXamlSource.h>
6#include <mutex>
7
16namespace cppxaml {
17 struct XamlWindow;
18
23 public:
27 void (*OnUICreated)(winrt::Windows::UI::Xaml::UIElement content, XamlWindow* xw) { nullptr };
28 LRESULT(*WndProc)(HWND, INT, WPARAM, LPARAM, XamlWindow*) { nullptr };
29
35 AppController(HINSTANCE hInst, winrt::Windows::UI::Xaml::Application xapp) {
36 m_hInstance = hInst;
37 m_xapp = xapp;
38 m_winxamlmanager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
39 }
40
41 HINSTANCE HInstance() const {
42 return m_hInstance;
43 }
44
45 private:
46 winrt::Windows::UI::Xaml::Application m_xapp{ nullptr };
47 HINSTANCE m_hInstance{ nullptr };
48 winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager m_winxamlmanager{ nullptr };
49 };
50
54 struct XamlWindow {
55 private:
56 XamlWindow(std::wstring_view id) : m_Id(id) {}
57 winrt::Windows::UI::Xaml::UIElement(*m_getUI) (const XamlWindow& xw) { nullptr };
58
59 // This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
60 // to host WinRT XAML controls in any UI element that is associated with a window handle (HWND).
61 winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource m_desktopXamlSource{ nullptr };
62 HWND m_hWnd{ nullptr };
63 HACCEL m_hAccelTable{ nullptr };
64
65 AppController* m_controller{ nullptr };
66 std::wstring m_Id;
67 std::wstring m_markup;
68 winrt::Windows::UI::Xaml::UIElement m_ui{ nullptr };
69
70 static inline std::unordered_map<std::wstring, XamlWindow> s_windows{};
71 public:
72 XamlWindow(const XamlWindow&) = delete;
73 XamlWindow(XamlWindow&& other) noexcept :
74 m_Id(std::move(other.m_Id)),
75 m_getUI(std::move(other.m_getUI)),
76 m_markup(std::move(other.m_markup)),
77 m_desktopXamlSource(std::move(other.m_desktopXamlSource)),
78 m_hWnd(std::move(other.m_hWnd)),
79 m_hAccelTable(std::move(m_hAccelTable)),
80 m_controller(std::move(other.m_controller))
81 {}
82
87 HWND hwnd() const {
88 return m_hWnd;
89 }
90
96 template<typename T = winrt::Windows::UI::Xaml::UIElement>
97 T GetUIElement() const {
98 return m_ui.as<T>();
99 }
100
101
113 template<typename TUIElement>
114 static XamlWindow& Make(std::wstring_view id, AppController* controller = nullptr) {
115 XamlWindow xw(id);
116 xw.m_controller = controller;
117 xw.m_getUI = [](const XamlWindow&) { return TUIElement().as<winrt::Windows::UI::Xaml::UIElement>(); };
118 const auto& entry = s_windows.emplace(id, std::move(xw));
119 return entry.first->second;
120 }
121
137 static XamlWindow& Make(std::wstring_view id, std::wstring_view markup, AppController* c = nullptr) {
138 XamlWindow xw(id);
139 xw.m_controller = c;
140 xw.m_markup = markup;
141 xw.m_getUI = [](const XamlWindow& xw) {
142 return winrt::Windows::UI::Xaml::Markup::XamlReader::Load(xw.m_markup)
143 .as<winrt::Windows::UI::Xaml::UIElement>();
144 };
145 const auto& entry = s_windows.emplace(id, std::move(xw));
146 return entry.first->second;
147 }
148
161 static XamlWindow& Make(std::wstring_view id, winrt::Windows::UI::Xaml::UIElement(*getUI)(const XamlWindow&), AppController* c = nullptr) {
162 XamlWindow xw(id);
163 xw.m_controller = c;
164 xw.m_getUI = getUI;
165 const auto& entry = s_windows.emplace(id, std::move(xw));
166 return entry.first->second;
167 }
168
173 std::wstring_view Id() const {
174 return m_Id;
175 }
176
182 static XamlWindow& Get(std::wstring_view id) {
183 return s_windows.at(std::wstring(id));
184 }
185 static constexpr wchar_t const* const WindowClass() {
186 return L"XamlWindow";
187 }
188
199 HWND Create(wchar_t const* szTitle, DWORD style, HWND parent = nullptr, int width = CW_USEDEFAULT, int height = CW_USEDEFAULT, int nCmdShow = SW_NORMAL) {
200 static std::once_flag once;
201
202 std::call_once(once, [ctl = this->m_controller]() {
203 WNDCLASSEXW wcex{};
204 wcex.cbSize = sizeof(wcex);
205
206 wcex.style = CS_HREDRAW | CS_VREDRAW;
207 wcex.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT
208 {
209 // Get handle to the core window.
210 auto xw = reinterpret_cast<XamlWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
211 if (xw == nullptr && message == WM_CREATE) {
212 auto createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
213
214 xw = reinterpret_cast<XamlWindow*>(createStruct->lpCreateParams);
215 SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(xw));
216 }
217
218
219 return xw ? xw->WndProc(hWnd, message, wParam, lParam) : DefWindowProc(hWnd, message, wParam, lParam);
220 };
221
222 wcex.cbWndExtra = sizeof(XamlWindow*);
223 wcex.hInstance = ctl->HInstance();
224 wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
225 wcex.lpszClassName = WindowClass();
226 winrt::check_bool(RegisterClassExW(&wcex) != 0);
227 });
228
229 m_desktopXamlSource = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource();
230 auto hWnd = CreateWindowW(WindowClass(), szTitle, style,
231 CW_USEDEFAULT, CW_USEDEFAULT, width, height, parent, nullptr, m_controller->HInstance(), this);
232 if (hWnd) {
233 ShowWindow(hWnd, nCmdShow);
234 UpdateWindow(hWnd);
235 }
236 return hWnd;
237 }
238
243 void SetAcceleratorTable(HACCEL acc) {
244 m_hAccelTable = acc;
245 }
246
252 return m_controller;
253 }
254
259 int RunLoop() {
260 MSG msg;
261
262 // Main message loop:
263 while (GetMessage(&msg, nullptr, 0, 0))
264 {
265 if (auto xamlSourceNative2 = m_desktopXamlSource.as<IDesktopWindowXamlSourceNative2>()) {
266 BOOL xamlSourceProcessedMessage = FALSE;
267 winrt::check_hresult(xamlSourceNative2->PreTranslateMessage(&msg, &xamlSourceProcessedMessage));
268 if (xamlSourceProcessedMessage) {
269 continue;
270 }
271 }
272
273 if (!TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
274 {
275 TranslateMessage(&msg);
276 DispatchMessage(&msg);
277 }
278 }
279 return (int)msg.wParam;
280 }
281
282 HWND GetBridgeWindow() const {
283 static HWND hWndXamlIsland = nullptr;
284 if (!hWndXamlIsland) {
285 auto interop = m_desktopXamlSource.as<IDesktopWindowXamlSourceNative>();
286 winrt::check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
287 }
288 return hWndXamlIsland;
289 }
290
291 LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
292 auto interop = m_desktopXamlSource.as<IDesktopWindowXamlSourceNative>();
293
294 switch (message)
295 {
296 case WM_CREATE: {
297 this->m_hWnd = hwnd;
298 auto createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
299
300 // Parent the DesktopWindowXamlSource object to the current window.
301 winrt::check_hresult(interop->AttachToWindow(m_hWnd)); // This fails due to access violation!
302
303 this->m_ui = this->m_getUI(*this);
304 if (m_controller && m_controller->OnUICreated) {
305 m_controller->OnUICreated(m_ui, this);
306 }
307 m_desktopXamlSource.Content(m_ui);
308 break;
309 }
310 case WM_SIZE:
311 {
312 HWND hWndXamlIsland = nullptr;
313 winrt::check_hresult(interop->get_WindowHandle(&hWndXamlIsland));
314
315 SetWindowPos(hWndXamlIsland, nullptr, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_SHOWWINDOW);
316
317 break;
318 }
319 case WM_NCDESTROY:
320 {
321 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)nullptr);
322 break;
323 }
324 }
325 if (m_controller && m_controller->WndProc) {
326 return m_controller->WndProc(hwnd, message, wParam, lParam, this);
327 }
328 else return DefWindowProc(hwnd, message, wParam, lParam);
329
330 }
331 };
332}
The main CppXAML namespace.
AppController is responsible for coordinating XamlWindow instances, can extend their wndproc,...
Definition: XamlWindow.h:22
AppController(HINSTANCE hInst, winrt::Windows::UI::Xaml::Application xapp)
Definition: XamlWindow.h:35
void(* OnUICreated)(winrt::Windows::UI::Xaml::UIElement content, XamlWindow *xw)
App-provided callback to be called when any of this controller's windows create their UI (usually Pag...
Definition: XamlWindow.h:27
Implements an HWND based host for XAML Islands. You can create a XamlWindow from one of three overloa...
Definition: XamlWindow.h:54
static XamlWindow & Make(std::wstring_view id, AppController *controller=nullptr)
Creates a window that hosts a XAML UI element.
Definition: XamlWindow.h:114
static XamlWindow & Get(std::wstring_view id)
returns the XamlWindow corresponding to the id.
Definition: XamlWindow.h:182
AppController * Controller() const
Definition: XamlWindow.h:251
static XamlWindow & Make(std::wstring_view id, std::wstring_view markup, AppController *c=nullptr)
Creates a window that hosts XAML UI, based on some markup provided as an input parameter.
Definition: XamlWindow.h:137
HWND hwnd() const
returns the HWND backing the XamlWindow.
Definition: XamlWindow.h:87
T GetUIElement() const
returns the XAML UI that the XamlWindow was created with.
Definition: XamlWindow.h:97
int RunLoop()
Definition: XamlWindow.h:259
HWND Create(wchar_t const *szTitle, DWORD style, HWND parent=nullptr, int width=CW_USEDEFAULT, int height=CW_USEDEFAULT, int nCmdShow=SW_NORMAL)
Call this function to create the actual window. Afterwards, you will call XamlWindow::RunLoop to proc...
Definition: XamlWindow.h:199
void SetAcceleratorTable(HACCEL acc)
Definition: XamlWindow.h:243
std::wstring_view Id() const
returns the window's id
Definition: XamlWindow.h:173
static XamlWindow & Make(std::wstring_view id, winrt::Windows::UI::Xaml::UIElement(*getUI)(const XamlWindow &), AppController *c=nullptr)
Creates a window that hosts XAML UI. The UI will be provided by the app.
Definition: XamlWindow.h:161