aboutsummaryrefslogtreecommitdiff
path: root/src/samples/thmviewer/display.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/samples/thmviewer/display.cpp')
-rw-r--r--src/samples/thmviewer/display.cpp354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/samples/thmviewer/display.cpp b/src/samples/thmviewer/display.cpp
new file mode 100644
index 00000000..52fa3cf8
--- /dev/null
+++ b/src/samples/thmviewer/display.cpp
@@ -0,0 +1,354 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5static const LPCWSTR THMVWR_WINDOW_CLASS_DISPLAY = L"ThmViewerDisplay";
6
7struct DISPLAY_THREAD_CONTEXT
8{
9 HWND hWnd;
10 HINSTANCE hInstance;
11
12 HANDLE hInit;
13};
14
15static DWORD WINAPI DisplayThreadProc(
16 __in LPVOID pvContext
17 );
18static LRESULT CALLBACK DisplayWndProc(
19 __in HWND hWnd,
20 __in UINT uMsg,
21 __in WPARAM wParam,
22 __in LPARAM lParam
23 );
24static BOOL DisplayOnCreate(
25 __in THEME* pTheme,
26 __in HWND hWnd
27 );
28
29
30extern "C" HRESULT DisplayStart(
31 __in HINSTANCE hInstance,
32 __in HWND hWnd,
33 __out HANDLE *phThread,
34 __out DWORD* pdwThreadId
35 )
36{
37 HRESULT hr = S_OK;
38 HANDLE rgHandles[2] = { };
39 DISPLAY_THREAD_CONTEXT context = { };
40
41 rgHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
42 ExitOnNullWithLastError(rgHandles[0], hr, "Failed to create load init event.");
43
44 context.hWnd = hWnd;
45 context.hInstance = hInstance;
46 context.hInit = rgHandles[0];
47
48 rgHandles[1] = ::CreateThread(NULL, 0, DisplayThreadProc, reinterpret_cast<LPVOID>(&context), 0, pdwThreadId);
49 ExitOnNullWithLastError(rgHandles[1], hr, "Failed to create display thread.");
50
51 ::WaitForMultipleObjects(countof(rgHandles), rgHandles, FALSE, INFINITE);
52
53 *phThread = rgHandles[1];
54 rgHandles[1] = NULL;
55
56LExit:
57 ReleaseHandle(rgHandles[1]);
58 ReleaseHandle(rgHandles[0]);
59 return hr;
60}
61
62static DWORD WINAPI DisplayThreadProc(
63 __in LPVOID pvContext
64 )
65{
66 HRESULT hr = S_OK;
67
68 DISPLAY_THREAD_CONTEXT* pContext = static_cast<DISPLAY_THREAD_CONTEXT*>(pvContext);
69 HINSTANCE hInstance = pContext->hInstance;
70 HWND hwndParent = pContext->hWnd;
71
72 // We can signal the initialization event as soon as we have copied the context
73 // values into local variables.
74 ::SetEvent(pContext->hInit);
75
76 BOOL fComInitialized = FALSE;
77
78 HANDLE_THEME* pCurrentHandle = NULL;
79 ATOM atomWc = 0;
80 WNDCLASSW wc = { }; // the following are constant for the display window class.
81 wc.lpfnWndProc = DisplayWndProc;
82 wc.hInstance = hInstance;
83 wc.lpszClassName = THMVWR_WINDOW_CLASS_DISPLAY;
84
85 HWND hWnd = NULL;
86 RECT rc = { };
87 int x = CW_USEDEFAULT;
88 int y = CW_USEDEFAULT;
89
90 BOOL fRedoMsg = FALSE;
91 BOOL fRet = FALSE;
92 MSG msg = { };
93
94 BOOL fCreateIfNecessary = FALSE;
95
96 hr = ::CoInitialize(NULL);
97 ExitOnFailure(hr, "Failed to initialize COM on display thread.");
98 fComInitialized = TRUE;
99
100 // As long as the parent window is alive and kicking, keep this thread going (with or without a theme to display ).
101 while (::IsWindow(hwndParent))
102 {
103 if (pCurrentHandle && fCreateIfNecessary)
104 {
105 THEME* pTheme = pCurrentHandle->pTheme;
106
107 if (CW_USEDEFAULT == x && CW_USEDEFAULT == y && ::GetWindowRect(hwndParent, &rc))
108 {
109 x = rc.left;
110 y = rc.bottom + 20;
111 }
112
113 hr = ThemeCreateParentWindow(pTheme, 0, wc.lpszClassName, pTheme->sczCaption, pTheme->dwStyle, x, y, hwndParent, hInstance, pCurrentHandle, THEME_WINDOW_INITIAL_POSITION_DEFAULT, &hWnd);
114 ExitOnFailure(hr, "Failed to create display window.");
115
116 fCreateIfNecessary = FALSE;
117 }
118
119 // message pump
120 while (fRedoMsg || 0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
121 {
122 if (fRedoMsg)
123 {
124 fRedoMsg = FALSE;
125 }
126
127 if (-1 == fRet)
128 {
129 hr = E_UNEXPECTED;
130 ExitOnFailure(hr, "Unexpected return value from display message pump.");
131 }
132 else if (NULL == msg.hwnd) // Thread message.
133 {
134 if (WM_THMVWR_NEW_THEME == msg.message)
135 {
136 // If there is already a handle, release it.
137 if (pCurrentHandle)
138 {
139 DecrementHandleTheme(pCurrentHandle);
140 pCurrentHandle = NULL;
141 }
142
143 // If the window was created, remember its window location before we destroy
144 // it so so we can open the new window in the same place.
145 if (::IsWindow(hWnd))
146 {
147 ::GetWindowRect(hWnd, &rc);
148 x = rc.left;
149 y = rc.top;
150
151 ::DestroyWindow(hWnd);
152 }
153
154 // If the display window class was registered, unregister it so we can
155 // reuse the same window class name for the new theme.
156 if (atomWc)
157 {
158 if (!::UnregisterClassW(reinterpret_cast<LPCWSTR>(atomWc), hInstance))
159 {
160 DWORD er = ::GetLastError();
161 er = er;
162 }
163
164 atomWc = 0;
165 }
166
167 // If we were provided a new theme handle, create a new window class to
168 // support it.
169 pCurrentHandle = reinterpret_cast<HANDLE_THEME*>(msg.lParam);
170 if (pCurrentHandle)
171 {
172 wc.hIcon = reinterpret_cast<HICON>(pCurrentHandle->pTheme->hIcon);
173 wc.hCursor = ::LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
174 if (0 < pCurrentHandle->pTheme->cFonts)
175 {
176 wc.hbrBackground = pCurrentHandle->pTheme->rgFonts[pCurrentHandle->pTheme->dwFontId].hBackground;
177 }
178 atomWc = ::RegisterClassW(&wc);
179 if (!atomWc)
180 {
181 ExitWithLastError(hr, "Failed to register display window class.");
182 }
183 }
184 }
185 else if (WM_THMVWR_SHOWPAGE == msg.message)
186 {
187 if (pCurrentHandle && ::IsWindow(hWnd) && pCurrentHandle->pTheme->hwndParent == hWnd)
188 {
189 DWORD dwPageId = static_cast<DWORD>(msg.lParam);
190 int nCmdShow = static_cast<int>(msg.wParam);
191
192 // First show/hide the controls not associated with a page.
193 for (DWORD i = 0; i < pCurrentHandle->pTheme->cControls; ++i)
194 {
195 THEME_CONTROL* pControl = pCurrentHandle->pTheme->rgControls + i;
196 if (!pControl->wPageId)
197 {
198 ThemeShowControl(pCurrentHandle->pTheme, pControl->wId, nCmdShow);
199 }
200 }
201
202 // If a page id was provided also, show/hide those controls
203 if (dwPageId)
204 {
205 // Ignore error since we aren't using variables and it can only fail when using variables.
206 ThemeShowPage(pCurrentHandle->pTheme, dwPageId, nCmdShow);
207 }
208 }
209 else // display window isn't visible or it doesn't match the current handle.
210 {
211 // Keep the current message around to try again after we break out of this loop
212 // and create the window.
213 fRedoMsg = TRUE;
214 fCreateIfNecessary = TRUE;
215 break;
216 }
217 }
218 }
219 else if (!ThemeHandleKeyboardMessage(pCurrentHandle->pTheme, hwndParent, &msg)) // Window message.
220 {
221 ::TranslateMessage(&msg);
222 ::DispatchMessageW(&msg);
223 }
224 }
225 }
226
227LExit:
228 if (::IsWindow(hWnd))
229 {
230 ::DestroyWindow(hWnd);
231 }
232
233 if (atomWc)
234 {
235 if (!::UnregisterClassW(THMVWR_WINDOW_CLASS_DISPLAY, hInstance))
236 {
237 DWORD er = ::GetLastError();
238 er = er;
239 }
240 }
241
242 DecrementHandleTheme(pCurrentHandle);
243
244 if (fComInitialized)
245 {
246 ::CoUninitialize();
247 }
248
249 return hr;
250}
251
252static LRESULT CALLBACK DisplayWndProc(
253 __in HWND hWnd,
254 __in UINT uMsg,
255 __in WPARAM wParam,
256 __in LPARAM lParam
257 )
258{
259 static DWORD dwProgress = 0;
260 HANDLE_THEME* pHandleTheme = reinterpret_cast<HANDLE_THEME*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
261
262 switch (uMsg)
263 {
264 case WM_NCCREATE:
265 {
266 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
267 pHandleTheme = reinterpret_cast<HANDLE_THEME*>(lpcs->lpCreateParams);
268 IncrementHandleTheme(pHandleTheme);
269 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pHandleTheme));
270 }
271 break;
272
273 case WM_CREATE:
274 if (!DisplayOnCreate(pHandleTheme->pTheme, hWnd))
275 {
276 return -1;
277 }
278 break;
279
280 case WM_TIMER:
281 if (!lParam && SUCCEEDED(ThemeSetProgressControl(pHandleTheme->pTheme, wParam, dwProgress)))
282 {
283 dwProgress += rand() % 10 + 1;
284 if (dwProgress > 100)
285 {
286 dwProgress = 0;
287 }
288
289 return 0;
290 }
291 break;
292
293 case WM_COMMAND:
294 {
295 WCHAR wzText[1024];
296 ::StringCchPrintfW(wzText, countof(wzText), L"Command %u\r\n", LOWORD(wParam));
297 OutputDebugStringW(wzText);
298 //::MessageBoxW(hWnd, wzText, L"Command fired", MB_OK);
299 }
300 break;
301
302 case WM_SYSCOMMAND:
303 {
304 WCHAR wzText[1024];
305 ::StringCchPrintfW(wzText, countof(wzText), L"SysCommand %u\r\n", LOWORD(wParam));
306 OutputDebugStringW(wzText);
307 //::MessageBoxW(hWnd, wzText, L"Command fired", MB_OK);
308 }
309 break;
310
311 case WM_DESTROY:
312 ThemeUnloadControls(pHandleTheme->pTheme);
313 ::PostQuitMessage(0);
314 break;
315
316 case WM_NCDESTROY:
317 DecrementHandleTheme(pHandleTheme);
318 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0);
319 break;
320 }
321
322 return ThemeDefWindowProc(pHandleTheme ? pHandleTheme->pTheme : NULL, hWnd, uMsg, wParam, lParam);
323}
324
325static BOOL DisplayOnCreate(
326 __in THEME* pTheme,
327 __in HWND hWnd
328 )
329{
330 HRESULT hr = S_OK;
331
332 hr = ThemeLoadControls(pTheme, NULL, 0);
333 ExitOnFailure(hr, "Failed to load theme controls");
334
335 // Pre-populate some control types with data.
336 for (DWORD i = 0; i < pTheme->cControls; ++i)
337 {
338 THEME_CONTROL* pControl = pTheme->rgControls + i;
339 if (THEME_CONTROL_TYPE_RICHEDIT == pControl->type)
340 {
341 hr = ThemeLoadRichEditFromResource(pTheme, pControl->wId, MAKEINTRESOURCEA(THMVWR_RES_RICHEDIT_FILE), ::GetModuleHandleW(NULL));
342 ExitOnFailure(hr, "Failed to load richedit text.");
343 }
344 else if (THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type)
345 {
346 DWORD dwId = ::SetTimer(hWnd, pControl->wId, 500, NULL);
347 dwId = dwId; // prevents warning in "ship" build.
348 Assert(dwId == pControl->wId);
349 }
350 }
351
352LExit:
353 return SUCCEEDED(hr);
354}