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