[COMCTL32]
[reactos.git] / reactos / dll / win32 / comctl32 / commctrl.c
1 /*
2 * Common controls functions
3 *
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
6 * Copyright 2014-2015 Michael Müller
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 *
24 * This code was audited for completeness against the documented features
25 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
26 *
27 * Unless otherwise noted, we believe this code to be complete, as per
28 * the specification mentioned above.
29 * If you discover missing features, or bugs, please note them below.
30 *
31 * TODO
32 * -- implement GetMUILanguage + InitMUILanguage
33 * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
34 * -- FIXMEs + BUGS (search for them)
35 *
36 * Control Classes
37 * -- ICC_ANIMATE_CLASS
38 * -- ICC_BAR_CLASSES
39 * -- ICC_COOL_CLASSES
40 * -- ICC_DATE_CLASSES
41 * -- ICC_HOTKEY_CLASS
42 * -- ICC_INTERNET_CLASSES
43 * -- ICC_LINK_CLASS
44 * -- ICC_LISTVIEW_CLASSES
45 * -- ICC_NATIVEFNTCTL_CLASS
46 * -- ICC_PAGESCROLLER_CLASS
47 * -- ICC_PROGRESS_CLASS
48 * -- ICC_STANDARD_CLASSES (not yet implemented)
49 * -- ICC_TAB_CLASSES
50 * -- ICC_TREEVIEW_CLASSES
51 * -- ICC_UPDOWN_CLASS
52 * -- ICC_USEREX_CLASSES
53 * -- ICC_WIN95_CLASSES
54 */
55
56 #include "comctl32.h"
57
58 #define NO_SHLWAPI_STREAM
59 #include <shlwapi.h>
60
61 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
62
63 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
64
65 static LPWSTR COMCTL32_wSubclass = NULL;
66 HMODULE COMCTL32_hModule = 0;
67 static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
68 HBRUSH COMCTL32_hPattern55AABrush = NULL;
69 COMCTL32_SysColor comctl32_color;
70
71 static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
72
73 static const WORD wPattern55AA[] =
74 {
75 0x5555, 0xaaaa, 0x5555, 0xaaaa,
76 0x5555, 0xaaaa, 0x5555, 0xaaaa
77 };
78
79 static const WCHAR strCC32SubclassInfo[] = {
80 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
81 };
82
83 #ifdef __REACTOS__
84
85 #include <strsafe.h>
86
87 #define NAME L"microsoft.windows.common-controls"
88 #define VERSION_V5 L"5.82.2600.2982"
89 #define VERSION L"6.0.2600.2982"
90 #define PUBLIC_KEY L"6595b64144ccf1df"
91
92 #ifdef __i386__
93 #define ARCH L"x86"
94 #elif defined __x86_64__
95 #define ARCH L"amd64"
96 #else
97 #define ARCH L"none"
98 #endif
99
100 static const WCHAR manifest_filename[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION L"_none_deadbeef.manifest";
101 static const WCHAR manifest_filename_v5[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION_V5 L"_none_deadbeef.manifest";
102
103 static WCHAR* GetManifestPath(BOOL create, BOOL bV6)
104 {
105 WCHAR *pwszBuf;
106 HRESULT hres;
107
108 pwszBuf = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
109 if (!pwszBuf)
110 return NULL;
111
112 GetWindowsDirectoryW(pwszBuf, MAX_PATH);
113 hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\winsxs");
114 if (FAILED(hres))
115 return NULL;
116 if (create)
117 CreateDirectoryW(pwszBuf, NULL);
118 hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\manifests\\");
119 if (FAILED(hres))
120 return NULL;
121 if (create)
122 CreateDirectoryW(pwszBuf, NULL);
123
124 hres = StringCchCatW(pwszBuf, MAX_PATH, bV6 ? manifest_filename : manifest_filename_v5);
125 if (FAILED(hres))
126 return NULL;
127
128 return pwszBuf;
129 }
130
131 static BOOL create_manifest(BOOL install, BOOL bV6)
132 {
133 WCHAR *pwszBuf;
134 HRSRC hResInfo;
135 HGLOBAL hResData;
136 PVOID pManifest;
137 DWORD cbManifest, cbWritten;
138 HANDLE hFile;
139 BOOL bRet = FALSE;
140
141 if (bV6)
142 hResInfo = FindResourceW(COMCTL32_hModule, L"WINE_MANIFEST", (LPWSTR)RT_MANIFEST);
143 else
144 hResInfo = FindResourceW(COMCTL32_hModule, L"WINE_MANIFESTV5", (LPWSTR)RT_MANIFEST);
145
146 if (!hResInfo)
147 return FALSE;
148
149 cbManifest = SizeofResource(COMCTL32_hModule, hResInfo);
150 if (!cbManifest)
151 return FALSE;
152
153 hResData = LoadResource(COMCTL32_hModule, hResInfo);
154 if (!hResData)
155 return FALSE;
156
157 pManifest = LockResource(hResData);
158 if (!pManifest)
159 return FALSE;
160
161 pwszBuf = GetManifestPath(TRUE, bV6);
162 if (!pwszBuf)
163 return FALSE;
164
165 if (install)
166 {
167 hFile = CreateFileW(pwszBuf, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
168 if (hFile != INVALID_HANDLE_VALUE)
169 {
170 if (WriteFile(hFile, pManifest, cbManifest, &cbWritten, NULL) && cbWritten == cbManifest)
171 bRet = TRUE;
172
173 CloseHandle(hFile);
174
175 if (!bRet)
176 DeleteFileW(pwszBuf);
177 else
178 TRACE("created %s\n", debugstr_w(pwszBuf));
179 }
180 }
181 else
182 bRet = DeleteFileW(pwszBuf);
183
184 HeapFree(GetProcessHeap(), 0, pwszBuf);
185
186 return bRet;
187 }
188
189 static HANDLE CreateComctl32ActCtx(BOOL bV6)
190 {
191 HANDLE ret;
192 WCHAR* pwstrSource;
193 ACTCTXW ActCtx = {sizeof(ACTCTX)};
194
195 pwstrSource = GetManifestPath(FALSE, bV6);
196 if (!pwstrSource)
197 {
198 ERR("GetManifestPath failed! bV6=%d\n", bV6);
199 return INVALID_HANDLE_VALUE;
200 }
201 ActCtx.lpSource = pwstrSource;
202 ret = CreateActCtxW(&ActCtx);
203 HeapFree(GetProcessHeap(), 0, pwstrSource);
204 if (ret == INVALID_HANDLE_VALUE)
205 ERR("CreateActCtxW failed! bV6=%d\n", bV6);
206 return ret;
207 }
208
209 static void RegisterControls()
210 {
211 ANIMATE_Register ();
212 COMBOEX_Register ();
213 DATETIME_Register ();
214 FLATSB_Register ();
215 HEADER_Register ();
216 HOTKEY_Register ();
217 IPADDRESS_Register ();
218 LISTVIEW_Register ();
219 MONTHCAL_Register ();
220 NATIVEFONT_Register ();
221 PAGER_Register ();
222 PROGRESS_Register ();
223 REBAR_Register ();
224 STATUS_Register ();
225 SYSLINK_Register ();
226 TAB_Register ();
227 TOOLBAR_Register ();
228 TOOLTIPS_Register ();
229 TRACKBAR_Register ();
230 TREEVIEW_Register ();
231 UPDOWN_Register ();
232 }
233
234 static void UnregisterControls()
235 {
236 ANIMATE_Unregister ();
237 COMBOEX_Unregister ();
238 DATETIME_Unregister ();
239 FLATSB_Unregister ();
240 HEADER_Unregister ();
241 HOTKEY_Unregister ();
242 IPADDRESS_Unregister ();
243 LISTVIEW_Unregister ();
244 MONTHCAL_Unregister ();
245 NATIVEFONT_Unregister ();
246 PAGER_Unregister ();
247 PROGRESS_Unregister ();
248 REBAR_Unregister ();
249 STATUS_Unregister ();
250 SYSLINK_Unregister ();
251 TAB_Unregister ();
252 TOOLBAR_Unregister ();
253 TOOLTIPS_Unregister ();
254 TRACKBAR_Unregister ();
255 TREEVIEW_Unregister ();
256 UPDOWN_Unregister ();
257 }
258
259 static void InitializeClasses()
260 {
261 HANDLE hActCtx5, hActCtx6;
262 BOOL activated;
263 ULONG_PTR ulCookie;
264
265 /* like comctl32 5.82+ register all the common control classes */
266 /* Register the classes once no matter what */
267 hActCtx5 = CreateComctl32ActCtx(FALSE);
268 activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
269 RegisterControls(); /* Register the classes pretending to be v5 */
270 if (activated) DeactivateActCtx(0, ulCookie);
271
272 hActCtx6 = CreateComctl32ActCtx(TRUE);
273 if (hActCtx6 != INVALID_HANDLE_VALUE)
274 {
275 activated = ActivateActCtx(hActCtx6, &ulCookie);
276 RegisterControls(); /* Register the classes pretending to be v6 */
277 if (activated) DeactivateActCtx(0, ulCookie);
278
279 /* Initialize the themed controls only when the v6 manifest is present */
280 THEMING_Initialize (hActCtx5, hActCtx6);
281 }
282 }
283
284 static void UninitializeClasses()
285 {
286 HANDLE hActCtx5, hActCtx6;
287 BOOL activated;
288 ULONG_PTR ulCookie;
289
290 hActCtx5 = CreateComctl32ActCtx(FALSE);
291 activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
292 UnregisterControls();
293 if (activated) DeactivateActCtx(0, ulCookie);
294
295 hActCtx6 = CreateComctl32ActCtx(TRUE);
296 if (hActCtx6 != INVALID_HANDLE_VALUE)
297 {
298 activated = ActivateActCtx(hActCtx6, &ulCookie);
299 THEMING_Uninitialize();
300 UnregisterControls();
301 if (activated) DeactivateActCtx(0, ulCookie);
302 }
303 }
304
305 /***********************************************************************
306 * RegisterClassNameW [COMCTL32.@]
307 *
308 * Register window class again while using as SxS module.
309 */
310 BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className)
311 {
312 InitializeClasses();
313 return TRUE;
314 }
315
316 #endif
317
318 /***********************************************************************
319 * DllMain [Internal]
320 *
321 * Initializes the internal 'COMCTL32.DLL'.
322 *
323 * PARAMS
324 * hinstDLL [I] handle to the 'dlls' instance
325 * fdwReason [I]
326 * lpvReserved [I] reserved, must be NULL
327 *
328 * RETURNS
329 * Success: TRUE
330 * Failure: FALSE
331 */
332
333 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
334 {
335 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
336
337 switch (fdwReason) {
338 case DLL_PROCESS_ATTACH:
339 DisableThreadLibraryCalls(hinstDLL);
340
341 COMCTL32_hModule = hinstDLL;
342
343 /* add global subclassing atom (used by 'tooltip' and 'updown') */
344 COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
345 TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
346
347 /* create local pattern brush */
348 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
349 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
350
351 /* Get all the colors at DLL load */
352 COMCTL32_RefreshSysColors();
353
354 #ifndef __REACTOS__
355 /* like comctl32 5.82+ register all the common control classes */
356 ANIMATE_Register ();
357 COMBOEX_Register ();
358 DATETIME_Register ();
359 FLATSB_Register ();
360 HEADER_Register ();
361 HOTKEY_Register ();
362 IPADDRESS_Register ();
363 LISTVIEW_Register ();
364 MONTHCAL_Register ();
365 NATIVEFONT_Register ();
366 PAGER_Register ();
367 PROGRESS_Register ();
368 REBAR_Register ();
369 STATUS_Register ();
370 SYSLINK_Register ();
371 TAB_Register ();
372 TOOLBAR_Register ();
373 TOOLTIPS_Register ();
374 TRACKBAR_Register ();
375 TREEVIEW_Register ();
376 UPDOWN_Register ();
377
378 /* subclass user32 controls */
379 THEMING_Initialize ();
380 #else
381 InitializeClasses();
382 #endif
383
384 break;
385
386 case DLL_PROCESS_DETACH:
387 if (lpvReserved) break;
388 #ifndef __REACTOS__
389 /* clean up subclassing */
390 THEMING_Uninitialize();
391
392 /* unregister all common control classes */
393 ANIMATE_Unregister ();
394 COMBOEX_Unregister ();
395 DATETIME_Unregister ();
396 FLATSB_Unregister ();
397 HEADER_Unregister ();
398 HOTKEY_Unregister ();
399 IPADDRESS_Unregister ();
400 LISTVIEW_Unregister ();
401 MONTHCAL_Unregister ();
402 NATIVEFONT_Unregister ();
403 PAGER_Unregister ();
404 PROGRESS_Unregister ();
405 REBAR_Unregister ();
406 STATUS_Unregister ();
407 SYSLINK_Unregister ();
408 TAB_Unregister ();
409 TOOLBAR_Unregister ();
410 TOOLTIPS_Unregister ();
411 TRACKBAR_Unregister ();
412 TREEVIEW_Unregister ();
413 UPDOWN_Unregister ();
414 #else
415 UninitializeClasses();
416 #endif
417 /* delete local pattern brush */
418 DeleteObject (COMCTL32_hPattern55AABrush);
419 DeleteObject (COMCTL32_hPattern55AABitmap);
420
421 /* delete global subclassing atom */
422 GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
423 TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
424 break;
425 }
426
427 return TRUE;
428 }
429
430
431 /***********************************************************************
432 * MenuHelp [COMCTL32.2]
433 *
434 * Handles the setting of status bar help messages when the user
435 * selects menu items.
436 *
437 * PARAMS
438 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
439 * wParam [I] wParam of the message uMsg
440 * lParam [I] lParam of the message uMsg
441 * hMainMenu [I] handle to the application's main menu
442 * hInst [I] handle to the module that contains string resources
443 * hwndStatus [I] handle to the status bar window
444 * lpwIDs [I] pointer to an array of integers (see NOTES)
445 *
446 * RETURNS
447 * No return value
448 *
449 * NOTES
450 * The official documentation is incomplete!
451 * This is the correct documentation:
452 *
453 * uMsg:
454 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
455 * WM_MENUSELECT messages.
456 *
457 * lpwIDs:
458 * (will be written ...)
459 */
460
461 VOID WINAPI
462 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
463 HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
464 {
465 UINT uMenuID = 0;
466
467 if (!IsWindow (hwndStatus))
468 return;
469
470 switch (uMsg) {
471 case WM_MENUSELECT:
472 TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
473 wParam, lParam);
474
475 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
476 /* menu was closed */
477 TRACE("menu was closed!\n");
478 SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
479 }
480 else {
481 /* menu item was selected */
482 if (HIWORD(wParam) & MF_POPUP)
483 uMenuID = *(lpwIDs+1);
484 else
485 uMenuID = (UINT)LOWORD(wParam);
486 TRACE("uMenuID = %u\n", uMenuID);
487
488 if (uMenuID) {
489 WCHAR szText[256];
490
491 if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
492 szText[0] = '\0';
493
494 SendMessageW (hwndStatus, SB_SETTEXTW,
495 255 | SBT_NOBORDERS, (LPARAM)szText);
496 SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
497 }
498 }
499 break;
500
501 case WM_COMMAND :
502 TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
503 wParam, lParam);
504 /* WM_COMMAND is not invalid since it is documented
505 * in the windows api reference. So don't output
506 * any FIXME for WM_COMMAND
507 */
508 WARN("We don't care about the WM_COMMAND\n");
509 break;
510
511 default:
512 FIXME("Invalid Message 0x%x!\n", uMsg);
513 break;
514 }
515 }
516
517
518 /***********************************************************************
519 * ShowHideMenuCtl [COMCTL32.3]
520 *
521 * Shows or hides controls and updates the corresponding menu item.
522 *
523 * PARAMS
524 * hwnd [I] handle to the client window.
525 * uFlags [I] menu command id.
526 * lpInfo [I] pointer to an array of integers. (See NOTES.)
527 *
528 * RETURNS
529 * Success: TRUE
530 * Failure: FALSE
531 *
532 * NOTES
533 * The official documentation is incomplete!
534 * This is the correct documentation:
535 *
536 * hwnd
537 * Handle to the window that contains the menu and controls.
538 *
539 * uFlags
540 * Identifier of the menu item to receive or lose a check mark.
541 *
542 * lpInfo
543 * The array of integers contains pairs of values. BOTH values of
544 * the first pair must be the handles to the application's main menu.
545 * Each subsequent pair consists of a menu id and control id.
546 */
547
548 BOOL WINAPI
549 ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
550 {
551 LPINT lpMenuId;
552
553 TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
554
555 if (lpInfo == NULL)
556 return FALSE;
557
558 if (!(lpInfo[0]) || !(lpInfo[1]))
559 return FALSE;
560
561 /* search for control */
562 lpMenuId = &lpInfo[2];
563 while (*lpMenuId != uFlags)
564 lpMenuId += 2;
565
566 if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
567 /* uncheck menu item */
568 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
569
570 /* hide control */
571 lpMenuId++;
572 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
573 SWP_HIDEWINDOW);
574 }
575 else {
576 /* check menu item */
577 CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
578
579 /* show control */
580 lpMenuId++;
581 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
582 SWP_SHOWWINDOW);
583 }
584
585 return TRUE;
586 }
587
588
589 /***********************************************************************
590 * GetEffectiveClientRect [COMCTL32.4]
591 *
592 * Calculates the coordinates of a rectangle in the client area.
593 *
594 * PARAMS
595 * hwnd [I] handle to the client window.
596 * lpRect [O] pointer to the rectangle of the client window
597 * lpInfo [I] pointer to an array of integers (see NOTES)
598 *
599 * RETURNS
600 * No return value.
601 *
602 * NOTES
603 * The official documentation is incomplete!
604 * This is the correct documentation:
605 *
606 * lpInfo
607 * (will be written ...)
608 */
609
610 VOID WINAPI
611 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
612 {
613 RECT rcCtrl;
614 const INT *lpRun;
615 HWND hwndCtrl;
616
617 TRACE("(%p %p %p)\n",
618 hwnd, lpRect, lpInfo);
619
620 GetClientRect (hwnd, lpRect);
621 lpRun = lpInfo;
622
623 do {
624 lpRun += 2;
625 if (*lpRun == 0)
626 return;
627 lpRun++;
628 hwndCtrl = GetDlgItem (hwnd, *lpRun);
629 if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
630 TRACE("control id 0x%x\n", *lpRun);
631 GetWindowRect (hwndCtrl, &rcCtrl);
632 MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
633 SubtractRect (lpRect, lpRect, &rcCtrl);
634 }
635 lpRun++;
636 } while (*lpRun);
637 }
638
639
640 /***********************************************************************
641 * DrawStatusTextW [COMCTL32.@]
642 *
643 * Draws text with borders, like in a status bar.
644 *
645 * PARAMS
646 * hdc [I] handle to the window's display context
647 * lprc [I] pointer to a rectangle
648 * text [I] pointer to the text
649 * style [I] drawing style
650 *
651 * RETURNS
652 * No return value.
653 *
654 * NOTES
655 * The style variable can have one of the following values:
656 * (will be written ...)
657 */
658
659 void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
660 {
661 RECT r = *lprc;
662 UINT border = BDR_SUNKENOUTER;
663
664 if (style & SBT_POPOUT)
665 border = BDR_RAISEDOUTER;
666 else if (style & SBT_NOBORDERS)
667 border = 0;
668
669 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
670
671 /* now draw text */
672 if (text) {
673 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
674 UINT align = DT_LEFT;
675 int strCnt = 0;
676
677 if (style & SBT_RTLREADING)
678 FIXME("Unsupported RTL style!\n");
679 r.left += 3;
680 do {
681 if (*text == '\t') {
682 if (strCnt) {
683 DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
684 strCnt = 0;
685 }
686 if (align==DT_RIGHT) {
687 break;
688 }
689 align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
690 } else {
691 strCnt++;
692 }
693 } while(*text++);
694
695 if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
696 SetBkMode(hdc, oldbkmode);
697 }
698 }
699
700
701 /***********************************************************************
702 * DrawStatusText [COMCTL32.@]
703 * DrawStatusTextA [COMCTL32.5]
704 *
705 * Draws text with borders, like in a status bar.
706 *
707 * PARAMS
708 * hdc [I] handle to the window's display context
709 * lprc [I] pointer to a rectangle
710 * text [I] pointer to the text
711 * style [I] drawing style
712 *
713 * RETURNS
714 * No return value.
715 */
716
717 void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
718 {
719 INT len;
720 LPWSTR textW = NULL;
721
722 if ( text ) {
723 if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
724 if ( (textW = Alloc( len * sizeof(WCHAR) )) )
725 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
726 }
727 }
728 DrawStatusTextW( hdc, lprc, textW, style );
729 Free( textW );
730 }
731
732
733 /***********************************************************************
734 * CreateStatusWindow [COMCTL32.@]
735 * CreateStatusWindowA [COMCTL32.6]
736 *
737 * Creates a status bar
738 *
739 * PARAMS
740 * style [I] window style
741 * text [I] pointer to the window text
742 * parent [I] handle to the parent window
743 * wid [I] control id of the status bar
744 *
745 * RETURNS
746 * Success: handle to the status window
747 * Failure: 0
748 */
749
750 HWND WINAPI
751 CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
752 {
753 return CreateWindowA(STATUSCLASSNAMEA, text, style,
754 CW_USEDEFAULT, CW_USEDEFAULT,
755 CW_USEDEFAULT, CW_USEDEFAULT,
756 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
757 }
758
759
760 /***********************************************************************
761 * CreateStatusWindowW [COMCTL32.@]
762 *
763 * Creates a status bar control
764 *
765 * PARAMS
766 * style [I] window style
767 * text [I] pointer to the window text
768 * parent [I] handle to the parent window
769 * wid [I] control id of the status bar
770 *
771 * RETURNS
772 * Success: handle to the status window
773 * Failure: 0
774 */
775
776 HWND WINAPI
777 CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
778 {
779 return CreateWindowW(STATUSCLASSNAMEW, text, style,
780 CW_USEDEFAULT, CW_USEDEFAULT,
781 CW_USEDEFAULT, CW_USEDEFAULT,
782 parent, (HMENU)(DWORD_PTR)wid, 0, 0);
783 }
784
785
786 /***********************************************************************
787 * CreateUpDownControl [COMCTL32.16]
788 *
789 * Creates an up-down control
790 *
791 * PARAMS
792 * style [I] window styles
793 * x [I] horizontal position of the control
794 * y [I] vertical position of the control
795 * cx [I] with of the control
796 * cy [I] height of the control
797 * parent [I] handle to the parent window
798 * id [I] the control's identifier
799 * inst [I] handle to the application's module instance
800 * buddy [I] handle to the buddy window, can be NULL
801 * maxVal [I] upper limit of the control
802 * minVal [I] lower limit of the control
803 * curVal [I] current value of the control
804 *
805 * RETURNS
806 * Success: handle to the updown control
807 * Failure: 0
808 */
809
810 HWND WINAPI
811 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
812 HWND parent, INT id, HINSTANCE inst,
813 HWND buddy, INT maxVal, INT minVal, INT curVal)
814 {
815 HWND hUD =
816 CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
817 parent, (HMENU)(DWORD_PTR)id, inst, 0);
818 if (hUD) {
819 SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
820 SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
821 SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
822 }
823
824 return hUD;
825 }
826
827
828 /***********************************************************************
829 * InitCommonControls [COMCTL32.17]
830 *
831 * Registers the common controls.
832 *
833 * PARAMS
834 * No parameters.
835 *
836 * RETURNS
837 * No return values.
838 *
839 * NOTES
840 * This function is just a dummy - all the controls are registered at
841 * the DLL initialization time. See InitCommonContolsEx for details.
842 */
843
844 VOID WINAPI
845 InitCommonControls (void)
846 {
847 }
848
849
850 /***********************************************************************
851 * InitCommonControlsEx [COMCTL32.@]
852 *
853 * Registers the common controls.
854 *
855 * PARAMS
856 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
857 *
858 * RETURNS
859 * Success: TRUE
860 * Failure: FALSE
861 *
862 * NOTES
863 * Probably all versions of comctl32 initializes the Win95 controls in DllMain
864 * during DLL initialization. Starting from comctl32 v5.82 all the controls
865 * are initialized there. We follow this behaviour and this function is just
866 * a dummy.
867 *
868 * Note: when writing programs under Windows, if you don't call any function
869 * from comctl32 the linker may not link this DLL. If InitCommonControlsEx
870 * was the only comctl32 function you were calling and you remove it you may
871 * have a false impression that InitCommonControlsEx actually did something.
872 */
873
874 BOOL WINAPI
875 InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
876 {
877 if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
878 return FALSE;
879
880 TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
881 return TRUE;
882 }
883
884
885 /***********************************************************************
886 * CreateToolbarEx [COMCTL32.@]
887 *
888 * Creates a toolbar window.
889 *
890 * PARAMS
891 * hwnd
892 * style
893 * wID
894 * nBitmaps
895 * hBMInst
896 * wBMID
897 * lpButtons
898 * iNumButtons
899 * dxButton
900 * dyButton
901 * dxBitmap
902 * dyBitmap
903 * uStructSize
904 *
905 * RETURNS
906 * Success: handle to the tool bar control
907 * Failure: 0
908 */
909
910 HWND WINAPI
911 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
912 HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
913 INT iNumButtons, INT dxButton, INT dyButton,
914 INT dxBitmap, INT dyBitmap, UINT uStructSize)
915 {
916 HWND hwndTB;
917
918 hwndTB =
919 CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
920 hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
921 if(hwndTB) {
922 TBADDBITMAP tbab;
923
924 SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
925
926 /* set bitmap and button size */
927 /*If CreateToolbarEx receives 0, windows sets default values*/
928 if (dxBitmap < 0)
929 dxBitmap = 16;
930 if (dyBitmap < 0)
931 dyBitmap = 16;
932 if (dxBitmap == 0 || dyBitmap == 0)
933 dxBitmap = dyBitmap = 16;
934 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
935
936 if (dxButton < 0)
937 dxButton = dxBitmap;
938 if (dyButton < 0)
939 dyButton = dyBitmap;
940 /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
941 if (dxButton != 0 && dyButton != 0)
942 SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
943
944
945 /* add bitmaps */
946 if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
947 {
948 tbab.hInst = hBMInst;
949 tbab.nID = wBMID;
950
951 SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
952 }
953 /* add buttons */
954 if(iNumButtons > 0)
955 SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
956 }
957
958 return hwndTB;
959 }
960
961
962 /***********************************************************************
963 * CreateMappedBitmap [COMCTL32.8]
964 *
965 * Loads a bitmap resource using a colour map.
966 *
967 * PARAMS
968 * hInstance [I] Handle to the module containing the bitmap.
969 * idBitmap [I] The bitmap resource ID.
970 * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
971 * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
972 * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
973 *
974 * RETURNS
975 * Success: handle to the new bitmap
976 * Failure: 0
977 */
978
979 HBITMAP WINAPI
980 CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
981 LPCOLORMAP lpColorMap, INT iNumMaps)
982 {
983 HGLOBAL hglb;
984 HRSRC hRsrc;
985 const BITMAPINFOHEADER *lpBitmap;
986 LPBITMAPINFOHEADER lpBitmapInfo;
987 UINT nSize, nColorTableSize, iColor;
988 RGBQUAD *pColorTable;
989 INT i, iMaps, nWidth, nHeight;
990 HDC hdcScreen;
991 HBITMAP hbm;
992 LPCOLORMAP sysColorMap;
993 COLORREF cRef;
994 COLORMAP internalColorMap[4] =
995 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
996
997 /* initialize pointer to colortable and default color table */
998 if (lpColorMap) {
999 iMaps = iNumMaps;
1000 sysColorMap = lpColorMap;
1001 }
1002 else {
1003 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
1004 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
1005 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
1006 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
1007 iMaps = 4;
1008 sysColorMap = internalColorMap;
1009 }
1010
1011 hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
1012 if (hRsrc == 0)
1013 return 0;
1014 hglb = LoadResource (hInstance, hRsrc);
1015 if (hglb == 0)
1016 return 0;
1017 lpBitmap = LockResource (hglb);
1018 if (lpBitmap == NULL)
1019 return 0;
1020
1021 if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
1022 nColorTableSize = lpBitmap->biClrUsed;
1023 else if (lpBitmap->biBitCount <= 8)
1024 nColorTableSize = (1 << lpBitmap->biBitCount);
1025 else
1026 nColorTableSize = 0;
1027 nSize = lpBitmap->biSize;
1028 if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
1029 nSize += 3 * sizeof(DWORD);
1030 nSize += nColorTableSize * sizeof(RGBQUAD);
1031 lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
1032 if (lpBitmapInfo == NULL)
1033 return 0;
1034 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
1035
1036 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
1037
1038 for (iColor = 0; iColor < nColorTableSize; iColor++) {
1039 for (i = 0; i < iMaps; i++) {
1040 cRef = RGB(pColorTable[iColor].rgbRed,
1041 pColorTable[iColor].rgbGreen,
1042 pColorTable[iColor].rgbBlue);
1043 if ( cRef == sysColorMap[i].from) {
1044 #if 0
1045 if (wFlags & CBS_MASKED) {
1046 if (sysColorMap[i].to != COLOR_BTNTEXT)
1047 pColorTable[iColor] = RGB(255, 255, 255);
1048 }
1049 else
1050 #endif
1051 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
1052 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
1053 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
1054 break;
1055 }
1056 }
1057 }
1058 nWidth = lpBitmapInfo->biWidth;
1059 nHeight = lpBitmapInfo->biHeight;
1060 hdcScreen = GetDC (NULL);
1061 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
1062 if (hbm) {
1063 HDC hdcDst = CreateCompatibleDC (hdcScreen);
1064 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
1065 const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
1066 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
1067 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
1068 SRCCOPY);
1069 SelectObject (hdcDst, hbmOld);
1070 DeleteDC (hdcDst);
1071 }
1072 ReleaseDC (NULL, hdcScreen);
1073 GlobalFree (lpBitmapInfo);
1074 FreeResource (hglb);
1075
1076 return hbm;
1077 }
1078
1079
1080 /***********************************************************************
1081 * CreateToolbar [COMCTL32.7]
1082 *
1083 * Creates a toolbar control.
1084 *
1085 * PARAMS
1086 * hwnd
1087 * style
1088 * wID
1089 * nBitmaps
1090 * hBMInst
1091 * wBMID
1092 * lpButtons
1093 * iNumButtons
1094 *
1095 * RETURNS
1096 * Success: handle to the tool bar control
1097 * Failure: 0
1098 *
1099 * NOTES
1100 * Do not use this function anymore. Use CreateToolbarEx instead.
1101 */
1102
1103 HWND WINAPI
1104 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
1105 HINSTANCE hBMInst, UINT wBMID,
1106 LPCTBBUTTON lpButtons,INT iNumButtons)
1107 {
1108 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
1109 hBMInst, wBMID, lpButtons,
1110 iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
1111 }
1112
1113
1114 /***********************************************************************
1115 * DllGetVersion [COMCTL32.@]
1116 *
1117 * Retrieves version information of the 'COMCTL32.DLL'
1118 *
1119 * PARAMS
1120 * pdvi [O] pointer to version information structure.
1121 *
1122 * RETURNS
1123 * Success: S_OK
1124 * Failure: E_INVALIDARG
1125 *
1126 * NOTES
1127 * Returns version of a comctl32.dll from IE4.01 SP1.
1128 */
1129
1130 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
1131 {
1132 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
1133 WARN("wrong DLLVERSIONINFO size from app\n");
1134 return E_INVALIDARG;
1135 }
1136
1137 pdvi->dwMajorVersion = COMCTL32_VERSION;
1138 pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
1139 pdvi->dwBuildNumber = 2919;
1140 pdvi->dwPlatformID = 6304;
1141
1142 TRACE("%u.%u.%u.%u\n",
1143 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
1144 pdvi->dwBuildNumber, pdvi->dwPlatformID);
1145
1146 return S_OK;
1147 }
1148
1149 /***********************************************************************
1150 * DllInstall (COMCTL32.@)
1151 *
1152 * Installs the ComCtl32 DLL.
1153 *
1154 * RETURNS
1155 * Success: S_OK
1156 * Failure: A HRESULT error
1157 */
1158 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1159 {
1160 TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
1161
1162 #ifdef __REACTOS__
1163
1164 if (!create_manifest(bInstall, TRUE))
1165 {
1166 ERR("Failed to install comctl32 v6 manifest!\n");
1167 return HRESULT_FROM_WIN32(GetLastError());
1168 }
1169
1170 if (!create_manifest(bInstall, FALSE))
1171 {
1172 ERR("Failed to install comctl32 v5 manifest!\n");
1173 return HRESULT_FROM_WIN32(GetLastError());
1174 }
1175 #endif
1176
1177 return S_OK;
1178 }
1179
1180 /***********************************************************************
1181 * _TrackMouseEvent [COMCTL32.@]
1182 *
1183 * Requests notification of mouse events
1184 *
1185 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1186 * to the hwnd specified in the ptme structure. After the event message
1187 * is posted to the hwnd, the entry in the queue is removed.
1188 *
1189 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1190 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1191 * immediately and the TME_LEAVE flag being ignored.
1192 *
1193 * PARAMS
1194 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1195 *
1196 * RETURNS
1197 * Success: non-zero
1198 * Failure: zero
1199 *
1200 * IMPLEMENTATION moved to USER32.TrackMouseEvent
1201 *
1202 */
1203
1204 BOOL WINAPI
1205 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1206 {
1207 return TrackMouseEvent (ptme);
1208 }
1209
1210 /*************************************************************************
1211 * GetMUILanguage [COMCTL32.@]
1212 *
1213 * Returns the user interface language in use by the current process.
1214 *
1215 * RETURNS
1216 * Language ID in use by the current process.
1217 */
1218 LANGID WINAPI GetMUILanguage (VOID)
1219 {
1220 return COMCTL32_uiLang;
1221 }
1222
1223
1224 /*************************************************************************
1225 * InitMUILanguage [COMCTL32.@]
1226 *
1227 * Sets the user interface language to be used by the current process.
1228 *
1229 * RETURNS
1230 * Nothing.
1231 */
1232 VOID WINAPI InitMUILanguage (LANGID uiLang)
1233 {
1234 COMCTL32_uiLang = uiLang;
1235 }
1236
1237
1238 /***********************************************************************
1239 * SetWindowSubclass [COMCTL32.410]
1240 *
1241 * Starts a window subclass
1242 *
1243 * PARAMS
1244 * hWnd [in] handle to window subclass.
1245 * pfnSubclass [in] Pointer to new window procedure.
1246 * uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1247 * dwRef [in] Reference data to pass to window procedure.
1248 *
1249 * RETURNS
1250 * Success: non-zero
1251 * Failure: zero
1252 *
1253 * BUGS
1254 * If an application manually subclasses a window after subclassing it with
1255 * this API and then with this API again, then none of the previous
1256 * subclasses get called or the original window procedure.
1257 */
1258
1259 BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1260 UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1261 {
1262 LPSUBCLASS_INFO stack;
1263 LPSUBCLASSPROCS proc;
1264
1265 TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1266
1267 /* Since the window procedure that we set here has two additional arguments,
1268 * we can't simply set it as the new window procedure of the window. So we
1269 * set our own window procedure and then calculate the other two arguments
1270 * from there. */
1271
1272 /* See if we have been called for this window */
1273 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1274 if (!stack) {
1275 /* allocate stack */
1276 stack = Alloc (sizeof(SUBCLASS_INFO));
1277 if (!stack) {
1278 ERR ("Failed to allocate our Subclassing stack\n");
1279 return FALSE;
1280 }
1281 SetPropW (hWnd, COMCTL32_wSubclass, stack);
1282
1283 /* set window procedure to our own and save the current one */
1284 if (IsWindowUnicode (hWnd))
1285 stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1286 (DWORD_PTR)COMCTL32_SubclassProc);
1287 else
1288 stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
1289 (DWORD_PTR)COMCTL32_SubclassProc);
1290 }
1291 else {
1292 /* Check to see if we have called this function with the same uIDSubClass
1293 * and pfnSubclass */
1294 proc = stack->SubclassProcs;
1295 while (proc) {
1296 if ((proc->id == uIDSubclass) &&
1297 (proc->subproc == pfnSubclass)) {
1298 proc->ref = dwRef;
1299 return TRUE;
1300 }
1301 proc = proc->next;
1302 }
1303 }
1304
1305 proc = Alloc(sizeof(SUBCLASSPROCS));
1306 if (!proc) {
1307 ERR ("Failed to allocate subclass entry in stack\n");
1308 if (IsWindowUnicode (hWnd))
1309 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1310 else
1311 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1312 Free (stack);
1313 RemovePropW( hWnd, COMCTL32_wSubclass );
1314 return FALSE;
1315 }
1316
1317 proc->subproc = pfnSubclass;
1318 proc->ref = dwRef;
1319 proc->id = uIDSubclass;
1320 proc->next = stack->SubclassProcs;
1321 stack->SubclassProcs = proc;
1322
1323 return TRUE;
1324 }
1325
1326
1327 /***********************************************************************
1328 * GetWindowSubclass [COMCTL32.411]
1329 *
1330 * Gets the Reference data from a subclass.
1331 *
1332 * PARAMS
1333 * hWnd [in] Handle to the window which we are subclassing
1334 * pfnSubclass [in] Pointer to the subclass procedure
1335 * uID [in] Unique identifier of the subclassing procedure
1336 * pdwRef [out] Pointer to the reference data
1337 *
1338 * RETURNS
1339 * Success: Non-zero
1340 * Failure: 0
1341 */
1342
1343 BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1344 UINT_PTR uID, DWORD_PTR *pdwRef)
1345 {
1346 const SUBCLASS_INFO *stack;
1347 const SUBCLASSPROCS *proc;
1348
1349 TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1350
1351 /* See if we have been called for this window */
1352 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1353 if (!stack)
1354 return FALSE;
1355
1356 proc = stack->SubclassProcs;
1357 while (proc) {
1358 if ((proc->id == uID) &&
1359 (proc->subproc == pfnSubclass)) {
1360 *pdwRef = proc->ref;
1361 return TRUE;
1362 }
1363 proc = proc->next;
1364 }
1365
1366 return FALSE;
1367 }
1368
1369
1370 /***********************************************************************
1371 * RemoveWindowSubclass [COMCTL32.412]
1372 *
1373 * Removes a window subclass.
1374 *
1375 * PARAMS
1376 * hWnd [in] Handle to the window which we are subclassing
1377 * pfnSubclass [in] Pointer to the subclass procedure
1378 * uID [in] Unique identifier of this subclass
1379 *
1380 * RETURNS
1381 * Success: non-zero
1382 * Failure: zero
1383 */
1384
1385 BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1386 {
1387 LPSUBCLASS_INFO stack;
1388 LPSUBCLASSPROCS prevproc = NULL;
1389 LPSUBCLASSPROCS proc;
1390 BOOL ret = FALSE;
1391
1392 TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1393
1394 /* Find the Subclass to remove */
1395 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1396 if (!stack)
1397 return FALSE;
1398
1399 proc = stack->SubclassProcs;
1400 while (proc) {
1401 if ((proc->id == uID) &&
1402 (proc->subproc == pfnSubclass)) {
1403
1404 if (!prevproc)
1405 stack->SubclassProcs = proc->next;
1406 else
1407 prevproc->next = proc->next;
1408
1409 if (stack->stackpos == proc)
1410 stack->stackpos = stack->stackpos->next;
1411
1412 Free (proc);
1413 ret = TRUE;
1414 break;
1415 }
1416 prevproc = proc;
1417 proc = proc->next;
1418 }
1419
1420 if (!stack->SubclassProcs && !stack->running) {
1421 TRACE("Last Subclass removed, cleaning up\n");
1422 /* clean up our heap and reset the original window procedure */
1423 if (IsWindowUnicode (hWnd))
1424 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1425 else
1426 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1427 Free (stack);
1428 RemovePropW( hWnd, COMCTL32_wSubclass );
1429 }
1430
1431 return ret;
1432 }
1433
1434 /***********************************************************************
1435 * COMCTL32_SubclassProc (internal)
1436 *
1437 * Window procedure for all subclassed windows.
1438 * Saves the current subclassing stack position to support nested messages
1439 */
1440 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1441 {
1442 LPSUBCLASS_INFO stack;
1443 LPSUBCLASSPROCS proc;
1444 LRESULT ret;
1445
1446 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1447
1448 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1449 if (!stack) {
1450 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1451 return 0;
1452 }
1453
1454 /* Save our old stackpos to properly handle nested messages */
1455 proc = stack->stackpos;
1456 stack->stackpos = stack->SubclassProcs;
1457 stack->running++;
1458 ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1459 stack->running--;
1460 stack->stackpos = proc;
1461
1462 if (!stack->SubclassProcs && !stack->running) {
1463 TRACE("Last Subclass removed, cleaning up\n");
1464 /* clean up our heap and reset the original window procedure */
1465 if (IsWindowUnicode (hWnd))
1466 SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1467 else
1468 SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1469 Free (stack);
1470 RemovePropW( hWnd, COMCTL32_wSubclass );
1471 }
1472 return ret;
1473 }
1474
1475 /***********************************************************************
1476 * DefSubclassProc [COMCTL32.413]
1477 *
1478 * Calls the next window procedure (i.e. the one before this subclass)
1479 *
1480 * PARAMS
1481 * hWnd [in] The window that we're subclassing
1482 * uMsg [in] Message
1483 * wParam [in] WPARAM
1484 * lParam [in] LPARAM
1485 *
1486 * RETURNS
1487 * Success: non-zero
1488 * Failure: zero
1489 */
1490
1491 LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1492 {
1493 LPSUBCLASS_INFO stack;
1494 LRESULT ret;
1495
1496 TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1497
1498 /* retrieve our little stack from the Properties */
1499 stack = GetPropW (hWnd, COMCTL32_wSubclass);
1500 if (!stack) {
1501 ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1502 return 0;
1503 }
1504
1505 /* If we are at the end of stack then we have to call the original
1506 * window procedure */
1507 if (!stack->stackpos) {
1508 if (IsWindowUnicode (hWnd))
1509 ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1510 else
1511 ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
1512 } else {
1513 const SUBCLASSPROCS *proc = stack->stackpos;
1514 stack->stackpos = stack->stackpos->next;
1515 /* call the Subclass procedure from the stack */
1516 ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1517 proc->id, proc->ref);
1518 }
1519
1520 return ret;
1521 }
1522
1523
1524 /***********************************************************************
1525 * COMCTL32_CreateToolTip [NOT AN API]
1526 *
1527 * Creates a tooltip for the control specified in hwnd and does all
1528 * necessary setup and notifications.
1529 *
1530 * PARAMS
1531 * hwndOwner [I] Handle to the window that will own the tool tip.
1532 *
1533 * RETURNS
1534 * Success: Handle of tool tip window.
1535 * Failure: NULL
1536 */
1537
1538 HWND
1539 COMCTL32_CreateToolTip(HWND hwndOwner)
1540 {
1541 HWND hwndToolTip;
1542
1543 hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1544 CW_USEDEFAULT, CW_USEDEFAULT,
1545 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1546 0, 0, 0);
1547
1548 /* Send NM_TOOLTIPSCREATED notification */
1549 if (hwndToolTip)
1550 {
1551 NMTOOLTIPSCREATED nmttc;
1552 /* true owner can be different if hwndOwner is a child window */
1553 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1554 nmttc.hdr.hwndFrom = hwndTrueOwner;
1555 nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1556 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1557 nmttc.hwndToolTips = hwndToolTip;
1558
1559 SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1560 GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1561 }
1562
1563 return hwndToolTip;
1564 }
1565
1566
1567 /***********************************************************************
1568 * COMCTL32_RefreshSysColors [NOT AN API]
1569 *
1570 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1571 * refresh the color values in the color structure
1572 *
1573 * PARAMS
1574 * none
1575 *
1576 * RETURNS
1577 * none
1578 */
1579
1580 VOID
1581 COMCTL32_RefreshSysColors(void)
1582 {
1583 comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1584 comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1585 comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1586 comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1587 comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1588 comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1589 comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1590 comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1591 comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1592 comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1593 comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1594 comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1595 comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1596 comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1597 comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1598 comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1599 comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1600 }
1601
1602 /***********************************************************************
1603 * COMCTL32_DrawInsertMark [NOT AN API]
1604 *
1605 * Draws an insertion mark (which looks similar to an 'I').
1606 *
1607 * PARAMS
1608 * hDC [I] Device context to draw onto.
1609 * lpRect [I] Co-ordinates of insertion mark.
1610 * clrInsertMark [I] Colour of the insertion mark.
1611 * bHorizontal [I] True if insert mark should be drawn horizontally,
1612 * vertical otherwise.
1613 *
1614 * RETURNS
1615 * none
1616 *
1617 * NOTES
1618 * Draws up to but not including the bottom co-ordinate when drawing
1619 * vertically or the right co-ordinate when horizontal.
1620 */
1621 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1622 {
1623 HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1624 HPEN hOldPen;
1625 static const DWORD adwPolyPoints[] = {4,4,4};
1626 LONG lCentre = (bHorizontal ?
1627 lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1628 lpRect->left + (lpRect->right - lpRect->left)/2);
1629 LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1630 LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1631 const POINT aptInsertMark[] =
1632 {
1633 /* top (V) or left (H) arrow */
1634 {lCentre , l1 + 2},
1635 {lCentre - 2, l1 },
1636 {lCentre + 3, l1 },
1637 {lCentre + 1, l1 + 2},
1638 /* middle line */
1639 {lCentre , l2 - 2},
1640 {lCentre , l1 - 1},
1641 {lCentre + 1, l1 - 1},
1642 {lCentre + 1, l2 - 2},
1643 /* bottom (V) or right (H) arrow */
1644 {lCentre , l2 - 3},
1645 {lCentre - 2, l2 - 1},
1646 {lCentre + 3, l2 - 1},
1647 {lCentre + 1, l2 - 3},
1648 };
1649 hOldPen = SelectObject(hDC, hPen);
1650 PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
1651 SelectObject(hDC, hOldPen);
1652 DeleteObject(hPen);
1653 }
1654
1655 /***********************************************************************
1656 * COMCTL32_EnsureBitmapSize [internal]
1657 *
1658 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1659 * the height is at least cyMinHeight. If the bitmap already has these
1660 * dimensions nothing changes.
1661 *
1662 * PARAMS
1663 * hBitmap [I/O] Bitmap to modify. The handle may change
1664 * cxMinWidth [I] If the width of the bitmap is smaller, then it will
1665 * be enlarged to this value
1666 * cyMinHeight [I] If the height of the bitmap is smaller, then it will
1667 * be enlarged to this value
1668 * cyBackground [I] The color with which the new area will be filled
1669 *
1670 * RETURNS
1671 * none
1672 */
1673 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1674 {
1675 int cxNew, cyNew;
1676 BITMAP bmp;
1677 HBITMAP hNewBitmap;
1678 HBITMAP hNewDCBitmap, hOldDCBitmap;
1679 HBRUSH hNewDCBrush;
1680 HDC hdcNew, hdcOld;
1681
1682 if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1683 return;
1684 cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1685 cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1686 if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1687 return;
1688
1689 hdcNew = CreateCompatibleDC(NULL);
1690 hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1691 hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1692 hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1693
1694 hdcOld = CreateCompatibleDC(NULL);
1695 hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1696
1697 BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1698 if (bmp.bmWidth < cxMinWidth)
1699 PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1700 if (bmp.bmHeight < cyMinHeight)
1701 PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1702 if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1703 PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1704
1705 SelectObject(hdcNew, hNewDCBitmap);
1706 DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1707 DeleteDC(hdcNew);
1708 SelectObject(hdcOld, hOldDCBitmap);
1709 DeleteDC(hdcOld);
1710
1711 DeleteObject(*pBitmap);
1712 *pBitmap = hNewBitmap;
1713 return;
1714 }
1715
1716 void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1717 {
1718 HDC hdc = GetDC(NULL);
1719 HFONT hOldFont;
1720
1721 hOldFont = SelectObject(hdc, hFont);
1722 GetTextMetricsW(hdc, ptm);
1723 SelectObject(hdc, hOldFont);
1724 ReleaseDC(NULL, hdc);
1725 }
1726
1727 #ifndef OCM__BASE /* avoid including olectl.h */
1728 #define OCM__BASE (WM_USER+0x1c00)
1729 #endif
1730
1731 /***********************************************************************
1732 * COMCTL32_IsReflectedMessage [internal]
1733 *
1734 * Some parents reflect notify messages - for some messages sent by the child,
1735 * they send it back with the message code increased by OCM__BASE (0x2000).
1736 * This allows better subclassing of controls. We don't need to handle such
1737 * messages but we don't want to print ERRs for them, so this helper function
1738 * identifies them.
1739 *
1740 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1741 * collision with defined CCM_ codes.
1742 */
1743 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1744 {
1745 switch (uMsg)
1746 {
1747 case OCM__BASE + WM_COMMAND:
1748 case OCM__BASE + WM_CTLCOLORBTN:
1749 case OCM__BASE + WM_CTLCOLOREDIT:
1750 case OCM__BASE + WM_CTLCOLORDLG:
1751 case OCM__BASE + WM_CTLCOLORLISTBOX:
1752 case OCM__BASE + WM_CTLCOLORMSGBOX:
1753 case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1754 case OCM__BASE + WM_CTLCOLORSTATIC:
1755 case OCM__BASE + WM_DRAWITEM:
1756 case OCM__BASE + WM_MEASUREITEM:
1757 case OCM__BASE + WM_DELETEITEM:
1758 case OCM__BASE + WM_VKEYTOITEM:
1759 case OCM__BASE + WM_CHARTOITEM:
1760 case OCM__BASE + WM_COMPAREITEM:
1761 case OCM__BASE + WM_HSCROLL:
1762 case OCM__BASE + WM_VSCROLL:
1763 case OCM__BASE + WM_PARENTNOTIFY:
1764 case OCM__BASE + WM_NOTIFY:
1765 return TRUE;
1766 default:
1767 return FALSE;
1768 }
1769 }
1770
1771 /***********************************************************************
1772 * MirrorIcon [COMCTL32.414]
1773 *
1774 * Mirrors an icon so that it will appear correctly on a mirrored DC.
1775 *
1776 * PARAMS
1777 * phicon1 [I/O] Icon.
1778 * phicon2 [I/O] Icon.
1779 *
1780 * RETURNS
1781 * Success: TRUE.
1782 * Failure: FALSE.
1783 */
1784 BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1785 {
1786 FIXME("(%p, %p): stub\n", phicon1, phicon2);
1787 return FALSE;
1788 }
1789
1790 static inline BOOL IsDelimiter(WCHAR c)
1791 {
1792 switch(c)
1793 {
1794 case '/':
1795 case '\\':
1796 case '.':
1797 case ' ':
1798 return TRUE;
1799 }
1800 return FALSE;
1801 }
1802
1803 static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1804 {
1805 if (code == WB_ISDELIMITER)
1806 return IsDelimiter(lpch[ichCurrent]);
1807 else
1808 {
1809 int dir = (code == WB_LEFT) ? -1 : 1;
1810 for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1811 if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1812 }
1813 return ichCurrent;
1814 }
1815
1816 /***********************************************************************
1817 * SetPathWordBreakProc [COMCTL32.384]
1818 *
1819 * Sets the word break procedure for an edit control to one that understands
1820 * paths so that the user can jump over directories.
1821 *
1822 * PARAMS
1823 * hwnd [I] Handle to edit control.
1824 * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1825 *
1826 * RETURNS
1827 * Result from EM_SETWORDBREAKPROC message.
1828 */
1829 LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1830 {
1831 return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1832 (LPARAM)(bSet ? PathWordBreakProc : NULL));
1833 }
1834
1835 /***********************************************************************
1836 * DrawShadowText [COMCTL32.@]
1837 *
1838 * Draw text with shadow.
1839 */
1840 int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
1841 COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
1842 {
1843 COLORREF crOldText;
1844 RECT rcText;
1845 INT iRet, x, y, x2, y2;
1846 BYTE *pBits;
1847 HBITMAP hbm, hbmOld;
1848 BITMAPINFO bi;
1849 HDC hdcMem;
1850 HFONT hOldFont;
1851 BLENDFUNCTION bf;
1852
1853 /* Create 32 bit DIB section for the shadow */
1854 ZeroMemory(&bi, sizeof(bi));
1855 bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
1856 bi.bmiHeader.biWidth = prc->right - prc->left + 4;
1857 bi.bmiHeader.biHeight = prc->bottom - prc->top + 5; // bottom-up DIB
1858 bi.bmiHeader.biPlanes = 1;
1859 bi.bmiHeader.biBitCount = 32;
1860 bi.bmiHeader.biCompression = BI_RGB;
1861 hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0);
1862 if(!hbm)
1863 {
1864 ERR("CreateDIBSection failed\n");
1865 return 0;
1866 }
1867
1868 /* Create memory device context for new DIB section and select it */
1869 hdcMem = CreateCompatibleDC(hdc);
1870 if(!hdcMem)
1871 {
1872 ERR("CreateCompatibleDC failed\n");
1873 DeleteObject(hbm);
1874 return 0;
1875 }
1876
1877 hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
1878
1879 /* Draw text on our helper bitmap */
1880 hOldFont = (HFONT)SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
1881 SetTextColor(hdcMem, RGB(16, 16, 16));
1882 SetBkColor(hdcMem, RGB(0, 0, 0));
1883 SetBkMode(hdcMem, TRANSPARENT);
1884 SetRect(&rcText, 0, 0, prc->right - prc->left, prc->bottom - prc->top);
1885 DrawTextW(hdcMem, pszText, cch, &rcText, dwFlags);
1886 SelectObject(hdcMem, hOldFont);
1887
1888 /* Flush GDI so data pointed by pBits is valid */
1889 GdiFlush();
1890
1891 /* Set alpha of pixels (forget about colors for now. They will be changed in next loop).
1892 We copy text image 4*5 times and each time alpha is added */
1893 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1894 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1895 {
1896 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1897 UINT Alpha = 0;
1898
1899 for (x2 = x - 4 + 1; x2 <= x; ++x2)
1900 for (y2 = y; y2 < y + 5; ++y2)
1901 {
1902 if (x2 >= 0 && x2 < bi.bmiHeader.biWidth && y2 >= 0 && y2 < bi.bmiHeader.biHeight)
1903 {
1904 BYTE *pSrc = &pBits[(y2 * bi.bmiHeader.biWidth + x2) * 4];
1905 Alpha += pSrc[0];
1906 }
1907 }
1908
1909 if (Alpha > 255)
1910 Alpha = 255;
1911 pDest[3] = Alpha;
1912 }
1913
1914 /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */
1915 for (x = 0; x < bi.bmiHeader.biWidth; ++x)
1916 for (y = 0; y < bi.bmiHeader.biHeight; ++y)
1917 {
1918 BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
1919 pDest[0] = GetBValue(crShadow) * pDest[3] / 255;
1920 pDest[1] = GetGValue(crShadow) * pDest[3] / 255;
1921 pDest[2] = GetRValue(crShadow) * pDest[3] / 255;
1922 }
1923
1924 /* Fix ixOffset of the shadow (tested on Win) */
1925 ixOffset -= 3;
1926 iyOffset -= 3;
1927
1928 /* Alpha blend helper image to destination DC */
1929 bf.BlendOp = AC_SRC_OVER;
1930 bf.BlendFlags = 0;
1931 bf.SourceConstantAlpha = 255;
1932 bf.AlphaFormat = AC_SRC_ALPHA;
1933 if (!GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf))
1934 ERR("GdiAlphaBlend failed: %lu\n", GetLastError());
1935
1936 /* Delete the helper bitmap */
1937 SelectObject(hdcMem, hbmOld);
1938 DeleteObject(hbm);
1939 DeleteDC(hdcMem);
1940
1941 /* Finally draw the text over shadow */
1942 crOldText = SetTextColor(hdc, crText);
1943 SetBkMode(hdc, TRANSPARENT);
1944 iRet = DrawTextW(hdc, pszText, cch, prc, dwFlags);
1945 SetTextColor(hdc, crOldText);
1946
1947 return iRet;
1948 }
1949
1950 /***********************************************************************
1951 * TaskDialogIndirect [COMCTL32.@]
1952 */
1953 HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton,
1954 int *pnRadioButton, BOOL *pfVerificationFlagChecked)
1955 {
1956 UINT uType = 0;
1957 INT ret;
1958 FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
1959
1960 if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
1961 pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON &&
1962 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1963 uType |= MB_YESNOCANCEL;
1964 else
1965 if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
1966 pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON)
1967 uType |= MB_YESNO;
1968 else
1969 if (pTaskConfig->dwCommonButtons & TDCBF_RETRY_BUTTON &&
1970 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1971 uType |= MB_RETRYCANCEL;
1972 else
1973 if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON &&
1974 pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
1975 uType |= MB_OKCANCEL;
1976 else
1977 if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON)
1978 uType |= MB_OK;
1979 ret = MessageBoxW(pTaskConfig->hwndParent, pTaskConfig->pszMainInstruction,
1980 pTaskConfig->pszWindowTitle, uType);
1981 FIXME("dwCommonButtons=%x uType=%x ret=%x\n", pTaskConfig->dwCommonButtons, uType, ret);
1982
1983 if (pnButton) *pnButton = ret;
1984 if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
1985 if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
1986 return S_OK;
1987 }
1988
1989 /***********************************************************************
1990 * LoadIconWithScaleDown [COMCTL32.@]
1991 */
1992 HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1993 {
1994 TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1995
1996 *icon = NULL;
1997
1998 if (!name)
1999 return E_INVALIDARG;
2000
2001 *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
2002 (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
2003 if (!*icon)
2004 return HRESULT_FROM_WIN32(GetLastError());
2005
2006 return S_OK;
2007 }
2008
2009 /***********************************************************************
2010 * LoadIconMetric [COMCTL32.@]
2011 */
2012 HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
2013 {
2014 int cx, cy;
2015
2016 TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
2017
2018 if (size == LIM_SMALL)
2019 {
2020 cx = GetSystemMetrics(SM_CXSMICON);
2021 cy = GetSystemMetrics(SM_CYSMICON);
2022 }
2023 else if (size == LIM_LARGE)
2024 {
2025 cx = GetSystemMetrics(SM_CXICON);
2026 cy = GetSystemMetrics(SM_CYICON);
2027 }
2028 else
2029 {
2030 *icon = NULL;
2031 return E_INVALIDARG;
2032 }
2033
2034 return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
2035 }