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