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