14289d9b17ab7ea610463689e84e9ef82d564e61
[reactos.git] / reactos / dll / win32 / uxtheme / nonclient.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS uxtheme.dll
4 * FILE: dll/win32/uxtheme/nonclient.c
5 * PURPOSE: uxtheme non client area management
6 * PROGRAMMER: Giannis Adamopoulos
7 */
8
9 #include "uxthemep.h"
10
11 static BOOL
12 IsWindowActive(HWND hWnd, DWORD ExStyle)
13 {
14 BOOL ret;
15
16 if (ExStyle & WS_EX_MDICHILD)
17 {
18 ret = IsChild(GetForegroundWindow(), hWnd);
19 if (ret)
20 ret = (hWnd == (HWND)SendMessageW(GetParent(hWnd), WM_MDIGETACTIVE, 0, 0));
21 }
22 else
23 {
24 ret = (GetForegroundWindow() == hWnd);
25 }
26
27 return ret;
28 }
29
30 BOOL
31 IsScrollBarVisible(HWND hWnd, INT hBar)
32 {
33 SCROLLBARINFO sbi = {sizeof(SCROLLBARINFO)};
34 if(!GetScrollBarInfo(hWnd, hBar, &sbi))
35 return FALSE;
36
37 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
38 }
39
40 static BOOL
41 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
42 {
43 if (Style & WS_MINIMIZE)
44 return TRUE;
45 if (ExStyle & WS_EX_DLGMODALFRAME)
46 return TRUE;
47 if (ExStyle & WS_EX_STATICEDGE)
48 return FALSE;
49 if (Style & WS_THICKFRAME)
50 return TRUE;
51 Style &= WS_CAPTION;
52 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
53 return TRUE;
54 return FALSE;
55 }
56
57 static HICON
58 UserGetWindowIcon(PDRAW_CONTEXT pcontext)
59 {
60 HICON hIcon = NULL;
61
62 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
63
64 if (!hIcon)
65 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
66
67 if (!hIcon)
68 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
69
70 if (!hIcon)
71 hIcon = (HICON)GetClassLong(pcontext->hWnd, GCL_HICONSM);
72
73 if (!hIcon)
74 hIcon = (HICON)GetClassLong(pcontext->hWnd, GCL_HICON);
75
76 // See also win32ss/user/ntuser/nonclient.c!NC_IconForWindow
77 if (!hIcon && !(pcontext->wi.dwExStyle & WS_EX_DLGMODALFRAME))
78 hIcon = LoadIconW(NULL, (LPCWSTR)IDI_WINLOGO);
79
80 return hIcon;
81 }
82
83 HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPartId, int iStateId)
84 {
85 HRESULT hr;
86 HFONT hFont = NULL;
87 HGDIOBJ oldFont = NULL;
88 LOGFONTW logfont;
89 COLORREF textColor;
90 COLORREF oldTextColor;
91 int align = CA_LEFT;
92 int drawStyles = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS;
93
94 WCHAR buffer[50];
95 WCHAR *pszText = buffer;
96 INT len;
97
98 len = InternalGetWindowText(pcontext->hWnd, NULL, 0);
99 if (!len)
100 return S_OK;
101
102 len++; /* From now on this is the size of the buffer so include the null */
103
104 if (len > ARRAYSIZE(buffer))
105 {
106 pszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
107 if (!pszText)
108 return E_OUTOFMEMORY;
109 }
110
111 InternalGetWindowText(pcontext->hWnd, pszText, len);
112
113 hr = GetThemeSysFont(0,TMT_CAPTIONFONT,&logfont);
114 if(SUCCEEDED(hr))
115 hFont = CreateFontIndirectW(&logfont);
116
117 if(hFont)
118 oldFont = SelectObject(pcontext->hDC, hFont);
119
120 if (!pcontext->Active)
121 textColor = GetSysColor(COLOR_INACTIVECAPTIONTEXT);
122 else
123 textColor = GetSysColor(COLOR_CAPTIONTEXT);
124
125 GetThemeEnumValue(pcontext->theme, iPartId, iStateId, TMT_CONTENTALIGNMENT, &align);
126 if (align == CA_CENTER)
127 drawStyles |= DT_CENTER;
128 else if (align == CA_RIGHT)
129 drawStyles |= DT_RIGHT;
130
131 oldTextColor = SetTextColor(pcontext->hDC, textColor);
132 DrawThemeText(pcontext->theme,
133 pcontext->hDC,
134 iPartId,
135 iStateId,
136 pszText,
137 len - 1,
138 drawStyles,
139 0,
140 pRect);
141 SetTextColor(pcontext->hDC, oldTextColor);
142
143 if (hFont)
144 {
145 SelectObject(pcontext->hDC, oldFont);
146 DeleteObject(hFont);
147 }
148 if (pszText != buffer)
149 {
150 HeapFree(GetProcessHeap(), 0, pszText);
151 }
152 return S_OK;
153 }
154
155 void
156 ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
157 HWND hWnd,
158 HRGN hRgn)
159 {
160 pcontext->wi.cbSize = sizeof(pcontext->wi);
161 GetWindowInfo(hWnd, &pcontext->wi);
162 pcontext->hWnd = hWnd;
163 pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle);
164 pcontext->theme = GetNCCaptionTheme(hWnd, pcontext->wi.dwStyle);
165 pcontext->scrolltheme = GetNCScrollbarTheme(hWnd, pcontext->wi.dwStyle);
166
167 pcontext->CaptionHeight = pcontext->wi.cyWindowBorders;
168 pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
169
170 if(hRgn <= (HRGN)1)
171 {
172 hRgn = CreateRectRgnIndirect(&pcontext->wi.rcWindow);
173 }
174 pcontext->hRgn = hRgn;
175
176 pcontext->hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
177 }
178
179 void
180 ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext)
181 {
182 ReleaseDC(pcontext->hWnd ,pcontext->hDC);
183
184 if(pcontext->hRgn != NULL)
185 {
186 DeleteObject(pcontext->hRgn);
187 }
188 }
189
190 static void
191 ThemeStartBufferedPaint(PDRAW_CONTEXT pcontext, int cx, int cy)
192 {
193 HBITMAP hbmp;
194
195 pcontext->hDCScreen = pcontext->hDC;
196 pcontext->hDC = CreateCompatibleDC(pcontext->hDCScreen);
197 hbmp = CreateCompatibleBitmap(pcontext->hDCScreen, cx, cy);
198 pcontext->hbmpOld = (HBITMAP)SelectObject(pcontext->hDC, hbmp);
199 }
200
201 static void
202 ThemeEndBufferedPaint(PDRAW_CONTEXT pcontext, int x, int y, int cx, int cy)
203 {
204 HBITMAP hbmp;
205 BitBlt(pcontext->hDCScreen, 0, 0, cx, cy, pcontext->hDC, x, y, SRCCOPY);
206 hbmp = (HBITMAP) SelectObject(pcontext->hDC, pcontext->hbmpOld);
207 DeleteObject(pcontext->hDC);
208 DeleteObject(hbmp);
209
210 pcontext->hDC = pcontext->hDCScreen;
211 }
212
213 void ThemeCalculateCaptionButtonsPos(HWND hWnd, HTHEME htheme)
214 {
215 PWND_DATA pwndData;
216 DWORD style;
217 INT ButtonWidth, ButtonHeight, iPartId, i;
218 WINDOWINFO wi = {sizeof(wi)};
219 RECT rcCurrent;
220
221 /* First of all check if we have something to do here */
222 style = GetWindowLongW(hWnd, GWL_STYLE);
223 if((style & (WS_CAPTION | WS_SYSMENU)) != (WS_CAPTION | WS_SYSMENU))
224 return;
225
226 /* Get theme data for this window */
227 pwndData = ThemeGetWndData(hWnd);
228 if (pwndData == NULL)
229 return;
230
231 if (!htheme)
232 htheme = pwndData->hthemeWindow;
233
234 if(!GetWindowInfo(hWnd, &wi))
235 return;
236
237 /* Calculate the area of the caption */
238 rcCurrent.top = rcCurrent.left = 0;
239 rcCurrent.right = wi.rcWindow.right - wi.rcWindow.left;
240 rcCurrent.bottom = wi.rcWindow.bottom - wi.rcWindow.top;
241
242 /* Add a padding around the objects of the caption */
243 InflateRect(&rcCurrent, -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE,
244 -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE);
245
246 for (i = CLOSEBUTTON; i <= HELPBUTTON; i++)
247 {
248 SIZE ButtonSize;
249
250 switch(i)
251 {
252 case CLOSEBUTTON:
253 iPartId = wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
254 break;
255
256 case MAXBUTTON:
257 iPartId = wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
258 break;
259
260 case MINBUTTON:
261 iPartId = wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
262 break;
263
264 default:
265 iPartId = WP_HELPBUTTON ;
266 }
267
268 GetThemePartSize(htheme, NULL, iPartId, 0, NULL, TS_MIN, &ButtonSize);
269
270 ButtonHeight = GetSystemMetrics( wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE);
271 ButtonWidth = MulDiv(ButtonSize.cx, ButtonHeight, ButtonSize.cy);
272
273 ButtonHeight -= 4;
274 ButtonWidth -= 4;
275
276 SetRect(&pwndData->rcCaptionButtons[i],
277 rcCurrent.right - ButtonWidth,
278 rcCurrent.top,
279 rcCurrent.right,
280 rcCurrent.top + ButtonHeight);
281
282 rcCurrent.right -= ButtonWidth + BUTTON_GAP_SIZE;
283 }
284 }
285
286 static void
287 ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext,
288 RECT* prcCurrent,
289 CAPTIONBUTTON buttonId,
290 INT iStateId)
291 {
292 INT iPartId;
293 PWND_DATA pwndData = ThemeGetWndData(pcontext->hWnd);
294 if (!pwndData)
295 return;
296
297 switch(buttonId)
298 {
299 case CLOSEBUTTON:
300 iPartId = pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
301 break;
302
303 case MAXBUTTON:
304 if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
305 {
306 if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
307 return;
308 else
309 iStateId = BUTTON_DISABLED;
310 }
311
312 iPartId = pcontext->wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
313 break;
314
315 case MINBUTTON:
316 if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
317 {
318 if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
319 return;
320 else
321 iStateId = BUTTON_DISABLED;
322 }
323
324 iPartId = pcontext->wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
325 break;
326
327 default:
328 //FIXME: Implement Help Button
329 return;
330 }
331
332 if (prcCurrent)
333 prcCurrent->right = pwndData->rcCaptionButtons[buttonId].left;
334
335 DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &pwndData->rcCaptionButtons[buttonId], NULL);
336 }
337
338 static DWORD
339 ThemeGetButtonState(DWORD htCurrect, DWORD htHot, DWORD htDown, BOOL Active)
340 {
341 if (htHot == htCurrect)
342 return BUTTON_HOT;
343 if (!Active)
344 return BUTTON_INACTIVE;
345 if (htDown == htCurrect)
346 return BUTTON_PRESSED;
347
348 return BUTTON_NORMAL;
349 }
350
351 /* Used only from mouse event handlers */
352 static void
353 ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
354 {
355 /* Draw the buttons */
356 ThemeDrawCaptionButton(pcontext, NULL, CLOSEBUTTON,
357 ThemeGetButtonState(HTCLOSE, htHot, htDown, pcontext->Active));
358 ThemeDrawCaptionButton(pcontext, NULL, MAXBUTTON,
359 ThemeGetButtonState(HTMAXBUTTON, htHot, htDown, pcontext->Active));
360 ThemeDrawCaptionButton(pcontext, NULL, MINBUTTON,
361 ThemeGetButtonState(HTMINBUTTON, htHot, htDown, pcontext->Active));
362 ThemeDrawCaptionButton(pcontext, NULL, HELPBUTTON,
363 ThemeGetButtonState(HTHELP, htHot, htDown, pcontext->Active));
364 }
365
366 /* Used from WM_NCPAINT and WM_NCACTIVATE handlers */
367 static void
368 ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
369 {
370 RECT rcPart;
371 int iPart, iState;
372 HICON hIcon;
373
374 // See also win32ss/user/ntuser/nonclient.c!UserDrawCaptionBar
375 // and win32ss/user/ntuser/nonclient.c!UserDrawCaption
376 if ((pcontext->wi.dwStyle & WS_SYSMENU) && !(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW))
377 hIcon = UserGetWindowIcon(pcontext);
378 else
379 hIcon = NULL;
380
381 /* Get the caption part and state id */
382 if (pcontext->wi.dwStyle & WS_MINIMIZE)
383 iPart = WP_MINCAPTION;
384 else if (pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW)
385 iPart = WP_SMALLCAPTION;
386 else if (pcontext->wi.dwStyle & WS_MAXIMIZE)
387 iPart = WP_MAXCAPTION;
388 else
389 iPart = WP_CAPTION;
390
391 iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
392
393 /* Draw the caption background */
394 rcPart = *prcCurrent;
395 rcPart.bottom = rcPart.top + pcontext->CaptionHeight;
396 prcCurrent->top = rcPart.bottom;
397 DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL);
398
399 /* Add a padding around the objects of the caption */
400 InflateRect(&rcPart, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE,
401 -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
402
403 /* Draw the caption buttons */
404 if (pcontext->wi.dwStyle & WS_SYSMENU)
405 {
406 iState = pcontext->Active ? BUTTON_NORMAL : BUTTON_INACTIVE;
407
408 ThemeDrawCaptionButton(pcontext, &rcPart, CLOSEBUTTON, iState);
409 ThemeDrawCaptionButton(pcontext, &rcPart, MAXBUTTON, iState);
410 ThemeDrawCaptionButton(pcontext, &rcPart, MINBUTTON, iState);
411 ThemeDrawCaptionButton(pcontext, &rcPart, HELPBUTTON, iState);
412 }
413
414 rcPart.top += 3 ;
415
416 /* Draw the icon */
417 if (hIcon)
418 {
419 int IconHeight = GetSystemMetrics(SM_CYSMICON);
420 int IconWidth = GetSystemMetrics(SM_CXSMICON);
421 DrawIconEx(pcontext->hDC, rcPart.left, rcPart.top , hIcon, IconWidth, IconHeight, 0, NULL, DI_NORMAL);
422 rcPart.left += IconWidth + 4;
423 }
424
425 rcPart.right -= 4;
426
427 /* Draw the caption */
428 ThemeDrawCaptionText(pcontext, &rcPart, iPart, iState);
429 }
430
431 static void
432 ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
433 {
434 RECT rcPart;
435 int iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
436
437 /* Draw the bottom border */
438 rcPart = *prcCurrent;
439 rcPart.top = rcPart.bottom - pcontext->wi.cyWindowBorders;
440 prcCurrent->bottom = rcPart.top;
441 DrawThemeBackground(pcontext->theme, pcontext->hDC, WP_FRAMEBOTTOM, iState, &rcPart, NULL);
442
443 /* Draw the left border */
444 rcPart = *prcCurrent;
445 rcPart.right = rcPart.left + pcontext->wi.cxWindowBorders ;
446 prcCurrent->left = rcPart.right;
447 DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMELEFT, iState, &rcPart, NULL);
448
449 /* Draw the right border */
450 rcPart = *prcCurrent;
451 rcPart.left = rcPart.right - pcontext->wi.cxWindowBorders;
452 prcCurrent->right = rcPart.left;
453 DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMERIGHT, iState, &rcPart, NULL);
454 }
455
456 static void
457 DrawClassicFrame(PDRAW_CONTEXT context, RECT* prcCurrent)
458 {
459 /* Draw outer edge */
460 if (UserHasWindowEdge(context->wi.dwStyle, context->wi.dwExStyle))
461 {
462 DrawEdge(context->hDC, prcCurrent, EDGE_RAISED, BF_RECT | BF_ADJUST);
463 }
464 else if (context->wi.dwExStyle & WS_EX_STATICEDGE)
465 {
466 DrawEdge(context->hDC, prcCurrent, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
467 }
468
469 /* Firstly the "thick" frame */
470 if ((context->wi.dwStyle & WS_THICKFRAME) && !(context->wi.dwStyle & WS_MINIMIZE))
471 {
472 INT Width =
473 (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
474 GetSystemMetrics(SM_CXBORDER);
475 INT Height =
476 (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
477 GetSystemMetrics(SM_CYBORDER);
478
479 SelectObject(context->hDC, GetSysColorBrush(
480 context->Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
481
482 /* Draw frame */
483 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
484 prcCurrent->right - prcCurrent->left, Height, PATCOPY);
485 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
486 Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
487 PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
488 prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
489 PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
490 -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
491
492 InflateRect(prcCurrent, -Width, -Height);
493 }
494
495 /* Now the other bit of the frame */
496 if (context->wi.dwStyle & (WS_DLGFRAME | WS_BORDER) || (context->wi.dwExStyle & WS_EX_DLGMODALFRAME))
497 {
498 INT Width = GetSystemMetrics(SM_CXBORDER);
499 INT Height = GetSystemMetrics(SM_CYBORDER);
500
501 SelectObject(context->hDC, GetSysColorBrush(
502 (context->wi.dwExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
503 (context->wi.dwExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
504 (context->wi.dwStyle & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
505 COLOR_WINDOWFRAME));
506
507 /* Draw frame */
508 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
509 prcCurrent->right - prcCurrent->left, Height, PATCOPY);
510 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
511 Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
512 PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
513 prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
514 PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
515 -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
516
517 InflateRect(prcCurrent, -Width, -Height);
518 }
519 }
520
521 static void ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
522 {
523 /* Let the window manager paint the menu */
524 prcCurrent->top += PaintMenuBar(pcontext->hWnd,
525 pcontext->hDC,
526 pcontext->wi.cxWindowBorders,
527 pcontext->wi.cxWindowBorders,
528 prcCurrent->top,
529 pcontext->Active);
530 }
531
532 static void ThemeDrawScrollBarsGrip(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
533 {
534 RECT rcPart;
535 HWND hwndParent;
536 RECT ParentClientRect;
537 DWORD ParentStyle;
538
539 rcPart = *prcCurrent;
540
541 if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
542 rcPart.right = rcPart.left + GetSystemMetrics(SM_CXVSCROLL);
543 else
544 rcPart.left = rcPart.right - GetSystemMetrics(SM_CXVSCROLL);
545
546 rcPart.top = rcPart.bottom - GetSystemMetrics(SM_CYHSCROLL);
547
548 FillRect(pcontext->hDC, &rcPart, GetSysColorBrush(COLOR_BTNFACE));
549
550 hwndParent = GetParent(pcontext->hWnd);
551 GetClientRect(hwndParent, &ParentClientRect);
552 ParentStyle = GetWindowLongW(hwndParent, GWL_STYLE);
553
554 if (HASSIZEGRIP(pcontext->wi.dwStyle, pcontext->wi.dwExStyle, ParentStyle, pcontext->wi.rcWindow, ParentClientRect))
555 {
556 int iState;
557 if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
558 iState = pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR;
559 else
560 iState = SZB_RIGHTALIGN;
561 DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, SBP_SIZEBOX, iState, &rcPart, NULL);
562 }
563 }
564
565 static void
566 ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent, BOOL bDoDoubleBuffering)
567 {
568 if(!(pcontext->wi.dwStyle & WS_VISIBLE))
569 return;
570
571 if((pcontext->wi.dwStyle & WS_CAPTION)==WS_CAPTION)
572 {
573 if (bDoDoubleBuffering)
574 ThemeStartBufferedPaint(pcontext, prcCurrent->right, pcontext->CaptionHeight);
575 ThemeDrawCaption(pcontext, prcCurrent);
576 if (bDoDoubleBuffering)
577 ThemeEndBufferedPaint(pcontext, 0, 0, prcCurrent->right, pcontext->CaptionHeight);
578 ThemeDrawBorders(pcontext, prcCurrent);
579 }
580 else
581 {
582 DrawClassicFrame(pcontext, prcCurrent);
583 }
584
585 if(pcontext->wi.dwStyle & WS_MINIMIZE)
586 return;
587
588 if(HAS_MENU(pcontext->hWnd, pcontext->wi.dwStyle))
589 ThemeDrawMenuBar(pcontext, prcCurrent);
590
591 if (pcontext->wi.dwExStyle & WS_EX_CLIENTEDGE)
592 DrawEdge(pcontext->hDC, prcCurrent, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
593
594 if((pcontext->wi.dwStyle & WS_HSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL))
595 ThemeDrawScrollBar(pcontext, SB_HORZ , NULL);
596
597 if((pcontext->wi.dwStyle & WS_VSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
598 ThemeDrawScrollBar(pcontext, SB_VERT, NULL);
599
600 if((pcontext->wi.dwStyle & (WS_HSCROLL|WS_VSCROLL)) == (WS_HSCROLL|WS_VSCROLL) &&
601 IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL) &&
602 IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
603 {
604 ThemeDrawScrollBarsGrip(pcontext, prcCurrent);
605 }
606 }
607
608 /*
609 * Message handlers
610 */
611
612 static LRESULT
613 ThemeHandleNCPaint(HWND hWnd, HRGN hRgn)
614 {
615 DRAW_CONTEXT context;
616 RECT rcCurrent;
617
618 ThemeInitDrawContext(&context, hWnd, hRgn);
619
620 rcCurrent = context.wi.rcWindow;
621 OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
622
623 ThemePaintWindow(&context, &rcCurrent, TRUE);
624 ThemeCleanupDrawContext(&context);
625
626 return 0;
627 }
628
629 static LRESULT
630 ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
631 {
632 DRAW_CONTEXT context;
633 TRACKMOUSEEVENT tme;
634 DWORD style;
635 PWND_DATA pwndData;
636
637 /* First of all check if we have something to do here */
638 style = GetWindowLongW(hWnd, GWL_STYLE);
639 if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
640 return 0;
641
642 /* Get theme data for this window */
643 pwndData = ThemeGetWndData(hWnd);
644 if (pwndData == NULL)
645 return 0;
646
647 /* Begin tracking in the non client area if we are not tracking yet */
648 tme.cbSize = sizeof(TRACKMOUSEEVENT);
649 tme.dwFlags = TME_QUERY;
650 tme.hwndTrack = hWnd;
651 TrackMouseEvent(&tme);
652 if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
653 {
654 tme.hwndTrack = hWnd;
655 tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
656 TrackMouseEvent(&tme);
657 }
658
659 ThemeInitDrawContext(&context, hWnd, 0);
660 if (context.wi.dwStyle & WS_SYSMENU)
661 {
662 if (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest))
663 ThemeDrawCaptionButtons(&context, ht, 0);
664 }
665
666 if (context.wi.dwStyle & WS_HSCROLL)
667 {
668 if (ht == HTHSCROLL || pwndData->lastHitTest == HTHSCROLL)
669 ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
670 }
671
672 if (context.wi.dwStyle & WS_VSCROLL)
673 {
674 if (ht == HTVSCROLL || pwndData->lastHitTest == HTVSCROLL)
675 ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
676 }
677 ThemeCleanupDrawContext(&context);
678
679 pwndData->lastHitTest = ht;
680
681 return 0;
682 }
683
684 static LRESULT
685 ThemeHandleNcMouseLeave(HWND hWnd)
686 {
687 DRAW_CONTEXT context;
688 DWORD style;
689 PWND_DATA pwndData;
690
691 /* First of all check if we have something to do here */
692 style = GetWindowLongW(hWnd, GWL_STYLE);
693 if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
694 return 0;
695
696 /* Get theme data for this window */
697 pwndData = ThemeGetWndData(hWnd);
698 if (pwndData == NULL)
699 return 0;
700
701 ThemeInitDrawContext(&context, hWnd, 0);
702 if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pwndData->lastHitTest))
703 ThemeDrawCaptionButtons(&context, 0, 0);
704
705 if (context.wi.dwStyle & WS_HSCROLL && pwndData->lastHitTest == HTHSCROLL)
706 ThemeDrawScrollBar(&context, SB_HORZ, NULL);
707
708 if (context.wi.dwStyle & WS_VSCROLL && pwndData->lastHitTest == HTVSCROLL)
709 ThemeDrawScrollBar(&context, SB_VERT, NULL);
710
711 ThemeCleanupDrawContext(&context);
712
713 pwndData->lastHitTest = HTNOWHERE;
714
715 return 0;
716 }
717
718 static VOID
719 ThemeHandleButton(HWND hWnd, WPARAM wParam)
720 {
721 MSG Msg;
722 BOOL Pressed = TRUE;
723 WPARAM SCMsg, ht;
724 ULONG Style;
725 DRAW_CONTEXT context;
726 PWND_DATA pwndData;
727
728 Style = GetWindowLongW(hWnd, GWL_STYLE);
729 if (!((Style & WS_CAPTION) && (Style & WS_SYSMENU)))
730 return ;
731
732 switch (wParam)
733 {
734 case HTCLOSE:
735 SCMsg = SC_CLOSE;
736 break;
737 case HTMINBUTTON:
738 if (!(Style & WS_MINIMIZEBOX))
739 return;
740 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
741 break;
742 case HTMAXBUTTON:
743 if (!(Style & WS_MAXIMIZEBOX))
744 return;
745 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
746 break;
747 default :
748 return;
749 }
750
751 /* Get theme data for this window */
752 pwndData = ThemeGetWndData(hWnd);
753 if (pwndData == NULL)
754 return;
755
756 ThemeInitDrawContext(&context, hWnd, 0);
757 ThemeDrawCaptionButtons(&context, 0, wParam);
758 pwndData->lastHitTest = wParam;
759
760 SetCapture(hWnd);
761
762 ht = wParam;
763
764 for (;;)
765 {
766 if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
767 break;
768
769 if (Msg.message == WM_LBUTTONUP)
770 break;
771
772 if (Msg.message != WM_MOUSEMOVE)
773 continue;
774
775 ht = SendMessage(hWnd, WM_NCHITTEST, 0, MAKELPARAM(Msg.pt.x, Msg.pt.y));
776 Pressed = (ht == wParam);
777
778 /* Only draw the buttons if the hit test changed */
779 if (ht != pwndData->lastHitTest &&
780 (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest)))
781 {
782 ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
783 pwndData->lastHitTest = ht;
784 }
785 }
786
787 ThemeDrawCaptionButtons(&context, ht, 0);
788 ThemeCleanupDrawContext(&context);
789
790 ReleaseCapture();
791
792 if (Pressed)
793 SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, 0);
794 }
795
796
797 static LRESULT
798 DefWndNCHitTest(HWND hWnd, POINT Point)
799 {
800 RECT WindowRect;
801 POINT ClientPoint;
802 WINDOWINFO wi;
803
804 wi.cbSize = sizeof(wi);
805 GetWindowInfo(hWnd, &wi);
806
807 if (!PtInRect(&wi.rcWindow, Point))
808 {
809 return HTNOWHERE;
810 }
811 WindowRect = wi.rcWindow;
812
813 if (UserHasWindowEdge(wi.dwStyle, wi.dwExStyle))
814 {
815 LONG XSize, YSize;
816
817 InflateRect(&WindowRect, -(int)wi.cxWindowBorders, -(int)wi.cyWindowBorders);
818 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
819 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
820 if (!PtInRect(&WindowRect, Point))
821 {
822 BOOL ThickFrame;
823
824 ThickFrame = (wi.dwStyle & WS_THICKFRAME);
825 if (Point.y < WindowRect.top)
826 {
827 if(wi.dwStyle & WS_MINIMIZE)
828 return HTCAPTION;
829 if(!ThickFrame)
830 return HTBORDER;
831 if (Point.x < (WindowRect.left + XSize))
832 return HTTOPLEFT;
833 if (Point.x >= (WindowRect.right - XSize))
834 return HTTOPRIGHT;
835 return HTTOP;
836 }
837 if (Point.y >= WindowRect.bottom)
838 {
839 if(wi.dwStyle & WS_MINIMIZE)
840 return HTCAPTION;
841 if(!ThickFrame)
842 return HTBORDER;
843 if (Point.x < (WindowRect.left + XSize))
844 return HTBOTTOMLEFT;
845 if (Point.x >= (WindowRect.right - XSize))
846 return HTBOTTOMRIGHT;
847 return HTBOTTOM;
848 }
849 if (Point.x < WindowRect.left)
850 {
851 if(wi.dwStyle & WS_MINIMIZE)
852 return HTCAPTION;
853 if(!ThickFrame)
854 return HTBORDER;
855 if (Point.y < (WindowRect.top + YSize))
856 return HTTOPLEFT;
857 if (Point.y >= (WindowRect.bottom - YSize))
858 return HTBOTTOMLEFT;
859 return HTLEFT;
860 }
861 if (Point.x >= WindowRect.right)
862 {
863 if(wi.dwStyle & WS_MINIMIZE)
864 return HTCAPTION;
865 if(!ThickFrame)
866 return HTBORDER;
867 if (Point.y < (WindowRect.top + YSize))
868 return HTTOPRIGHT;
869 if (Point.y >= (WindowRect.bottom - YSize))
870 return HTBOTTOMRIGHT;
871 return HTRIGHT;
872 }
873 }
874 }
875 else
876 {
877 if (wi.dwExStyle & WS_EX_STATICEDGE)
878 InflateRect(&WindowRect, -GetSystemMetrics(SM_CXBORDER),
879 -GetSystemMetrics(SM_CYBORDER));
880 if (!PtInRect(&WindowRect, Point))
881 return HTBORDER;
882 }
883
884 if ((wi.dwStyle & WS_CAPTION) == WS_CAPTION)
885 {
886 if (wi.dwExStyle & WS_EX_TOOLWINDOW)
887 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
888 else
889 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
890
891 if (!PtInRect(&WindowRect, Point))
892 {
893 if (wi.dwStyle & WS_SYSMENU)
894 {
895 PWND_DATA pwndData = ThemeGetWndData(hWnd);
896
897 if (!(wi.dwExStyle & WS_EX_TOOLWINDOW))
898 {
899 // if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
900 // FIXME: The real test should check whether there is
901 // an icon for the system window, and if so, do the
902 // rect.left increase.
903 // See win32ss/user/user32/windows/nonclient.c!DefWndNCHitTest
904 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
905 // the test better.
906 WindowRect.left += GetSystemMetrics(SM_CXSMICON);
907 }
908
909 if (pwndData)
910 {
911 POINT pt = {Point.x - wi.rcWindow.left, Point.y - wi.rcWindow.top};
912 if (PtInRect(&pwndData->rcCaptionButtons[CLOSEBUTTON], pt))
913 return HTCLOSE;
914 if (PtInRect(&pwndData->rcCaptionButtons[MAXBUTTON], pt))
915 return HTMAXBUTTON;
916 if (PtInRect(&pwndData->rcCaptionButtons[MINBUTTON], pt))
917 return HTMINBUTTON;
918 }
919 }
920 if (Point.x < WindowRect.left)
921 return HTSYSMENU;
922 return HTCAPTION;
923 }
924 }
925
926 if(!(wi.dwStyle & WS_MINIMIZE))
927 {
928 HMENU menu;
929
930 ClientPoint = Point;
931 ScreenToClient(hWnd, &ClientPoint);
932 GetClientRect(hWnd, &wi.rcClient);
933
934 if (PtInRect(&wi.rcClient, ClientPoint))
935 {
936 return HTCLIENT;
937 }
938
939 if ((menu = GetMenu(hWnd)) && !(wi.dwStyle & WS_CHILD))
940 {
941 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
942 return HTMENU;
943 }
944
945 if (wi.dwExStyle & WS_EX_CLIENTEDGE)
946 {
947 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
948 -2 * GetSystemMetrics(SM_CYBORDER));
949 }
950
951 if ((wi.dwStyle & WS_VSCROLL) && (wi.dwStyle & WS_HSCROLL) &&
952 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
953 {
954 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
955 HWND Parent = GetParent(hWnd);
956
957 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
958 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
959 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
960 else
961 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
962 if (PtInRect(&TempRect, Point))
963 return HTVSCROLL;
964
965 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
966 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
967 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
968 else
969 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
970 if (PtInRect(&TempRect2, Point))
971 return HTHSCROLL;
972
973 TempRect.top = TempRect2.top;
974 TempRect.bottom = TempRect2.bottom;
975 if(Parent)
976 GetClientRect(Parent, &ParentRect);
977 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(wi.dwStyle, wi.dwExStyle,
978 GetWindowLongW(Parent, GWL_STYLE), wi.rcWindow, ParentRect))
979 {
980 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
981 return HTBOTTOMLEFT;
982 else
983 return HTBOTTOMRIGHT;
984 }
985 }
986 else
987 {
988 if (wi.dwStyle & WS_VSCROLL)
989 {
990 RECT TempRect = WindowRect;
991
992 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
993 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
994 else
995 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
996 if (PtInRect(&TempRect, Point))
997 return HTVSCROLL;
998 }
999 else if (wi.dwStyle & WS_HSCROLL)
1000 {
1001 RECT TempRect = WindowRect;
1002 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1003 if (PtInRect(&TempRect, Point))
1004 return HTHSCROLL;
1005 }
1006 }
1007 }
1008
1009 return HTNOWHERE;
1010 }
1011
1012 LRESULT CALLBACK
1013 ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndProc)
1014 {
1015 switch(Msg)
1016 {
1017 case WM_NCPAINT:
1018 return ThemeHandleNCPaint(hWnd, (HRGN)wParam);
1019 //
1020 // WM_NCUAHDRAWCAPTION : wParam are DC_* flags.
1021 //
1022 case WM_NCUAHDRAWCAPTION:
1023 //
1024 // WM_NCUAHDRAWFRAME : wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
1025 //
1026 case WM_NCUAHDRAWFRAME:
1027 case WM_NCACTIVATE:
1028
1029 if ((GetWindowLongW(hWnd, GWL_STYLE) & WS_CAPTION) != WS_CAPTION)
1030 return TRUE;
1031
1032 ThemeHandleNCPaint(hWnd, (HRGN)1);
1033 return TRUE;
1034 case WM_NCMOUSEMOVE:
1035 {
1036 POINT Point;
1037 Point.x = GET_X_LPARAM(lParam);
1038 Point.y = GET_Y_LPARAM(lParam);
1039 return ThemeHandleNcMouseMove(hWnd, wParam, &Point);
1040 }
1041 case WM_NCMOUSELEAVE:
1042 return ThemeHandleNcMouseLeave(hWnd);
1043 case WM_NCLBUTTONDOWN:
1044 switch (wParam)
1045 {
1046 case HTMINBUTTON:
1047 case HTMAXBUTTON:
1048 case HTCLOSE:
1049 {
1050 ThemeHandleButton(hWnd, wParam);
1051 return 0;
1052 }
1053 default:
1054 return DefWndProc(hWnd, Msg, wParam, lParam);
1055 }
1056 case WM_NCHITTEST:
1057 {
1058 POINT Point;
1059 Point.x = GET_X_LPARAM(lParam);
1060 Point.y = GET_Y_LPARAM(lParam);
1061 return DefWndNCHitTest(hWnd, Point);
1062 }
1063 case WM_SYSCOMMAND:
1064 {
1065 if((wParam & 0xfff0) == SC_VSCROLL ||
1066 (wParam & 0xfff0) == SC_HSCROLL)
1067 {
1068 POINT Pt;
1069 Pt.x = (short)LOWORD(lParam);
1070 Pt.y = (short)HIWORD(lParam);
1071 NC_TrackScrollBar(hWnd, wParam, Pt);
1072 return 0;
1073 }
1074 else
1075 {
1076 return DefWndProc(hWnd, Msg, wParam, lParam);
1077 }
1078 }
1079 default:
1080 return DefWndProc(hWnd, Msg, wParam, lParam);
1081 }
1082 }
1083
1084 HRESULT WINAPI DrawNCPreview(HDC hDC,
1085 DWORD DNCP_Flag,
1086 LPRECT prcPreview,
1087 LPCWSTR pszThemeFileName,
1088 LPCWSTR pszColorName,
1089 LPCWSTR pszSizeName,
1090 PNONCLIENTMETRICSW pncMetrics,
1091 COLORREF* lpaRgbValues)
1092 {
1093 WNDCLASSEXW DummyPreviewWindowClass;
1094 HWND hwndDummy;
1095 HRESULT hres;
1096 HTHEMEFILE hThemeFile;
1097 DRAW_CONTEXT context;
1098 RECT rcCurrent;
1099
1100 /* FIXME: We also need to implement drawing the rest of the preview windows
1101 * and make use of the ncmetrics and colors passed as parameters */
1102
1103 /* Create a dummy window that will be used to trick the paint funtions */
1104 memset(&DummyPreviewWindowClass, 0, sizeof(DummyPreviewWindowClass));
1105 DummyPreviewWindowClass.cbSize = sizeof(DummyPreviewWindowClass);
1106 DummyPreviewWindowClass.lpszClassName = L"DummyPreviewWindowClass";
1107 DummyPreviewWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
1108 DummyPreviewWindowClass.hInstance = hDllInst;
1109 DummyPreviewWindowClass.lpfnWndProc = DefWindowProcW;
1110 if (!RegisterClassExW(&DummyPreviewWindowClass))
1111 return E_FAIL;
1112
1113 hwndDummy = CreateWindowExW(0, L"DummyPreviewWindowClass", L"Active window", WS_OVERLAPPEDWINDOW,30,30,300,150,0,0,hDllInst,NULL);
1114 if (!hwndDummy)
1115 return E_FAIL;
1116
1117 hres = OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, &hThemeFile,0);
1118 if (FAILED(hres))
1119 return hres;
1120
1121 /* Initialize the special draw context for the preview */
1122 context.hDC = hDC;
1123 context.hWnd = hwndDummy;
1124 context.theme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"WINDOW", 0);
1125 if (!context.theme)
1126 return E_FAIL;
1127 context.scrolltheme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"SCROLLBAR", 0);
1128 if (!context.scrolltheme)
1129 return E_FAIL;
1130 context.Active = TRUE;
1131 context.wi.cbSize = sizeof(context.wi);
1132 if (!GetWindowInfo(hwndDummy, &context.wi))
1133 return E_FAIL;
1134 context.wi.dwStyle |= WS_VISIBLE;
1135 context.CaptionHeight = context.wi.cyWindowBorders;
1136 context.CaptionHeight += GetSystemMetrics(context.wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
1137 context.hRgn = CreateRectRgnIndirect(&context.wi.rcWindow);
1138
1139 /* Paint the window on the preview hDC */
1140 rcCurrent = context.wi.rcWindow;
1141 OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
1142 SetViewportOrgEx(hDC, context.wi.rcWindow.left, context.wi.rcWindow.top, NULL);
1143 ThemeCalculateCaptionButtonsPos(hwndDummy, context.theme);
1144 ThemePaintWindow(&context, &rcCurrent, FALSE);
1145 SetViewportOrgEx(hDC, 0, 0, NULL);
1146
1147 context.hDC = NULL;
1148 CloseThemeData (context.theme);
1149 CloseThemeData (context.scrolltheme);
1150 ThemeCleanupDrawContext(&context);
1151
1152 /* Cleanup */
1153 DestroyWindow(hwndDummy);
1154 UnregisterClassW(L"DummyPreviewWindowClass", hDllInst);
1155
1156 return S_OK;
1157 }