Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comctl32/commctrl.c
8599 views
1
/*
2
* Common controls functions
3
*
4
* Copyright 1997 Dimitrie O. Paun
5
* 1998 Juergen Schmied <[email protected]>
6
* Copyright 1998,2000 Eric Kohl
7
* Copyright 2014-2015 Michael Müller
8
*
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public
11
* License as published by the Free Software Foundation; either
12
* version 2.1 of the License, or (at your option) any later version.
13
*
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
18
*
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22
*
23
* NOTES
24
*
25
* This code was audited for completeness against the documented features
26
* of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
27
*
28
* Unless otherwise noted, we believe this code to be complete, as per
29
* the specification mentioned above.
30
* If you discover missing features, or bugs, please note them below.
31
*
32
* TODO
33
* -- implement GetMUILanguage + InitMUILanguage
34
* -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
35
* -- FIXMEs + BUGS (search for them)
36
*
37
* Control Classes
38
* -- ICC_ANIMATE_CLASS
39
* -- ICC_BAR_CLASSES
40
* -- ICC_COOL_CLASSES
41
* -- ICC_DATE_CLASSES
42
* -- ICC_HOTKEY_CLASS
43
* -- ICC_INTERNET_CLASSES
44
* -- ICC_LINK_CLASS
45
* -- ICC_LISTVIEW_CLASSES
46
* -- ICC_NATIVEFNTCTL_CLASS
47
* -- ICC_PAGESCROLLER_CLASS
48
* -- ICC_PROGRESS_CLASS
49
* -- ICC_STANDARD_CLASSES (not yet implemented)
50
* -- ICC_TAB_CLASSES
51
* -- ICC_TREEVIEW_CLASSES
52
* -- ICC_UPDOWN_CLASS
53
* -- ICC_USEREX_CLASSES
54
* -- ICC_WIN95_CLASSES
55
*/
56
57
#include <stdarg.h>
58
#include <string.h>
59
#include <stdlib.h>
60
61
#define COBJMACROS
62
#include "windef.h"
63
#include "winbase.h"
64
#include "wingdi.h"
65
#include "winuser.h"
66
#include "winnls.h"
67
#include "commctrl.h"
68
#include "winerror.h"
69
#include "winreg.h"
70
#include "comctl32.h"
71
#include "wine/debug.h"
72
73
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
74
75
76
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
77
78
static LPWSTR COMCTL32_wSubclass = NULL;
79
HMODULE COMCTL32_hModule = 0;
80
static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
81
HBRUSH COMCTL32_hPattern55AABrush = NULL;
82
COMCTL32_SysColor comctl32_color;
83
84
static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
85
86
static const WORD wPattern55AA[] =
87
{
88
0x5555, 0xaaaa, 0x5555, 0xaaaa,
89
0x5555, 0xaaaa, 0x5555, 0xaaaa
90
};
91
92
static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
93
94
static const struct
95
{
96
const WCHAR *nameW;
97
void (*fn_register)(void);
98
}
99
classes[] =
100
{
101
#if __WINE_COMCTL32_VERSION == 6
102
{L"Button", BUTTON_Register},
103
{L"ComboBox", COMBO_Register},
104
{L"ComboBoxEx32", COMBOEX_Register},
105
{L"ComboLBox", COMBOLBOX_Register},
106
{L"Edit", EDIT_Register},
107
{L"ListBox", LISTBOX_Register},
108
{L"msctls_hotkey32", HOTKEY_Register},
109
{L"msctls_progress32", PROGRESS_Register},
110
{L"msctls_statusbar32", STATUS_Register},
111
{L"msctls_trackbar32", TRACKBAR_Register},
112
{L"msctls_updown32", UPDOWN_Register},
113
{L"NativeFontCtl", NATIVEFONT_Register},
114
{L"ReBarWindow32", REBAR_Register},
115
{L"Static", STATIC_Register},
116
{L"SysAnimate32", ANIMATE_Register},
117
{L"SysDateTimePick32", DATETIME_Register},
118
{L"SysHeader32", HEADER_Register},
119
{L"SysIPAddress32", IPADDRESS_Register},
120
{L"SysLink", SYSLINK_Register},
121
{L"SysListView32", LISTVIEW_Register},
122
{L"SysMonthCal32", MONTHCAL_Register},
123
{L"SysPager", PAGER_Register},
124
{L"SysTabControl32", TAB_Register},
125
{L"SysTreeView32", TREEVIEW_Register},
126
{L"ToolbarWindow32", TOOLBAR_Register},
127
{L"tooltips_class32", TOOLTIPS_Register},
128
#else
129
{L"ComboBoxEx32", COMBOEX_Register},
130
{L"msctls_hotkey32", HOTKEY_Register},
131
{L"msctls_progress32", PROGRESS_Register},
132
{L"msctls_statusbar32", STATUS_Register},
133
{L"msctls_trackbar32", TRACKBAR_Register},
134
{L"msctls_updown32", UPDOWN_Register},
135
{L"NativeFontCtl", NATIVEFONT_Register},
136
{L"ReBarWindow32", REBAR_Register},
137
{L"SysAnimate32", ANIMATE_Register},
138
{L"SysDateTimePick32", DATETIME_Register},
139
{L"SysHeader32", HEADER_Register},
140
{L"SysIPAddress32", IPADDRESS_Register},
141
{L"SysListView32", LISTVIEW_Register},
142
{L"SysMonthCal32", MONTHCAL_Register},
143
{L"SysPager", PAGER_Register},
144
{L"SysTabControl32", TAB_Register},
145
{L"SysTreeView32", TREEVIEW_Register},
146
{L"ToolbarWindow32", TOOLBAR_Register},
147
{L"tooltips_class32", TOOLTIPS_Register},
148
#endif /* __WINE_COMCTL32_VERSION == 6 */
149
};
150
151
static void unregister_classes(void)
152
{
153
for (unsigned int i = 0; i < ARRAY_SIZE(classes); i++)
154
{
155
#if __WINE_COMCTL32_VERSION == 6
156
WCHAR versioned_class[40];
157
158
wcscpy(versioned_class, L"6.0.2600.2982!");
159
wcscat(versioned_class, classes[i].nameW);
160
UnregisterClassW(versioned_class, NULL);
161
#else
162
UnregisterClassW(classes[i].nameW, NULL);
163
#endif
164
}
165
}
166
167
BOOLEAN WINAPI RegisterClassNameW(const WCHAR *class)
168
{
169
int min = 0, max = ARRAY_SIZE(classes) - 1;
170
171
while (min <= max)
172
{
173
int res, pos = (min + max) / 2;
174
if (!(res = wcsicmp(class, classes[pos].nameW)))
175
{
176
classes[pos].fn_register();
177
return TRUE;
178
}
179
if (res < 0) max = pos - 1;
180
else min = pos + 1;
181
}
182
183
return FALSE;
184
}
185
186
/***********************************************************************
187
* DllMain [Internal]
188
*
189
* Initializes the internal 'COMCTL32.DLL'.
190
*
191
* PARAMS
192
* hinstDLL [I] handle to the 'dlls' instance
193
* fdwReason [I]
194
* lpvReserved [I] reserved, must be NULL
195
*
196
* RETURNS
197
* Success: TRUE
198
* Failure: FALSE
199
*/
200
201
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
202
{
203
TRACE("%p, %#lx, %p\n", hinstDLL, fdwReason, lpvReserved);
204
205
switch (fdwReason) {
206
case DLL_PROCESS_ATTACH:
207
DisableThreadLibraryCalls(hinstDLL);
208
209
COMCTL32_hModule = hinstDLL;
210
211
/* add global subclassing atom (used by 'tooltip' and 'updown') */
212
COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
213
TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
214
215
/* create local pattern brush */
216
COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
217
COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
218
219
/* Get all the colors at DLL load */
220
COMCTL32_RefreshSysColors();
221
break;
222
223
case DLL_PROCESS_DETACH:
224
if (lpvReserved) break;
225
226
/* unregister all common control classes */
227
unregister_classes ();
228
229
/* delete local pattern brush */
230
DeleteObject (COMCTL32_hPattern55AABrush);
231
DeleteObject (COMCTL32_hPattern55AABitmap);
232
233
/* delete global subclassing atom */
234
GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
235
TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
236
break;
237
}
238
239
return TRUE;
240
}
241
242
243
/***********************************************************************
244
* MenuHelp [COMCTL32.2]
245
*
246
* Handles the setting of status bar help messages when the user
247
* selects menu items.
248
*
249
* PARAMS
250
* uMsg [I] message (WM_MENUSELECT) (see NOTES)
251
* wParam [I] wParam of the message uMsg
252
* lParam [I] lParam of the message uMsg
253
* hMainMenu [I] handle to the application's main menu
254
* hInst [I] handle to the module that contains string resources
255
* hwndStatus [I] handle to the status bar window
256
* lpwIDs [I] pointer to an array of integers (see NOTES)
257
*
258
* RETURNS
259
* No return value
260
*
261
* NOTES
262
* The official documentation is incomplete!
263
* This is the correct documentation:
264
*
265
* uMsg:
266
* MenuHelp() does NOT handle WM_COMMAND messages! It only handles
267
* WM_MENUSELECT messages.
268
*
269
* lpwIDs:
270
* (will be written ...)
271
*/
272
273
VOID WINAPI
274
MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
275
HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
276
{
277
UINT uMenuID = 0;
278
279
if (!IsWindow (hwndStatus))
280
return;
281
282
switch (uMsg) {
283
case WM_MENUSELECT:
284
TRACE("WM_MENUSELECT wParam %#Ix, lParam %#Ix\n", wParam, lParam);
285
286
if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
287
/* menu was closed */
288
TRACE("menu was closed!\n");
289
SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
290
}
291
else {
292
/* menu item was selected */
293
if (HIWORD(wParam) & MF_POPUP)
294
uMenuID = *(lpwIDs+1);
295
else
296
uMenuID = (UINT)LOWORD(wParam);
297
TRACE("uMenuID = %u\n", uMenuID);
298
299
if (uMenuID) {
300
WCHAR szText[256];
301
302
if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
303
szText[0] = '\0';
304
305
SendMessageW (hwndStatus, SB_SETTEXTW,
306
255 | SBT_NOBORDERS, (LPARAM)szText);
307
SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
308
}
309
}
310
break;
311
312
case WM_COMMAND :
313
TRACE("WM_COMMAND wParam %#Ix, lParam %#Ix\n", wParam, lParam);
314
/* WM_COMMAND is not invalid since it is documented
315
* in the windows api reference. So don't output
316
* any FIXME for WM_COMMAND
317
*/
318
WARN("We don't care about the WM_COMMAND\n");
319
break;
320
321
default:
322
FIXME("Invalid Message 0x%x!\n", uMsg);
323
break;
324
}
325
}
326
327
328
/***********************************************************************
329
* ShowHideMenuCtl [COMCTL32.3]
330
*
331
* Shows or hides controls and updates the corresponding menu item.
332
*
333
* PARAMS
334
* hwnd [I] handle to the client window.
335
* uFlags [I] menu command id.
336
* lpInfo [I] pointer to an array of integers. (See NOTES.)
337
*
338
* RETURNS
339
* Success: TRUE
340
* Failure: FALSE
341
*
342
* NOTES
343
* The official documentation is incomplete!
344
* This is the correct documentation:
345
*
346
* hwnd
347
* Handle to the window that contains the menu and controls.
348
*
349
* uFlags
350
* Identifier of the menu item to receive or lose a check mark.
351
*
352
* lpInfo
353
* The array of integers contains pairs of values. BOTH values of
354
* the first pair must be the handles to the application's main menu.
355
* Each subsequent pair consists of a menu id and control id.
356
*/
357
358
BOOL WINAPI
359
ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
360
{
361
LPINT lpMenuId;
362
363
TRACE("%p, %Ix, %p\n", hwnd, uFlags, lpInfo);
364
365
if (lpInfo == NULL)
366
return FALSE;
367
368
if (!(lpInfo[0]) || !(lpInfo[1]))
369
return FALSE;
370
371
/* search for control */
372
lpMenuId = &lpInfo[2];
373
while (*lpMenuId != uFlags)
374
lpMenuId += 2;
375
376
if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
377
/* uncheck menu item */
378
CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
379
380
/* hide control */
381
lpMenuId++;
382
SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
383
SWP_HIDEWINDOW);
384
}
385
else {
386
/* check menu item */
387
CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
388
389
/* show control */
390
lpMenuId++;
391
SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
392
SWP_SHOWWINDOW);
393
}
394
395
return TRUE;
396
}
397
398
399
/***********************************************************************
400
* GetEffectiveClientRect [COMCTL32.4]
401
*
402
* Calculates the coordinates of a rectangle in the client area.
403
*
404
* PARAMS
405
* hwnd [I] handle to the client window.
406
* lpRect [O] pointer to the rectangle of the client window
407
* lpInfo [I] pointer to an array of integers (see NOTES)
408
*
409
* RETURNS
410
* No return value.
411
*
412
* NOTES
413
* The official documentation is incomplete!
414
* This is the correct documentation:
415
*
416
* lpInfo
417
* (will be written ...)
418
*/
419
420
VOID WINAPI
421
GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
422
{
423
RECT rcCtrl;
424
const INT *lpRun;
425
HWND hwndCtrl;
426
427
TRACE("(%p %p %p)\n",
428
hwnd, lpRect, lpInfo);
429
430
GetClientRect (hwnd, lpRect);
431
lpRun = lpInfo;
432
433
do {
434
lpRun += 2;
435
if (*lpRun == 0)
436
return;
437
lpRun++;
438
hwndCtrl = GetDlgItem (hwnd, *lpRun);
439
if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
440
TRACE("control id 0x%x\n", *lpRun);
441
GetWindowRect (hwndCtrl, &rcCtrl);
442
MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
443
SubtractRect (lpRect, lpRect, &rcCtrl);
444
}
445
lpRun++;
446
} while (*lpRun);
447
}
448
449
void COMCTL32_DrawStatusText(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style, BOOL draw_background)
450
{
451
RECT r = *lprc;
452
UINT border;
453
COLORREF oldbkcolor;
454
455
if (draw_background)
456
{
457
if (style & SBT_POPOUT)
458
border = BDR_RAISEDOUTER;
459
else if (style & SBT_NOBORDERS)
460
border = 0;
461
else
462
border = BDR_SUNKENOUTER;
463
464
oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
465
DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
466
SetBkColor (hdc, oldbkcolor);
467
}
468
469
/* now draw text */
470
if (text) {
471
int oldbkmode = SetBkMode (hdc, TRANSPARENT);
472
COLORREF oldtextcolor;
473
UINT align = DT_LEFT;
474
int strCnt = 0;
475
476
oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
477
if (style & SBT_RTLREADING)
478
FIXME("Unsupported RTL style!\n");
479
r.left += 3;
480
do {
481
if (*text == '\t') {
482
if (strCnt) {
483
DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
484
strCnt = 0;
485
}
486
if (align==DT_RIGHT) {
487
break;
488
}
489
align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
490
} else {
491
strCnt++;
492
}
493
} while(*text++);
494
495
if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
496
SetBkMode (hdc, oldbkmode);
497
SetTextColor (hdc, oldtextcolor);
498
}
499
}
500
501
/***********************************************************************
502
* DrawStatusTextW [COMCTL32.@]
503
*
504
* Draws text with borders, like in a status bar.
505
*
506
* PARAMS
507
* hdc [I] handle to the window's display context
508
* lprc [I] pointer to a rectangle
509
* text [I] pointer to the text
510
* style [I] drawing style
511
*
512
* RETURNS
513
* No return value.
514
*
515
* NOTES
516
* The style variable can have one of the following values:
517
* (will be written ...)
518
*/
519
520
void WINAPI DrawStatusTextW(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
521
{
522
COMCTL32_DrawStatusText(hdc, lprc, text, style, TRUE);
523
}
524
525
/***********************************************************************
526
* DrawStatusText [COMCTL32.@]
527
* DrawStatusTextA [COMCTL32.5]
528
*
529
* Draws text with borders, like in a status bar.
530
*
531
* PARAMS
532
* hdc [I] handle to the window's display context
533
* lprc [I] pointer to a rectangle
534
* text [I] pointer to the text
535
* style [I] drawing style
536
*
537
* RETURNS
538
* No return value.
539
*/
540
541
void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
542
{
543
INT len;
544
LPWSTR textW = NULL;
545
546
if ( text ) {
547
if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
548
if ( (textW = Alloc( len * sizeof(WCHAR) )) )
549
MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
550
}
551
}
552
DrawStatusTextW( hdc, lprc, textW, style );
553
Free( textW );
554
}
555
556
557
/***********************************************************************
558
* CreateStatusWindow [COMCTL32.@]
559
* CreateStatusWindowA [COMCTL32.6]
560
*
561
* Creates a status bar
562
*
563
* PARAMS
564
* style [I] window style
565
* text [I] pointer to the window text
566
* parent [I] handle to the parent window
567
* wid [I] control id of the status bar
568
*
569
* RETURNS
570
* Success: handle to the status window
571
* Failure: 0
572
*/
573
574
HWND WINAPI
575
CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
576
{
577
return CreateWindowA(STATUSCLASSNAMEA, text, style,
578
CW_USEDEFAULT, CW_USEDEFAULT,
579
CW_USEDEFAULT, CW_USEDEFAULT,
580
parent, (HMENU)(DWORD_PTR)wid, 0, 0);
581
}
582
583
584
/***********************************************************************
585
* CreateStatusWindowW [COMCTL32.@]
586
*
587
* Creates a status bar control
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
CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
602
{
603
return CreateWindowW(STATUSCLASSNAMEW, 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
* CreateUpDownControl [COMCTL32.16]
612
*
613
* Creates an up-down control
614
*
615
* PARAMS
616
* style [I] window styles
617
* x [I] horizontal position of the control
618
* y [I] vertical position of the control
619
* cx [I] with of the control
620
* cy [I] height of the control
621
* parent [I] handle to the parent window
622
* id [I] the control's identifier
623
* inst [I] handle to the application's module instance
624
* buddy [I] handle to the buddy window, can be NULL
625
* maxVal [I] upper limit of the control
626
* minVal [I] lower limit of the control
627
* curVal [I] current value of the control
628
*
629
* RETURNS
630
* Success: handle to the updown control
631
* Failure: 0
632
*/
633
634
HWND WINAPI
635
CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
636
HWND parent, INT id, HINSTANCE inst,
637
HWND buddy, INT maxVal, INT minVal, INT curVal)
638
{
639
HWND hUD =
640
CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
641
parent, (HMENU)(DWORD_PTR)id, inst, 0);
642
if (hUD) {
643
SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
644
SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
645
SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
646
}
647
648
return hUD;
649
}
650
651
652
/***********************************************************************
653
* InitCommonControls [COMCTL32.17]
654
*
655
* Registers the common controls.
656
*
657
* PARAMS
658
* No parameters.
659
*
660
* RETURNS
661
* No return values.
662
*
663
* NOTES
664
* This function is just a dummy - all the controls are registered at
665
* the DLL initialization time. See InitCommonControlsEx for details.
666
*/
667
668
VOID WINAPI
669
InitCommonControls (void)
670
{
671
}
672
673
674
/***********************************************************************
675
* InitCommonControlsEx [COMCTL32.@]
676
*
677
* Registers the common controls.
678
*
679
* PARAMS
680
* lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
681
*
682
* RETURNS
683
* Success: TRUE
684
* Failure: FALSE
685
*
686
* NOTES
687
* Probably all versions of comctl32 initializes the Win95 controls in DllMain
688
* during DLL initialization. Starting from comctl32 v5.82 all the controls
689
* are initialized there. We follow this behaviour and this function is just
690
* a dummy.
691
*
692
* Note: when writing programs under Windows, if you don't call any function
693
* from comctl32 the linker may not link this DLL. If InitCommonControlsEx
694
* was the only comctl32 function you were calling and you remove it you may
695
* have a false impression that InitCommonControlsEx actually did something.
696
*/
697
698
BOOL WINAPI
699
InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
700
{
701
if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
702
return FALSE;
703
704
TRACE("%#lx\n", lpInitCtrls->dwICC);
705
return TRUE;
706
}
707
708
709
/***********************************************************************
710
* CreateToolbarEx [COMCTL32.@]
711
*
712
* Creates a toolbar window.
713
*
714
* PARAMS
715
* hwnd
716
* style
717
* wID
718
* nBitmaps
719
* hBMInst
720
* wBMID
721
* lpButtons
722
* iNumButtons
723
* dxButton
724
* dyButton
725
* dxBitmap
726
* dyBitmap
727
* uStructSize
728
*
729
* RETURNS
730
* Success: handle to the tool bar control
731
* Failure: 0
732
*/
733
734
HWND WINAPI
735
CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
736
HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
737
INT iNumButtons, INT dxButton, INT dyButton,
738
INT dxBitmap, INT dyBitmap, UINT uStructSize)
739
{
740
HWND hwndTB;
741
742
hwndTB =
743
CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
744
hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
745
if(hwndTB) {
746
TBADDBITMAP tbab;
747
748
SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
749
750
/* set bitmap and button size */
751
/*If CreateToolbarEx receives 0, windows sets default values*/
752
if (dxBitmap < 0)
753
dxBitmap = 16;
754
if (dyBitmap < 0)
755
dyBitmap = 16;
756
if (dxBitmap == 0 || dyBitmap == 0)
757
dxBitmap = dyBitmap = 16;
758
SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
759
760
if (dxButton < 0)
761
dxButton = dxBitmap;
762
if (dyButton < 0)
763
dyButton = dyBitmap;
764
/* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
765
if (dxButton != 0 && dyButton != 0)
766
SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
767
768
769
/* add bitmaps */
770
if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
771
{
772
tbab.hInst = hBMInst;
773
tbab.nID = wBMID;
774
775
SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
776
}
777
/* add buttons */
778
if(iNumButtons > 0)
779
SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
780
}
781
782
return hwndTB;
783
}
784
785
786
/***********************************************************************
787
* CreateMappedBitmap [COMCTL32.8]
788
*
789
* Loads a bitmap resource using a colour map.
790
*
791
* PARAMS
792
* hInstance [I] Handle to the module containing the bitmap.
793
* idBitmap [I] The bitmap resource ID.
794
* wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
795
* lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
796
* iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap.
797
*
798
* RETURNS
799
* Success: handle to the new bitmap
800
* Failure: 0
801
*/
802
803
HBITMAP WINAPI
804
CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
805
LPCOLORMAP lpColorMap, INT iNumMaps)
806
{
807
HGLOBAL hglb;
808
HRSRC hRsrc;
809
const BITMAPINFOHEADER *lpBitmap;
810
LPBITMAPINFOHEADER lpBitmapInfo;
811
UINT nSize, nColorTableSize, iColor;
812
RGBQUAD *pColorTable;
813
INT i, iMaps, nWidth, nHeight;
814
HDC hdcScreen;
815
HBITMAP hbm;
816
LPCOLORMAP sysColorMap;
817
COLORREF cRef;
818
COLORMAP internalColorMap[4] =
819
{{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
820
821
/* initialize pointer to colortable and default color table */
822
if (lpColorMap) {
823
iMaps = iNumMaps;
824
sysColorMap = lpColorMap;
825
}
826
else {
827
internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
828
internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
829
internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
830
internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
831
iMaps = 4;
832
sysColorMap = internalColorMap;
833
}
834
835
hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
836
if (hRsrc == 0)
837
return 0;
838
hglb = LoadResource (hInstance, hRsrc);
839
if (hglb == 0)
840
return 0;
841
lpBitmap = LockResource (hglb);
842
if (lpBitmap == NULL)
843
return 0;
844
845
if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
846
nColorTableSize = lpBitmap->biClrUsed;
847
else if (lpBitmap->biBitCount <= 8)
848
nColorTableSize = (1 << lpBitmap->biBitCount);
849
else
850
nColorTableSize = 0;
851
nSize = lpBitmap->biSize;
852
if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
853
nSize += 3 * sizeof(DWORD);
854
nSize += nColorTableSize * sizeof(RGBQUAD);
855
lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
856
if (lpBitmapInfo == NULL)
857
return 0;
858
RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
859
860
pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
861
862
for (iColor = 0; iColor < nColorTableSize; iColor++) {
863
for (i = 0; i < iMaps; i++) {
864
cRef = RGB(pColorTable[iColor].rgbRed,
865
pColorTable[iColor].rgbGreen,
866
pColorTable[iColor].rgbBlue);
867
if ( cRef == sysColorMap[i].from) {
868
#if 0
869
if (wFlags & CBS_MASKED) {
870
if (sysColorMap[i].to != COLOR_BTNTEXT)
871
pColorTable[iColor] = RGB(255, 255, 255);
872
}
873
else
874
#endif
875
pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
876
pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
877
pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
878
break;
879
}
880
}
881
}
882
nWidth = lpBitmapInfo->biWidth;
883
nHeight = lpBitmapInfo->biHeight;
884
hdcScreen = GetDC (NULL);
885
hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
886
if (hbm) {
887
HDC hdcDst = CreateCompatibleDC (hdcScreen);
888
HBITMAP hbmOld = SelectObject (hdcDst, hbm);
889
const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
890
StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
891
lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
892
SRCCOPY);
893
SelectObject (hdcDst, hbmOld);
894
DeleteDC (hdcDst);
895
}
896
ReleaseDC (NULL, hdcScreen);
897
GlobalFree (lpBitmapInfo);
898
FreeResource (hglb);
899
900
return hbm;
901
}
902
903
904
/***********************************************************************
905
* CreateToolbar [COMCTL32.7]
906
*
907
* Creates a toolbar control.
908
*
909
* PARAMS
910
* hwnd
911
* style
912
* wID
913
* nBitmaps
914
* hBMInst
915
* wBMID
916
* lpButtons
917
* iNumButtons
918
*
919
* RETURNS
920
* Success: handle to the tool bar control
921
* Failure: 0
922
*
923
* NOTES
924
* Do not use this function anymore. Use CreateToolbarEx instead.
925
*/
926
927
HWND WINAPI
928
CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
929
HINSTANCE hBMInst, UINT wBMID,
930
LPCTBBUTTON lpButtons,INT iNumButtons)
931
{
932
return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
933
hBMInst, wBMID, lpButtons,
934
iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
935
}
936
937
938
#if __WINE_COMCTL32_VERSION == 6
939
/***********************************************************************
940
* DllInstall (COMCTL32.@)
941
*
942
* Installs the ComCtl32 DLL.
943
*
944
* RETURNS
945
* Success: S_OK
946
* Failure: A HRESULT error
947
*/
948
HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
949
{
950
TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
951
return S_OK;
952
}
953
#endif /* __WINE_COMCTL32_VERSION == 6 */
954
955
/***********************************************************************
956
* _TrackMouseEvent [COMCTL32.@]
957
*
958
* Requests notification of mouse events
959
*
960
* During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
961
* to the hwnd specified in the ptme structure. After the event message
962
* is posted to the hwnd, the entry in the queue is removed.
963
*
964
* If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
965
* ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
966
* immediately and the TME_LEAVE flag being ignored.
967
*
968
* PARAMS
969
* ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
970
*
971
* RETURNS
972
* Success: non-zero
973
* Failure: zero
974
*
975
* IMPLEMENTATION moved to USER32.TrackMouseEvent
976
*
977
*/
978
979
BOOL WINAPI
980
_TrackMouseEvent (TRACKMOUSEEVENT *ptme)
981
{
982
return TrackMouseEvent (ptme);
983
}
984
985
/*************************************************************************
986
* GetMUILanguage [COMCTL32.@]
987
*
988
* Returns the user interface language in use by the current process.
989
*
990
* RETURNS
991
* Language ID in use by the current process.
992
*/
993
LANGID WINAPI GetMUILanguage (VOID)
994
{
995
return COMCTL32_uiLang;
996
}
997
998
999
/*************************************************************************
1000
* InitMUILanguage [COMCTL32.@]
1001
*
1002
* Sets the user interface language to be used by the current process.
1003
*
1004
* RETURNS
1005
* Nothing.
1006
*/
1007
VOID WINAPI InitMUILanguage (LANGID uiLang)
1008
{
1009
COMCTL32_uiLang = uiLang;
1010
}
1011
1012
1013
/***********************************************************************
1014
* SetWindowSubclass [COMCTL32.410]
1015
*
1016
* Starts a window subclass
1017
*
1018
* PARAMS
1019
* hWnd [in] handle to window subclass.
1020
* pfnSubclass [in] Pointer to new window procedure.
1021
* uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
1022
* dwRef [in] Reference data to pass to window procedure.
1023
*
1024
* RETURNS
1025
* Success: non-zero
1026
* Failure: zero
1027
*
1028
* BUGS
1029
* If an application manually subclasses a window after subclassing it with
1030
* this API and then with this API again, then none of the previous
1031
* subclasses get called or the original window procedure.
1032
*/
1033
1034
BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1035
UINT_PTR uIDSubclass, DWORD_PTR dwRef)
1036
{
1037
LPSUBCLASS_INFO stack;
1038
LPSUBCLASSPROCS proc;
1039
1040
TRACE("%p, %p, %Ix, %Ix\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1041
1042
if (!hWnd || !pfnSubclass)
1043
return FALSE;
1044
1045
/* Since the window procedure that we set here has two additional arguments,
1046
* we can't simply set it as the new window procedure of the window. So we
1047
* set our own window procedure and then calculate the other two arguments
1048
* from there. */
1049
1050
/* See if we have been called for this window */
1051
stack = GetPropW (hWnd, COMCTL32_wSubclass);
1052
if (!stack) {
1053
/* allocate stack */
1054
stack = Alloc (sizeof(SUBCLASS_INFO));
1055
if (!stack) {
1056
ERR ("Failed to allocate our Subclassing stack\n");
1057
return FALSE;
1058
}
1059
SetPropW (hWnd, COMCTL32_wSubclass, stack);
1060
1061
/* set window procedure to our own and save the current one */
1062
stack->is_unicode = IsWindowUnicode (hWnd);
1063
stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
1064
(DWORD_PTR)COMCTL32_SubclassProc);
1065
}
1066
else {
1067
/* Check to see if we have called this function with the same uIDSubClass
1068
* and pfnSubclass */
1069
proc = stack->SubclassProcs;
1070
while (proc) {
1071
if ((proc->id == uIDSubclass) &&
1072
(proc->subproc == pfnSubclass)) {
1073
proc->ref = dwRef;
1074
return TRUE;
1075
}
1076
proc = proc->next;
1077
}
1078
}
1079
1080
proc = Alloc(sizeof(SUBCLASSPROCS));
1081
if (!proc) {
1082
ERR ("Failed to allocate subclass entry in stack\n");
1083
if (stack->is_unicode)
1084
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1085
else
1086
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1087
Free (stack);
1088
RemovePropW( hWnd, COMCTL32_wSubclass );
1089
return FALSE;
1090
}
1091
1092
proc->subproc = pfnSubclass;
1093
proc->ref = dwRef;
1094
proc->id = uIDSubclass;
1095
proc->next = stack->SubclassProcs;
1096
stack->SubclassProcs = proc;
1097
1098
return TRUE;
1099
}
1100
1101
1102
/***********************************************************************
1103
* GetWindowSubclass [COMCTL32.411]
1104
*
1105
* Gets the Reference data from a subclass.
1106
*
1107
* PARAMS
1108
* hWnd [in] Handle to the window which we are subclassing
1109
* pfnSubclass [in] Pointer to the subclass procedure
1110
* uID [in] Unique identifier of the subclassing procedure
1111
* pdwRef [out] Pointer to the reference data
1112
*
1113
* RETURNS
1114
* Success: Non-zero
1115
* Failure: 0
1116
*/
1117
1118
BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
1119
UINT_PTR uID, DWORD_PTR *pdwRef)
1120
{
1121
const SUBCLASS_INFO *stack;
1122
const SUBCLASSPROCS *proc;
1123
1124
TRACE("%p, %p, %Ix, %p\n", hWnd, pfnSubclass, uID, pdwRef);
1125
1126
/* See if we have been called for this window */
1127
stack = GetPropW (hWnd, COMCTL32_wSubclass);
1128
if (!stack)
1129
goto done;
1130
1131
proc = stack->SubclassProcs;
1132
while (proc) {
1133
if ((proc->id == uID) &&
1134
(proc->subproc == pfnSubclass)) {
1135
if (pdwRef)
1136
*pdwRef = proc->ref;
1137
return TRUE;
1138
}
1139
proc = proc->next;
1140
}
1141
1142
done:
1143
if (pdwRef)
1144
*pdwRef = 0;
1145
return FALSE;
1146
}
1147
1148
1149
/***********************************************************************
1150
* RemoveWindowSubclass [COMCTL32.412]
1151
*
1152
* Removes a window subclass.
1153
*
1154
* PARAMS
1155
* hWnd [in] Handle to the window which we are subclassing
1156
* pfnSubclass [in] Pointer to the subclass procedure
1157
* uID [in] Unique identifier of this subclass
1158
*
1159
* RETURNS
1160
* Success: non-zero
1161
* Failure: zero
1162
*/
1163
1164
BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
1165
{
1166
LPSUBCLASS_INFO stack;
1167
LPSUBCLASSPROCS prevproc = NULL;
1168
LPSUBCLASSPROCS proc;
1169
BOOL ret = FALSE;
1170
1171
TRACE("%p, %p, %Ix.\n", hWnd, pfnSubclass, uID);
1172
1173
/* Find the Subclass to remove */
1174
stack = GetPropW (hWnd, COMCTL32_wSubclass);
1175
if (!stack)
1176
return FALSE;
1177
1178
proc = stack->SubclassProcs;
1179
while (proc) {
1180
if ((proc->id == uID) &&
1181
(proc->subproc == pfnSubclass)) {
1182
1183
if (!prevproc)
1184
stack->SubclassProcs = proc->next;
1185
else
1186
prevproc->next = proc->next;
1187
1188
if (stack->stackpos == proc)
1189
stack->stackpos = stack->stackpos->next;
1190
1191
Free (proc);
1192
ret = TRUE;
1193
break;
1194
}
1195
prevproc = proc;
1196
proc = proc->next;
1197
}
1198
1199
if (!stack->SubclassProcs && !stack->running) {
1200
TRACE("Last Subclass removed, cleaning up\n");
1201
/* clean up our heap and reset the original window procedure */
1202
if ((WNDPROC)GetWindowLongPtrW (hWnd, GWLP_WNDPROC) != COMCTL32_SubclassProc)
1203
WARN("Window procedure has been modified, skipping restore\n");
1204
else if (stack->is_unicode)
1205
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1206
else
1207
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1208
Free (stack);
1209
RemovePropW( hWnd, COMCTL32_wSubclass );
1210
}
1211
1212
return ret;
1213
}
1214
1215
/***********************************************************************
1216
* COMCTL32_SubclassProc (internal)
1217
*
1218
* Window procedure for all subclassed windows.
1219
* Saves the current subclassing stack position to support nested messages
1220
*/
1221
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1222
{
1223
LPSUBCLASS_INFO stack;
1224
LPSUBCLASSPROCS proc;
1225
LRESULT ret;
1226
1227
TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1228
1229
stack = GetPropW (hWnd, COMCTL32_wSubclass);
1230
if (!stack) {
1231
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1232
return 0;
1233
}
1234
1235
/* Save our old stackpos to properly handle nested messages */
1236
proc = stack->stackpos;
1237
stack->stackpos = stack->SubclassProcs;
1238
stack->running++;
1239
ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1240
stack->running--;
1241
stack->stackpos = proc;
1242
1243
if (!stack->SubclassProcs && !stack->running) {
1244
TRACE("Last Subclass removed, cleaning up\n");
1245
/* clean up our heap and reset the original window procedure */
1246
if (stack->is_unicode)
1247
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1248
else
1249
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1250
Free (stack);
1251
RemovePropW( hWnd, COMCTL32_wSubclass );
1252
}
1253
return ret;
1254
}
1255
1256
/***********************************************************************
1257
* DefSubclassProc [COMCTL32.413]
1258
*
1259
* Calls the next window procedure (i.e. the one before this subclass)
1260
*
1261
* PARAMS
1262
* hWnd [in] The window that we're subclassing
1263
* uMsg [in] Message
1264
* wParam [in] WPARAM
1265
* lParam [in] LPARAM
1266
*
1267
* RETURNS
1268
* Success: non-zero
1269
* Failure: zero
1270
*/
1271
1272
LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1273
{
1274
LPSUBCLASS_INFO stack;
1275
LRESULT ret;
1276
1277
TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
1278
1279
/* retrieve our little stack from the Properties */
1280
stack = GetPropW (hWnd, COMCTL32_wSubclass);
1281
if (!stack) {
1282
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1283
return 0;
1284
}
1285
1286
/* If we are at the end of stack then we have to call the original
1287
* window procedure */
1288
if (!stack->stackpos) {
1289
ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1290
} else {
1291
const SUBCLASSPROCS *proc = stack->stackpos;
1292
stack->stackpos = stack->stackpos->next;
1293
/* call the Subclass procedure from the stack */
1294
ret = proc->subproc (hWnd, uMsg, wParam, lParam,
1295
proc->id, proc->ref);
1296
}
1297
1298
return ret;
1299
}
1300
1301
1302
/***********************************************************************
1303
* COMCTL32_CreateToolTip [NOT AN API]
1304
*
1305
* Creates a tooltip for the control specified in hwnd and does all
1306
* necessary setup and notifications.
1307
*
1308
* PARAMS
1309
* hwndOwner [I] Handle to the window that will own the tool tip.
1310
*
1311
* RETURNS
1312
* Success: Handle of tool tip window.
1313
* Failure: NULL
1314
*/
1315
1316
HWND
1317
COMCTL32_CreateToolTip(HWND hwndOwner)
1318
{
1319
HWND hwndToolTip;
1320
1321
hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1322
CW_USEDEFAULT, CW_USEDEFAULT,
1323
CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1324
0, 0, 0);
1325
1326
/* Send NM_TOOLTIPSCREATED notification */
1327
if (hwndToolTip)
1328
{
1329
NMTOOLTIPSCREATED nmttc;
1330
/* true owner can be different if hwndOwner is a child window */
1331
HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1332
nmttc.hdr.hwndFrom = hwndTrueOwner;
1333
nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1334
nmttc.hdr.code = NM_TOOLTIPSCREATED;
1335
nmttc.hwndToolTips = hwndToolTip;
1336
1337
SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1338
GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
1339
}
1340
1341
return hwndToolTip;
1342
}
1343
1344
1345
/***********************************************************************
1346
* COMCTL32_RefreshSysColors [NOT AN API]
1347
*
1348
* Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
1349
* refresh the color values in the color structure
1350
*
1351
* PARAMS
1352
* none
1353
*
1354
* RETURNS
1355
* none
1356
*/
1357
1358
VOID
1359
COMCTL32_RefreshSysColors(void)
1360
{
1361
comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
1362
comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
1363
comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
1364
comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
1365
comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
1366
comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1367
comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1368
comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
1369
comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
1370
comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
1371
comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
1372
comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
1373
comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
1374
comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
1375
comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
1376
comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
1377
comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
1378
}
1379
1380
/***********************************************************************
1381
* COMCTL32_DrawInsertMark [NOT AN API]
1382
*
1383
* Draws an insertion mark (which looks similar to an 'I').
1384
*
1385
* PARAMS
1386
* hDC [I] Device context to draw onto.
1387
* lpRect [I] Co-ordinates of insertion mark.
1388
* clrInsertMark [I] Colour of the insertion mark.
1389
* bHorizontal [I] True if insert mark should be drawn horizontally,
1390
* vertical otherwise.
1391
*
1392
* RETURNS
1393
* none
1394
*
1395
* NOTES
1396
* Draws up to but not including the bottom co-ordinate when drawing
1397
* vertically or the right co-ordinate when horizontal.
1398
*/
1399
void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
1400
{
1401
HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
1402
HPEN hOldPen;
1403
static const DWORD adwPolyPoints[] = {4,4,4};
1404
LONG lCentre = (bHorizontal ?
1405
lpRect->top + (lpRect->bottom - lpRect->top)/2 :
1406
lpRect->left + (lpRect->right - lpRect->left)/2);
1407
LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
1408
LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
1409
const POINT aptInsertMark[] =
1410
{
1411
/* top (V) or left (H) arrow */
1412
{lCentre , l1 + 2},
1413
{lCentre - 2, l1 },
1414
{lCentre + 3, l1 },
1415
{lCentre + 1, l1 + 2},
1416
/* middle line */
1417
{lCentre , l2 - 2},
1418
{lCentre , l1 - 1},
1419
{lCentre + 1, l1 - 1},
1420
{lCentre + 1, l2 - 2},
1421
/* bottom (V) or right (H) arrow */
1422
{lCentre , l2 - 3},
1423
{lCentre - 2, l2 - 1},
1424
{lCentre + 3, l2 - 1},
1425
{lCentre + 1, l2 - 3},
1426
};
1427
hOldPen = SelectObject(hDC, hPen);
1428
PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
1429
SelectObject(hDC, hOldPen);
1430
DeleteObject(hPen);
1431
}
1432
1433
/***********************************************************************
1434
* COMCTL32_EnsureBitmapSize [internal]
1435
*
1436
* If needed, enlarge the bitmap so that the width is at least cxMinWidth and
1437
* the height is at least cyMinHeight. If the bitmap already has these
1438
* dimensions nothing changes.
1439
*
1440
* PARAMS
1441
* hBitmap [I/O] Bitmap to modify. The handle may change
1442
* cxMinWidth [I] If the width of the bitmap is smaller, then it will
1443
* be enlarged to this value
1444
* cyMinHeight [I] If the height of the bitmap is smaller, then it will
1445
* be enlarged to this value
1446
* cyBackground [I] The color with which the new area will be filled
1447
*
1448
* RETURNS
1449
* none
1450
*/
1451
void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
1452
{
1453
int cxNew, cyNew;
1454
BITMAP bmp;
1455
HBITMAP hNewBitmap;
1456
HBITMAP hNewDCBitmap, hOldDCBitmap;
1457
HBRUSH hNewDCBrush;
1458
HDC hdcNew, hdcOld;
1459
1460
if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
1461
return;
1462
cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
1463
cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
1464
if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
1465
return;
1466
1467
hdcNew = CreateCompatibleDC(NULL);
1468
hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
1469
hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
1470
hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
1471
1472
hdcOld = CreateCompatibleDC(NULL);
1473
hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
1474
1475
BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
1476
if (bmp.bmWidth < cxMinWidth)
1477
PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
1478
if (bmp.bmHeight < cyMinHeight)
1479
PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
1480
if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
1481
PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
1482
1483
SelectObject(hdcNew, hNewDCBitmap);
1484
DeleteObject(SelectObject(hdcNew, hNewDCBrush));
1485
DeleteDC(hdcNew);
1486
SelectObject(hdcOld, hOldDCBitmap);
1487
DeleteDC(hdcOld);
1488
1489
DeleteObject(*pBitmap);
1490
*pBitmap = hNewBitmap;
1491
return;
1492
}
1493
1494
void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
1495
{
1496
HDC hdc = GetDC(NULL);
1497
HFONT hOldFont;
1498
1499
hOldFont = SelectObject(hdc, hFont);
1500
GetTextMetricsW(hdc, ptm);
1501
SelectObject(hdc, hOldFont);
1502
ReleaseDC(NULL, hdc);
1503
}
1504
1505
#ifndef OCM__BASE /* avoid including olectl.h */
1506
#define OCM__BASE (WM_USER+0x1c00)
1507
#endif
1508
1509
/***********************************************************************
1510
* COMCTL32_IsReflectedMessage [internal]
1511
*
1512
* Some parents reflect notify messages - for some messages sent by the child,
1513
* they send it back with the message code increased by OCM__BASE (0x2000).
1514
* This allows better subclassing of controls. We don't need to handle such
1515
* messages but we don't want to print ERRs for them, so this helper function
1516
* identifies them.
1517
*
1518
* Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
1519
* collision with defined CCM_ codes.
1520
*/
1521
BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
1522
{
1523
switch (uMsg)
1524
{
1525
case OCM__BASE + WM_COMMAND:
1526
case OCM__BASE + WM_CTLCOLORBTN:
1527
case OCM__BASE + WM_CTLCOLOREDIT:
1528
case OCM__BASE + WM_CTLCOLORDLG:
1529
case OCM__BASE + WM_CTLCOLORLISTBOX:
1530
case OCM__BASE + WM_CTLCOLORMSGBOX:
1531
case OCM__BASE + WM_CTLCOLORSCROLLBAR:
1532
case OCM__BASE + WM_CTLCOLORSTATIC:
1533
case OCM__BASE + WM_DRAWITEM:
1534
case OCM__BASE + WM_MEASUREITEM:
1535
case OCM__BASE + WM_DELETEITEM:
1536
case OCM__BASE + WM_VKEYTOITEM:
1537
case OCM__BASE + WM_CHARTOITEM:
1538
case OCM__BASE + WM_COMPAREITEM:
1539
case OCM__BASE + WM_HSCROLL:
1540
case OCM__BASE + WM_VSCROLL:
1541
case OCM__BASE + WM_PARENTNOTIFY:
1542
case OCM__BASE + WM_NOTIFY:
1543
return TRUE;
1544
default:
1545
return FALSE;
1546
}
1547
}
1548
1549
/***********************************************************************
1550
* MirrorIcon [COMCTL32.414]
1551
*
1552
* Mirrors an icon so that it will appear correctly on a mirrored DC.
1553
*
1554
* PARAMS
1555
* phicon1 [I/O] Icon.
1556
* phicon2 [I/O] Icon.
1557
*
1558
* RETURNS
1559
* Success: TRUE.
1560
* Failure: FALSE.
1561
*/
1562
BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
1563
{
1564
FIXME("(%p, %p): stub\n", phicon1, phicon2);
1565
return FALSE;
1566
}
1567
1568
static inline BOOL IsDelimiter(WCHAR c)
1569
{
1570
switch(c)
1571
{
1572
case '/':
1573
case '\\':
1574
case '.':
1575
case ' ':
1576
return TRUE;
1577
}
1578
return FALSE;
1579
}
1580
1581
static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1582
{
1583
if (code == WB_ISDELIMITER)
1584
return IsDelimiter(lpch[ichCurrent]);
1585
else
1586
{
1587
int dir = (code == WB_LEFT) ? -1 : 1;
1588
for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
1589
if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
1590
}
1591
return ichCurrent;
1592
}
1593
1594
/***********************************************************************
1595
* SetPathWordBreakProc [COMCTL32.384]
1596
*
1597
* Sets the word break procedure for an edit control to one that understands
1598
* paths so that the user can jump over directories.
1599
*
1600
* PARAMS
1601
* hwnd [I] Handle to edit control.
1602
* bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
1603
*
1604
* RETURNS
1605
* Result from EM_SETWORDBREAKPROC message.
1606
*/
1607
LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
1608
{
1609
return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
1610
(LPARAM)(bSet ? PathWordBreakProc : NULL));
1611
}
1612
1613
#if __WINE_COMCTL32_VERSION == 6
1614
/***********************************************************************
1615
* DrawShadowText [COMCTL32.@]
1616
*
1617
* Draw text with shadow.
1618
*/
1619
int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
1620
COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
1621
{
1622
int bkmode, ret;
1623
COLORREF clr;
1624
RECT r;
1625
1626
FIXME("%p, %s, %d, %p, %#lx, %#lx, %#lx, %d, %d: semi-stub\n", hdc, debugstr_w(text),
1627
length, rect, flags, crText, crShadow, offset_x, offset_y);
1628
1629
bkmode = SetBkMode(hdc, TRANSPARENT);
1630
clr = SetTextColor(hdc, crShadow);
1631
1632
/* FIXME: for shadow we need to render normally, blur it, and blend with current background. */
1633
r = *rect;
1634
OffsetRect(&r, 1, 1);
1635
DrawTextW(hdc, text, length, &r, flags);
1636
1637
SetTextColor(hdc, crText);
1638
1639
/* with text color on top of a shadow */
1640
ret = DrawTextW(hdc, text, length, rect, flags);
1641
1642
SetTextColor(hdc, clr);
1643
SetBkMode(hdc, bkmode);
1644
1645
return ret;
1646
}
1647
1648
/***********************************************************************
1649
* LoadIconWithScaleDown [COMCTL32.@]
1650
*/
1651
HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
1652
{
1653
TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
1654
1655
*icon = NULL;
1656
1657
if (!name)
1658
return E_INVALIDARG;
1659
1660
*icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
1661
(hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
1662
if (!*icon)
1663
return HRESULT_FROM_WIN32(GetLastError());
1664
1665
return S_OK;
1666
}
1667
1668
/***********************************************************************
1669
* LoadIconMetric [COMCTL32.@]
1670
*/
1671
HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
1672
{
1673
int cx, cy;
1674
1675
TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
1676
1677
if (size == LIM_SMALL)
1678
{
1679
cx = GetSystemMetrics(SM_CXSMICON);
1680
cy = GetSystemMetrics(SM_CYSMICON);
1681
}
1682
else if (size == LIM_LARGE)
1683
{
1684
cx = GetSystemMetrics(SM_CXICON);
1685
cy = GetSystemMetrics(SM_CYICON);
1686
}
1687
else
1688
{
1689
*icon = NULL;
1690
return E_INVALIDARG;
1691
}
1692
1693
return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
1694
}
1695
#endif /* __WINE_COMCTL32_VERSION == 6 */
1696
1697
static const WCHAR strMRUList[] = L"MRUList";
1698
1699
/**************************************************************************
1700
* Alloc [COMCTL32.71]
1701
*
1702
* Allocates memory block from the dll's private heap
1703
*/
1704
void * WINAPI Alloc(DWORD size)
1705
{
1706
return LocalAlloc(LMEM_ZEROINIT, size);
1707
}
1708
1709
/**************************************************************************
1710
* ReAlloc [COMCTL32.72]
1711
*
1712
* Changes the size of an allocated memory block or allocates a memory
1713
* block using the dll's private heap.
1714
*
1715
*/
1716
void * WINAPI ReAlloc(void *src, DWORD size)
1717
{
1718
if (src)
1719
return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
1720
else
1721
return LocalAlloc(LMEM_ZEROINIT, size);
1722
}
1723
1724
/**************************************************************************
1725
* Free [COMCTL32.73]
1726
*
1727
* Frees an allocated memory block from the dll's private heap.
1728
*/
1729
BOOL WINAPI Free(void *mem)
1730
{
1731
return !LocalFree(mem);
1732
}
1733
1734
/**************************************************************************
1735
* GetSize [COMCTL32.74]
1736
*/
1737
DWORD WINAPI GetSize(void *mem)
1738
{
1739
return LocalSize(mem);
1740
}
1741
1742
/**************************************************************************
1743
* MRU-Functions {COMCTL32}
1744
*
1745
* NOTES
1746
* The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
1747
* Used) items. It is an undocumented API that is used (at least) by the shell
1748
* and explorer to implement their recent documents feature.
1749
*
1750
* Since these functions are undocumented, they are unsupported by MS and
1751
* may change at any time.
1752
*
1753
* Internally, the list is implemented as a last in, last out list of items
1754
* persisted into the system registry under a caller chosen key. Each list
1755
* item is given a one character identifier in the Ascii range from 'a' to
1756
* '}'. A list of the identifiers in order from newest to oldest is stored
1757
* under the same key in a value named "MRUList".
1758
*
1759
* Items are re-ordered by changing the order of the values in the MRUList
1760
* value. When a new item is added, it becomes the new value of the oldest
1761
* identifier, and that identifier is moved to the front of the MRUList value.
1762
*
1763
* Wine stores MRU-lists in the same registry format as Windows, so when
1764
* switching between the builtin and native comctl32.dll no problems or
1765
* incompatibilities should occur.
1766
*
1767
* The following undocumented structure is used to create an MRU-list:
1768
*|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
1769
*|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1770
*|
1771
*|typedef struct tagMRUINFO
1772
*|{
1773
*| DWORD cbSize;
1774
*| UINT uMax;
1775
*| UINT fFlags;
1776
*| HKEY hKey;
1777
*| LPTSTR lpszSubKey;
1778
*| PROC lpfnCompare;
1779
*|} MRUINFO, *LPMRUINFO;
1780
*
1781
* MEMBERS
1782
* cbSize [I] The size of the MRUINFO structure. This must be set
1783
* to sizeof(MRUINFO) by the caller.
1784
* uMax [I] The maximum number of items allowed in the list. Because
1785
* of the limited number of identifiers, this should be set to
1786
* a value from 1 to 30 by the caller.
1787
* fFlags [I] If bit 0 is set, the list will be used to store binary
1788
* data, otherwise it is assumed to store strings. If bit 1
1789
* is set, every change made to the list will be reflected in
1790
* the registry immediately, otherwise changes will only be
1791
* written when the list is closed.
1792
* hKey [I] The registry key that the list should be written under.
1793
* This must be supplied by the caller.
1794
* lpszSubKey [I] A caller supplied name of a subkey under hKey to write
1795
* the list to. This may not be blank.
1796
* lpfnCompare [I] A caller supplied comparison function, which may be either
1797
* an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
1798
* MRUBinaryCmpFn otherwise.
1799
*
1800
* FUNCTIONS
1801
* - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
1802
* - Add items to an MRU-list with AddMRUString() or AddMRUData().
1803
* - Remove items from an MRU-list with DelMRUString().
1804
* - Find data in an MRU-list with FindMRUString() or FindMRUData().
1805
* - Iterate through an MRU-list with EnumMRUList().
1806
* - Free an MRU-list with FreeMRUList().
1807
*/
1808
1809
typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
1810
typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
1811
typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
1812
1813
struct MRUINFOA
1814
{
1815
DWORD cbSize;
1816
UINT uMax;
1817
UINT fFlags;
1818
HKEY hKey;
1819
LPSTR lpszSubKey;
1820
union
1821
{
1822
MRUStringCmpFnA string_cmpfn;
1823
MRUBinaryCmpFn binary_cmpfn;
1824
} u;
1825
};
1826
1827
struct MRUINFOW
1828
{
1829
DWORD cbSize;
1830
UINT uMax;
1831
UINT fFlags;
1832
HKEY hKey;
1833
LPWSTR lpszSubKey;
1834
union
1835
{
1836
MRUStringCmpFnW string_cmpfn;
1837
MRUBinaryCmpFn binary_cmpfn;
1838
} u;
1839
};
1840
1841
/* MRUINFO.fFlags */
1842
#define MRU_STRING 0 /* list will contain strings */
1843
#define MRU_BINARY 1 /* list will contain binary data */
1844
#define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
1845
1846
/* If list is a string list lpfnCompare has the following prototype
1847
* int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
1848
* for binary lists the prototype is
1849
* int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
1850
* where cbData is the no. of bytes to compare.
1851
* Need to check what return value means identical - 0?
1852
*/
1853
1854
typedef struct tagWINEMRUITEM
1855
{
1856
DWORD size; /* size of data stored */
1857
DWORD itemFlag; /* flags */
1858
BYTE datastart;
1859
} WINEMRUITEM, *LPWINEMRUITEM;
1860
1861
/* itemFlag */
1862
#define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
1863
1864
typedef struct tagWINEMRULIST
1865
{
1866
struct MRUINFOW extview; /* original create information */
1867
BOOL isUnicode; /* is compare fn Unicode */
1868
DWORD wineFlags; /* internal flags */
1869
DWORD cursize; /* current size of realMRU */
1870
LPWSTR realMRU; /* pointer to string of index names */
1871
LPWINEMRUITEM *array; /* array of pointers to data */
1872
/* in 'a' to 'z' order */
1873
} WINEMRULIST, *LPWINEMRULIST;
1874
1875
/* wineFlags */
1876
#define WMRUF_CHANGED 0x0001 /* MRU list has changed */
1877
1878
/**************************************************************************
1879
* MRU_SaveChanged (internal)
1880
*
1881
* Local MRU saving code
1882
*/
1883
static void MRU_SaveChanged(WINEMRULIST *mp)
1884
{
1885
UINT i, err;
1886
HKEY newkey;
1887
WCHAR realname[2];
1888
WINEMRUITEM *witem;
1889
1890
/* or should we do the following instead of RegOpenKeyEx:
1891
*/
1892
1893
/* open the sub key */
1894
if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
1895
{
1896
/* not present - what to do ??? */
1897
ERR("Could not open key, error=%d, attempting to create\n", err);
1898
if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
1899
KEY_READ | KEY_WRITE, 0, &newkey, 0)))
1900
{
1901
ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
1902
return;
1903
}
1904
}
1905
1906
if (mp->wineFlags & WMRUF_CHANGED)
1907
{
1908
mp->wineFlags &= ~WMRUF_CHANGED;
1909
if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
1910
(lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
1911
{
1912
ERR("error saving MRUList, err=%d\n", err);
1913
}
1914
TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
1915
}
1916
1917
realname[1] = 0;
1918
for (i = 0; i < mp->cursize; ++i)
1919
{
1920
witem = mp->array[i];
1921
if (witem->itemFlag & WMRUIF_CHANGED)
1922
{
1923
witem->itemFlag &= ~WMRUIF_CHANGED;
1924
realname[0] = 'a' + i;
1925
if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
1926
REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
1927
{
1928
ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
1929
}
1930
TRACE("saving value for name /%s/ size %ld\n", debugstr_w(realname), witem->size);
1931
}
1932
}
1933
RegCloseKey(newkey);
1934
}
1935
1936
/**************************************************************************
1937
* FreeMRUList [COMCTL32.152]
1938
*
1939
* Frees a most-recently-used items list.
1940
*/
1941
void WINAPI FreeMRUList(HANDLE hMRUList)
1942
{
1943
WINEMRULIST *mp = hMRUList;
1944
unsigned int i;
1945
1946
TRACE("%p.\n", hMRUList);
1947
1948
if (!hMRUList)
1949
return;
1950
1951
if (mp->wineFlags & WMRUF_CHANGED)
1952
{
1953
/* need to open key and then save the info */
1954
MRU_SaveChanged(mp);
1955
}
1956
1957
for (i = 0; i < mp->extview.uMax; ++i)
1958
Free(mp->array[i]);
1959
1960
Free(mp->realMRU);
1961
Free(mp->array);
1962
Free(mp->extview.lpszSubKey);
1963
Free(mp);
1964
}
1965
1966
/**************************************************************************
1967
* FindMRUData [COMCTL32.169]
1968
*
1969
* Searches binary list for item that matches data of given length.
1970
* Returns position in list order 0 -> MRU and value corresponding to item's reg.
1971
* name will be stored in it ('a' -> 0).
1972
*
1973
*/
1974
INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
1975
{
1976
const WINEMRULIST *mp = hList;
1977
INT ret;
1978
UINT i;
1979
LPSTR dataA = NULL;
1980
1981
if (!mp || !mp->extview.u.string_cmpfn)
1982
return -1;
1983
1984
if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
1985
{
1986
DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
1987
dataA = Alloc(len);
1988
WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
1989
}
1990
1991
for (i = 0; i < mp->cursize; ++i)
1992
{
1993
if (mp->extview.fFlags & MRU_BINARY)
1994
{
1995
if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
1996
break;
1997
}
1998
else
1999
{
2000
if (mp->isUnicode)
2001
{
2002
if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
2003
break;
2004
}
2005
else
2006
{
2007
DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
2008
NULL, 0, NULL, NULL);
2009
LPSTR itemA = Alloc(len);
2010
INT cmp;
2011
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
2012
2013
cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
2014
Free(itemA);
2015
if (!cmp)
2016
break;
2017
}
2018
}
2019
}
2020
2021
Free(dataA);
2022
if (i < mp->cursize)
2023
ret = i;
2024
else
2025
ret = -1;
2026
if (pos && (ret != -1))
2027
*pos = 'a' + i;
2028
2029
TRACE("%p, %p, %ld, %p, returning %d.\n", hList, data, cbData, pos, ret);
2030
2031
return ret;
2032
}
2033
2034
/**************************************************************************
2035
* AddMRUData [COMCTL32.167]
2036
*
2037
* Add item to MRU binary list. If item already exists in list then it is
2038
* simply moved up to the top of the list and not added again. If list is
2039
* full then the least recently used item is removed to make room.
2040
*
2041
*/
2042
INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
2043
{
2044
WINEMRULIST *mp = hList;
2045
WINEMRUITEM *witem;
2046
INT i, replace;
2047
2048
if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
2049
{
2050
/* Item exists, just move it to the front */
2051
LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
2052
while (pos > mp->realMRU)
2053
{
2054
pos[0] = pos[-1];
2055
pos--;
2056
}
2057
}
2058
else
2059
{
2060
/* either add a new entry or replace oldest */
2061
if (mp->cursize < mp->extview.uMax)
2062
{
2063
/* Add in a new item */
2064
replace = mp->cursize;
2065
mp->cursize++;
2066
}
2067
else
2068
{
2069
/* get the oldest entry and replace data */
2070
replace = mp->realMRU[mp->cursize - 1] - 'a';
2071
Free(mp->array[replace]);
2072
}
2073
2074
/* Allocate space for new item and move in the data */
2075
mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
2076
witem->itemFlag |= WMRUIF_CHANGED;
2077
witem->size = cbData;
2078
memcpy( &witem->datastart, data, cbData);
2079
2080
/* now rotate MRU list */
2081
for (i = mp->cursize - 1; i >= 1; --i)
2082
mp->realMRU[i] = mp->realMRU[i-1];
2083
}
2084
2085
/* The new item gets the front spot */
2086
mp->wineFlags |= WMRUF_CHANGED;
2087
mp->realMRU[0] = replace + 'a';
2088
2089
TRACE("%p, %p, %ld adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
2090
2091
if (!(mp->extview.fFlags & MRU_CACHEWRITE))
2092
{
2093
/* save changed stuff right now */
2094
MRU_SaveChanged(mp);
2095
}
2096
2097
return replace;
2098
}
2099
2100
/**************************************************************************
2101
* AddMRUStringW [COMCTL32.401]
2102
*
2103
* Add an item to an MRU string list.
2104
*
2105
*/
2106
INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
2107
{
2108
TRACE("%p, %s.\n", hList, debugstr_w(str));
2109
2110
if (!hList)
2111
return -1;
2112
2113
if (!str || IsBadStringPtrW(str, -1))
2114
{
2115
SetLastError(ERROR_INVALID_PARAMETER);
2116
return 0;
2117
}
2118
2119
return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
2120
}
2121
2122
/**************************************************************************
2123
* AddMRUStringA [COMCTL32.153]
2124
*/
2125
INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
2126
{
2127
WCHAR *strW;
2128
DWORD len;
2129
INT ret;
2130
2131
TRACE("%p, %s.\n", hList, debugstr_a(str));
2132
2133
if (!hList)
2134
return -1;
2135
2136
if (IsBadStringPtrA(str, -1))
2137
{
2138
SetLastError(ERROR_INVALID_PARAMETER);
2139
return 0;
2140
}
2141
2142
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
2143
strW = Alloc(len);
2144
if (!strW)
2145
return -1;
2146
2147
MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
2148
ret = AddMRUData(hList, strW, len);
2149
Free(strW);
2150
return ret;
2151
}
2152
2153
/**************************************************************************
2154
* DelMRUString [COMCTL32.156]
2155
*
2156
* Removes item from either string or binary list (despite its name)
2157
*
2158
* PARAMS
2159
* hList [I] list handle
2160
* nItemPos [I] item position to remove 0 -> MRU
2161
*
2162
* RETURNS
2163
* TRUE if successful, FALSE if nItemPos is out of range.
2164
*/
2165
BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
2166
{
2167
FIXME("(%p, %d): stub\n", hList, nItemPos);
2168
return TRUE;
2169
}
2170
2171
/**************************************************************************
2172
* FindMRUStringW [COMCTL32.402]
2173
*/
2174
INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
2175
{
2176
return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
2177
}
2178
2179
/**************************************************************************
2180
* FindMRUStringA [COMCTL32.155]
2181
*
2182
* Searches string list for item that matches given string.
2183
*
2184
* RETURNS
2185
* Position in list 0 -> MRU. -1 if item not found.
2186
*/
2187
INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
2188
{
2189
DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
2190
WCHAR *strW = Alloc(len * sizeof(*strW));
2191
INT ret;
2192
2193
MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
2194
ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
2195
Free(strW);
2196
return ret;
2197
}
2198
2199
/*************************************************************************
2200
* create_mru_list (internal)
2201
*/
2202
static HANDLE create_mru_list(WINEMRULIST *mp)
2203
{
2204
UINT i, err;
2205
HKEY newkey;
2206
DWORD datasize, dwdisp;
2207
WCHAR realname[2];
2208
WINEMRUITEM *witem;
2209
DWORD type;
2210
2211
/* get space to save indices that will turn into names
2212
* but in order of most to least recently used
2213
*/
2214
mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
2215
2216
/* get space to save pointers to actual data in order of
2217
* 'a' to 'z' (0 to n).
2218
*/
2219
mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
2220
2221
/* open the sub key */
2222
if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2223
KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
2224
{
2225
/* error - what to do ??? */
2226
ERR("%lu, %u, %x, %p, %s, %p: Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2227
mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
2228
return 0;
2229
}
2230
2231
/* get values from key 'MRUList' */
2232
if (newkey)
2233
{
2234
datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
2235
if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
2236
{
2237
/* not present - set size to 1 (will become 0 later) */
2238
datasize = 1;
2239
*mp->realMRU = 0;
2240
}
2241
else
2242
datasize /= sizeof(WCHAR);
2243
2244
TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
2245
2246
mp->cursize = datasize - 1;
2247
/* datasize now has number of items in the MRUList */
2248
2249
/* get actual values for each entry */
2250
realname[1] = 0;
2251
for (i = 0; i < mp->cursize; ++i)
2252
{
2253
realname[0] = 'a' + i;
2254
if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
2255
{
2256
/* not present - what to do ??? */
2257
ERR("Key %s not found 1\n", debugstr_w(realname));
2258
}
2259
mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
2260
witem->size = datasize;
2261
if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
2262
{
2263
/* not present - what to do ??? */
2264
ERR("Key %s not found 2\n", debugstr_w(realname));
2265
}
2266
}
2267
RegCloseKey( newkey );
2268
}
2269
else
2270
mp->cursize = 0;
2271
2272
TRACE("%lu, %u, %x, %p, %s, %p: Current Size = %ld\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
2273
mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
2274
return mp;
2275
}
2276
2277
/**************************************************************************
2278
* CreateMRUListLazyW [COMCTL32.404]
2279
*/
2280
HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2281
{
2282
WINEMRULIST *mp;
2283
2284
/* Native does not check for a NULL. */
2285
if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
2286
return NULL;
2287
2288
mp = Alloc(sizeof(*mp));
2289
memcpy(&mp->extview, info, sizeof(*info));
2290
mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
2291
lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
2292
mp->isUnicode = TRUE;
2293
2294
return create_mru_list(mp);
2295
}
2296
2297
/**************************************************************************
2298
* CreateMRUListLazyA [COMCTL32.157]
2299
*
2300
* Creates a most-recently-used list.
2301
*/
2302
HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
2303
{
2304
WINEMRULIST *mp;
2305
DWORD len;
2306
2307
/* Native does not check for a NULL lpcml */
2308
2309
if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
2310
return 0;
2311
2312
mp = Alloc(sizeof(*mp));
2313
memcpy(&mp->extview, info, sizeof(*info));
2314
len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
2315
mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
2316
MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
2317
mp->isUnicode = FALSE;
2318
return create_mru_list(mp);
2319
}
2320
2321
/**************************************************************************
2322
* CreateMRUListW [COMCTL32.400]
2323
*/
2324
HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
2325
{
2326
return CreateMRUListLazyW(info, 0, 0, 0);
2327
}
2328
2329
/**************************************************************************
2330
* CreateMRUListA [COMCTL32.151]
2331
*/
2332
HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
2333
{
2334
return CreateMRUListLazyA(info, 0, 0, 0);
2335
}
2336
2337
/**************************************************************************
2338
* EnumMRUListW [COMCTL32.403]
2339
*
2340
* Enumerate item in a most-recently-used list
2341
*
2342
* PARAMS
2343
* hList [I] list handle
2344
* nItemPos [I] item position to enumerate
2345
* lpBuffer [O] buffer to receive item
2346
* nBufferSize [I] size of buffer
2347
*
2348
* RETURNS
2349
* For binary lists specifies how many bytes were copied to buffer, for
2350
* string lists specifies full length of string. Enumerating past the end
2351
* of list returns -1.
2352
* If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
2353
* the list.
2354
*/
2355
INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2356
{
2357
const WINEMRULIST *mp = hList;
2358
const WINEMRUITEM *witem;
2359
INT desired, datasize;
2360
2361
if (!mp) return -1;
2362
if ((nItemPos < 0) || !buffer) return mp->cursize;
2363
if (nItemPos >= mp->cursize) return -1;
2364
desired = mp->realMRU[nItemPos];
2365
desired -= 'a';
2366
TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2367
witem = mp->array[desired];
2368
datasize = min(witem->size, nBufferSize);
2369
memcpy(buffer, &witem->datastart, datasize);
2370
TRACE("(%p, %d, %p, %ld): returning len %d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2371
return datasize;
2372
}
2373
2374
/**************************************************************************
2375
* EnumMRUListA [COMCTL32.154]
2376
*/
2377
INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
2378
{
2379
const WINEMRULIST *mp = hList;
2380
WINEMRUITEM *witem;
2381
INT desired, datasize;
2382
DWORD lenA;
2383
2384
if (!mp) return -1;
2385
if ((nItemPos < 0) || !buffer) return mp->cursize;
2386
if (nItemPos >= mp->cursize) return -1;
2387
desired = mp->realMRU[nItemPos];
2388
desired -= 'a';
2389
TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
2390
witem = mp->array[desired];
2391
if (mp->extview.fFlags & MRU_BINARY)
2392
{
2393
datasize = min(witem->size, nBufferSize);
2394
memcpy(buffer, &witem->datastart, datasize);
2395
}
2396
else
2397
{
2398
lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
2399
datasize = min(lenA, nBufferSize);
2400
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
2401
((char *)buffer)[ datasize - 1 ] = '\0';
2402
datasize = lenA - 1;
2403
}
2404
TRACE("(%p, %d, %p, %ld): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
2405
return datasize;
2406
}
2407
2408
/**************************************************************************
2409
* Str_GetPtrWtoA [internal]
2410
*
2411
* Converts a unicode string into a multi byte string
2412
*
2413
*/
2414
2415
INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
2416
{
2417
INT len;
2418
2419
TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
2420
2421
if (!dst && src)
2422
return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2423
2424
if (!nMaxLen)
2425
return 0;
2426
2427
if (!src)
2428
{
2429
dst[0] = 0;
2430
return 0;
2431
}
2432
2433
len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
2434
if (len >= nMaxLen)
2435
len = nMaxLen - 1;
2436
2437
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
2438
dst[len] = '\0';
2439
2440
return len;
2441
}
2442
2443
/**************************************************************************
2444
* Str_GetPtrAtoW [internal]
2445
*
2446
* Converts a multibyte string into a unicode string
2447
*/
2448
2449
INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
2450
{
2451
INT len;
2452
2453
TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
2454
2455
if (!dst && src)
2456
return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2457
2458
if (!nMaxLen)
2459
return 0;
2460
2461
if (!src)
2462
{
2463
*dst = 0;
2464
return 0;
2465
}
2466
2467
len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
2468
if (len >= nMaxLen)
2469
len = nMaxLen - 1;
2470
2471
MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
2472
dst[len] = 0;
2473
2474
return len;
2475
}
2476
2477
/**************************************************************************
2478
* Str_SetPtrAtoW [internal]
2479
*
2480
* Converts a multi byte string to a unicode string.
2481
* If the pointer to the destination buffer is NULL a buffer is allocated.
2482
* If the destination buffer is too small to keep the converted multi byte
2483
* string the destination buffer is reallocated. If the source pointer is
2484
*/
2485
BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
2486
{
2487
TRACE("%p, %s.\n", dst, debugstr_a(src));
2488
2489
if (src)
2490
{
2491
INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
2492
LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2493
2494
if (!ptr)
2495
return FALSE;
2496
MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
2497
*dst = ptr;
2498
}
2499
else
2500
{
2501
Free(*dst);
2502
*dst = NULL;
2503
}
2504
2505
return TRUE;
2506
}
2507
2508
/**************************************************************************
2509
* Str_SetPtrWtoA [internal]
2510
*
2511
* Converts a unicode string to a multi byte string.
2512
* If the pointer to the destination buffer is NULL a buffer is allocated.
2513
* If the destination buffer is too small to keep the converted wide
2514
* string the destination buffer is reallocated. If the source pointer is
2515
* NULL, the destination buffer is freed.
2516
*/
2517
BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
2518
{
2519
TRACE("%p, %s.\n", dst, debugstr_w(src));
2520
2521
if (src)
2522
{
2523
INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
2524
LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
2525
2526
if (!ptr)
2527
return FALSE;
2528
WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
2529
*dst = ptr;
2530
}
2531
else
2532
{
2533
Free(*dst);
2534
*dst = NULL;
2535
}
2536
2537
return TRUE;
2538
}
2539
2540
/**************************************************************************
2541
* Notification functions
2542
*/
2543
2544
struct NOTIFYDATA
2545
{
2546
HWND hwndFrom;
2547
HWND hwndTo;
2548
DWORD dwParam3;
2549
DWORD dwParam4;
2550
DWORD dwParam5;
2551
DWORD dwParam6;
2552
};
2553
2554
/**************************************************************************
2555
* DoNotify [Internal]
2556
*/
2557
2558
static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
2559
{
2560
NMHDR nmhdr;
2561
NMHDR *lpNmh = NULL;
2562
UINT idFrom = 0;
2563
2564
TRACE("%p, %p, %d, %p, %#lx.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
2565
2566
if (!notify->hwndTo)
2567
return 0;
2568
2569
if (notify->hwndFrom == (HWND)-1)
2570
{
2571
lpNmh = hdr;
2572
idFrom = hdr->idFrom;
2573
}
2574
else
2575
{
2576
if (notify->hwndFrom)
2577
idFrom = GetDlgCtrlID(notify->hwndFrom);
2578
2579
lpNmh = hdr ? hdr : &nmhdr;
2580
lpNmh->hwndFrom = notify->hwndFrom;
2581
lpNmh->idFrom = idFrom;
2582
lpNmh->code = code;
2583
}
2584
2585
return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2586
}
2587
2588
/**************************************************************************
2589
* SendNotify [COMCTL32.341]
2590
*
2591
* Sends a WM_NOTIFY message to the specified window.
2592
*
2593
*/
2594
LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
2595
{
2596
struct NOTIFYDATA notify;
2597
2598
TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
2599
2600
notify.hwndFrom = hwndFrom;
2601
notify.hwndTo = hwndTo;
2602
notify.dwParam5 = 0;
2603
notify.dwParam6 = 0;
2604
2605
return DoNotify(&notify, code, hdr);
2606
}
2607
2608
/**************************************************************************
2609
* SendNotifyEx [COMCTL32.342]
2610
*
2611
* Sends a WM_NOTIFY message to the specified window.
2612
*
2613
* PARAMS
2614
* hwndFrom [I] Window to receive the message
2615
* hwndTo [I] Window that the message is from
2616
* code [I] Notification code
2617
* hdr [I] The NMHDR and any additional information to send or NULL
2618
* dwParam5 [I] Unknown
2619
*
2620
* RETURNS
2621
* Success: return value from notification
2622
* Failure: 0
2623
*
2624
* NOTES
2625
* If hwndFrom is -1 then the identifier of the control sending the
2626
* message is taken from the NMHDR structure.
2627
* If hwndFrom is not -1 then lpHdr can be NULL.
2628
*/
2629
LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
2630
{
2631
struct NOTIFYDATA notify;
2632
HWND hwndNotify;
2633
2634
TRACE("%p, %p, %d, %p, %#lx\n", hwndFrom, hwndTo, code, hdr, dwParam5);
2635
2636
hwndNotify = hwndTo;
2637
if (!hwndTo)
2638
{
2639
if (IsWindow(hwndFrom))
2640
{
2641
hwndNotify = GetParent(hwndFrom);
2642
if (!hwndNotify)
2643
return 0;
2644
}
2645
}
2646
2647
notify.hwndFrom = hwndFrom;
2648
notify.hwndTo = hwndNotify;
2649
notify.dwParam5 = dwParam5;
2650
notify.dwParam6 = 0;
2651
2652
return DoNotify(&notify, code, hdr);
2653
}
2654
2655
/* reallocate *array if needed so it can hold at least count items */
2656
/* *size measured in bytes, count measured in items */
2657
/* return FALSE means failed (*array still valid but too small) */
2658
/* return TRUE means successful */
2659
static BOOL COMCTL32_array_reserve(void **array, DWORD *size, DWORD count, DWORD item_size)
2660
{
2661
void *new_array;
2662
DWORD needed_size;
2663
2664
if (count > (DWORD)-1 / item_size)
2665
return FALSE;
2666
needed_size = count * item_size;
2667
if (*size >= needed_size)
2668
return TRUE;
2669
new_array = *array ? ReAlloc(*array, needed_size) : Alloc(needed_size);
2670
if (!new_array)
2671
return FALSE;
2672
*array = new_array;
2673
*size = needed_size;
2674
return TRUE;
2675
}
2676
2677
/* Text field conversion behavior flags for COMCTL32_SendConvertedNotify() */
2678
enum conversion_flags
2679
{
2680
/* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */
2681
CONVERT_SEND = 0x01,
2682
/* Convert ANSI text from parent back to Unicode for children */
2683
CONVERT_RECEIVE = 0x02,
2684
/* Send empty text to parent if text is NULL. Original text pointer still remains NULL */
2685
SEND_EMPTY_IF_NULL = 0x04,
2686
/* Set text to null after parent received the notification if the required mask is not set before sending notification */
2687
SET_NULL_IF_NO_MASK = 0x08,
2688
/* Zero out the text buffer before sending it to parent */
2689
ZERO_SEND = 0x10
2690
};
2691
2692
static UINT COMCTL32_GetAnsiNtfCode(UINT code)
2693
{
2694
switch (code)
2695
{
2696
/* ComboxBoxEx */
2697
case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA;
2698
case CBEN_ENDEDITW: return CBEN_ENDEDITA;
2699
case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA;
2700
/* Date and Time Picker */
2701
case DTN_FORMATW: return DTN_FORMATA;
2702
case DTN_FORMATQUERYW: return DTN_FORMATQUERYA;
2703
case DTN_USERSTRINGW: return DTN_USERSTRINGA;
2704
case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA;
2705
/* Header */
2706
case HDN_BEGINTRACKW: return HDN_BEGINTRACKA;
2707
case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA;
2708
case HDN_ENDTRACKW: return HDN_ENDTRACKA;
2709
case HDN_GETDISPINFOW: return HDN_GETDISPINFOA;
2710
case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA;
2711
case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA;
2712
case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
2713
case HDN_ITEMDBLCLICKW: return HDN_ITEMDBLCLICKA;
2714
case HDN_TRACKW: return HDN_TRACKA;
2715
/* List View */
2716
case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA;
2717
case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA;
2718
case LVN_GETDISPINFOW: return LVN_GETDISPINFOA;
2719
case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
2720
case LVN_INCREMENTALSEARCHW: return LVN_INCREMENTALSEARCHA;
2721
case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
2722
case LVN_SETDISPINFOW: return LVN_SETDISPINFOA;
2723
/* Toolbar */
2724
case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
2725
case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
2726
/* Tooltip */
2727
case TTN_GETDISPINFOW: return TTN_GETDISPINFOA;
2728
/* Tree View */
2729
case TVN_BEGINDRAGW: return TVN_BEGINDRAGA;
2730
case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA;
2731
case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA;
2732
case TVN_DELETEITEMW: return TVN_DELETEITEMA;
2733
case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA;
2734
case TVN_GETDISPINFOW: return TVN_GETDISPINFOA;
2735
case TVN_GETINFOTIPW: return TVN_GETINFOTIPA;
2736
case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA;
2737
case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA;
2738
case TVN_SELCHANGEDW: return TVN_SELCHANGEDA;
2739
case TVN_SELCHANGINGW: return TVN_SELCHANGINGA;
2740
case TVN_SETDISPINFOW: return TVN_SETDISPINFOA;
2741
}
2742
return code;
2743
}
2744
2745
/* Convert text to Unicode and return the original text address */
2746
static WCHAR *COMCTL32_ConvertText(WCHAR **text)
2747
{
2748
WCHAR *oldText = *text;
2749
*text = NULL;
2750
Str_SetPtrWtoA((CHAR **)text, oldText);
2751
return oldText;
2752
}
2753
2754
static void COMCTL32_RestoreText(WCHAR **text, WCHAR *oldText)
2755
{
2756
if (!oldText) return;
2757
2758
Free(*text);
2759
*text = oldText;
2760
}
2761
2762
static LRESULT COMCTL32_SendConvertedNotify(HWND hwndNotify, NMHDR *hdr, UINT *mask, UINT requiredMask, WCHAR **text,
2763
INT *textMax, DWORD flags)
2764
{
2765
CHAR *sendBuffer = NULL;
2766
CHAR *receiveBuffer;
2767
INT bufferSize;
2768
WCHAR *oldText;
2769
INT oldTextMax;
2770
LRESULT ret = NO_ERROR;
2771
2772
oldText = *text;
2773
oldTextMax = textMax ? *textMax : 0;
2774
2775
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
2776
2777
if (mask && !(*mask & requiredMask))
2778
{
2779
ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
2780
if (flags & SET_NULL_IF_NO_MASK) oldText = NULL;
2781
goto done;
2782
}
2783
2784
if (oldTextMax < 0) goto done;
2785
2786
if ((*text && flags & (CONVERT_SEND | ZERO_SEND)) || (!*text && flags & SEND_EMPTY_IF_NULL))
2787
{
2788
bufferSize = textMax ? *textMax : lstrlenW(*text) + 1;
2789
sendBuffer = Alloc(bufferSize);
2790
if (!sendBuffer) goto done;
2791
if (!(flags & ZERO_SEND)) WideCharToMultiByte(CP_ACP, 0, *text, -1, sendBuffer, bufferSize, NULL, FALSE);
2792
*text = (WCHAR *)sendBuffer;
2793
}
2794
2795
ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
2796
2797
if (*text && oldText && (flags & CONVERT_RECEIVE))
2798
{
2799
/* MultiByteToWideChar requires that source and destination are not the same buffer */
2800
if (*text == oldText)
2801
{
2802
bufferSize = lstrlenA((CHAR *)*text) + 1;
2803
receiveBuffer = Alloc(bufferSize);
2804
if (!receiveBuffer) goto done;
2805
memcpy(receiveBuffer, *text, bufferSize);
2806
MultiByteToWideChar(CP_ACP, 0, receiveBuffer, bufferSize, oldText, oldTextMax);
2807
Free(receiveBuffer);
2808
}
2809
else
2810
MultiByteToWideChar(CP_ACP, 0, (CHAR *)*text, -1, oldText, oldTextMax);
2811
}
2812
2813
done:
2814
Free(sendBuffer);
2815
*text = oldText;
2816
return ret;
2817
}
2818
2819
LRESULT COMCTL32_forward_notify_to_ansi_window(HWND hwnd_notify, NMHDR *hdr, WCHAR **unicode_buffer, DWORD *unicode_buffer_size)
2820
{
2821
LRESULT ret;
2822
2823
switch (hdr->code)
2824
{
2825
/* ComboBoxEx */
2826
case CBEN_GETDISPINFOW:
2827
{
2828
NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr;
2829
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmcbe->ceItem.mask, CBEIF_TEXT, &nmcbe->ceItem.pszText,
2830
&nmcbe->ceItem.cchTextMax, ZERO_SEND | SET_NULL_IF_NO_MASK | CONVERT_RECEIVE);
2831
}
2832
case CBEN_DRAGBEGINW:
2833
{
2834
NMCBEDRAGBEGINW *nmdbW = (NMCBEDRAGBEGINW *)hdr;
2835
NMCBEDRAGBEGINA nmdbA = {{0}};
2836
nmdbA.hdr.code = COMCTL32_GetAnsiNtfCode(nmdbW->hdr.code);
2837
nmdbA.hdr.hwndFrom = nmdbW->hdr.hwndFrom;
2838
nmdbA.hdr.idFrom = nmdbW->hdr.idFrom;
2839
nmdbA.iItemid = nmdbW->iItemid;
2840
WideCharToMultiByte(CP_ACP, 0, nmdbW->szText, ARRAY_SIZE(nmdbW->szText), nmdbA.szText, ARRAY_SIZE(nmdbA.szText),
2841
NULL, FALSE);
2842
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmdbA);
2843
}
2844
case CBEN_ENDEDITW:
2845
{
2846
NMCBEENDEDITW *nmedW = (NMCBEENDEDITW *)hdr;
2847
NMCBEENDEDITA nmedA = {{0}};
2848
nmedA.hdr.code = COMCTL32_GetAnsiNtfCode(nmedW->hdr.code);
2849
nmedA.hdr.hwndFrom = nmedW->hdr.hwndFrom;
2850
nmedA.hdr.idFrom = nmedW->hdr.idFrom;
2851
nmedA.fChanged = nmedW->fChanged;
2852
nmedA.iNewSelection = nmedW->iNewSelection;
2853
nmedA.iWhy = nmedW->iWhy;
2854
WideCharToMultiByte(CP_ACP, 0, nmedW->szText, ARRAY_SIZE(nmedW->szText), nmedA.szText, ARRAY_SIZE(nmedA.szText),
2855
NULL, FALSE);
2856
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmedA);
2857
}
2858
/* Date and Time Picker */
2859
case DTN_FORMATW:
2860
{
2861
NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr;
2862
WCHAR *oldFormat;
2863
DWORD textLength;
2864
2865
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
2866
oldFormat = COMCTL32_ConvertText((WCHAR **)&nmdtf->pszFormat);
2867
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)nmdtf);
2868
COMCTL32_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat);
2869
2870
if (nmdtf->pszDisplay)
2871
{
2872
textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, 0, 0);
2873
if (!COMCTL32_array_reserve((void **)unicode_buffer, unicode_buffer_size, textLength, sizeof(WCHAR))) return ret;
2874
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, *unicode_buffer, textLength);
2875
if (nmdtf->pszDisplay != nmdtf->szDisplay)
2876
nmdtf->pszDisplay = *unicode_buffer;
2877
else
2878
{
2879
textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay));
2880
memcpy(nmdtf->szDisplay, *unicode_buffer, textLength * sizeof(WCHAR));
2881
}
2882
}
2883
2884
return ret;
2885
}
2886
case DTN_FORMATQUERYW:
2887
{
2888
NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr;
2889
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdtfq->pszFormat, NULL, CONVERT_SEND);
2890
}
2891
case DTN_WMKEYDOWNW:
2892
{
2893
NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr;
2894
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdtkd->pszFormat, NULL, CONVERT_SEND);
2895
}
2896
case DTN_USERSTRINGW:
2897
{
2898
NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr;
2899
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdts->pszUserString, NULL, CONVERT_SEND);
2900
}
2901
/* Header */
2902
case HDN_BEGINTRACKW:
2903
case HDN_DIVIDERDBLCLICKW:
2904
case HDN_ENDTRACKW:
2905
case HDN_ITEMCHANGEDW:
2906
case HDN_ITEMCHANGINGW:
2907
case HDN_ITEMCLICKW:
2908
case HDN_ITEMDBLCLICKW:
2909
case HDN_TRACKW:
2910
{
2911
NMHEADERW *nmh = (NMHEADERW *)hdr;
2912
WCHAR *oldText = NULL, *oldFilterText = NULL;
2913
HD_TEXTFILTERW *tf = NULL;
2914
2915
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
2916
2917
if (!nmh->pitem) return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
2918
if (nmh->pitem->mask & HDI_TEXT) oldText = COMCTL32_ConvertText(&nmh->pitem->pszText);
2919
if ((nmh->pitem->mask & HDI_FILTER) && (nmh->pitem->type == HDFT_ISSTRING) && nmh->pitem->pvFilter)
2920
{
2921
tf = (HD_TEXTFILTERW *)nmh->pitem->pvFilter;
2922
oldFilterText = COMCTL32_ConvertText(&tf->pszText);
2923
}
2924
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
2925
COMCTL32_RestoreText(&nmh->pitem->pszText, oldText);
2926
if (tf) COMCTL32_RestoreText(&tf->pszText, oldFilterText);
2927
return ret;
2928
}
2929
case HDN_GETDISPINFOW:
2930
{
2931
NMHDDISPINFOW *nmhddi = (NMHDDISPINFOW *)hdr;
2932
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmhddi->mask, HDI_TEXT, &nmhddi->pszText, &nmhddi->cchTextMax,
2933
SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE);
2934
}
2935
/* List View */
2936
case LVN_BEGINLABELEDITW:
2937
case LVN_ENDLABELEDITW:
2938
case LVN_SETDISPINFOW:
2939
{
2940
NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
2941
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText,
2942
&nmlvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
2943
}
2944
case LVN_GETDISPINFOW:
2945
{
2946
NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
2947
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText,
2948
&nmlvdi->item.cchTextMax, CONVERT_RECEIVE);
2949
}
2950
case LVN_GETINFOTIPW:
2951
{
2952
NMLVGETINFOTIPW *nmlvgit = (NMLVGETINFOTIPW *)hdr;
2953
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmlvgit->pszText, &nmlvgit->cchTextMax,
2954
CONVERT_SEND | CONVERT_RECEIVE);
2955
}
2956
case LVN_INCREMENTALSEARCHW:
2957
case LVN_ODFINDITEMW:
2958
{
2959
NMLVFINDITEMW *nmlvfi = (NMLVFINDITEMW *)hdr;
2960
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvfi->lvfi.flags, LVFI_STRING | LVFI_SUBSTRING,
2961
(WCHAR **)&nmlvfi->lvfi.psz, NULL, CONVERT_SEND);
2962
}
2963
/* Toolbar */
2964
case TBN_GETBUTTONINFOW:
2965
{
2966
NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr;
2967
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtb->pszText, &nmtb->cchText,
2968
SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE);
2969
}
2970
case TBN_GETINFOTIPW:
2971
{
2972
NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
2973
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtbgit->pszText, &nmtbgit->cchTextMax, CONVERT_RECEIVE);
2974
}
2975
/* Tooltip */
2976
case TTN_GETDISPINFOW:
2977
{
2978
NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr;
2979
NMTTDISPINFOA nmttdiA = {{0}};
2980
DWORD size;
2981
2982
nmttdiA.hdr.code = COMCTL32_GetAnsiNtfCode(nmttdiW->hdr.code);
2983
nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom;
2984
nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom;
2985
nmttdiA.hinst = nmttdiW->hinst;
2986
nmttdiA.uFlags = nmttdiW->uFlags;
2987
nmttdiA.lParam = nmttdiW->lParam;
2988
nmttdiA.lpszText = nmttdiA.szText;
2989
WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText,
2990
ARRAY_SIZE(nmttdiA.szText), NULL, FALSE);
2991
2992
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA);
2993
2994
nmttdiW->hinst = nmttdiA.hinst;
2995
nmttdiW->uFlags = nmttdiA.uFlags;
2996
nmttdiW->lParam = nmttdiA.lParam;
2997
2998
MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText,
2999
ARRAY_SIZE(nmttdiW->szText));
3000
if (!nmttdiA.lpszText)
3001
nmttdiW->lpszText = nmttdiW->szText;
3002
else if (!IS_INTRESOURCE(nmttdiA.lpszText))
3003
{
3004
size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0);
3005
if (size > ARRAY_SIZE(nmttdiW->szText))
3006
{
3007
if (!COMCTL32_array_reserve((void **)unicode_buffer, unicode_buffer_size, size, sizeof(WCHAR))) return ret;
3008
MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, *unicode_buffer, size);
3009
nmttdiW->lpszText = *unicode_buffer;
3010
/* Override content in szText */
3011
memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR)));
3012
}
3013
else
3014
{
3015
MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText));
3016
nmttdiW->lpszText = nmttdiW->szText;
3017
}
3018
}
3019
else
3020
{
3021
nmttdiW->szText[0] = 0;
3022
nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText;
3023
}
3024
3025
return ret;
3026
}
3027
/* Tree View */
3028
case TVN_BEGINDRAGW:
3029
case TVN_BEGINRDRAGW:
3030
case TVN_ITEMEXPANDEDW:
3031
case TVN_ITEMEXPANDINGW:
3032
{
3033
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
3034
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtv->itemNew.mask, TVIF_TEXT, &nmtv->itemNew.pszText, NULL,
3035
CONVERT_SEND);
3036
}
3037
case TVN_DELETEITEMW:
3038
{
3039
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
3040
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtv->itemOld.mask, TVIF_TEXT, &nmtv->itemOld.pszText, NULL,
3041
CONVERT_SEND);
3042
}
3043
case TVN_BEGINLABELEDITW:
3044
case TVN_ENDLABELEDITW:
3045
{
3046
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
3047
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
3048
&nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
3049
}
3050
case TVN_SELCHANGINGW:
3051
case TVN_SELCHANGEDW:
3052
{
3053
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
3054
WCHAR *oldItemOldText = NULL;
3055
WCHAR *oldItemNewText = NULL;
3056
3057
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
3058
3059
if (!((nmtv->itemNew.mask | nmtv->itemOld.mask) & TVIF_TEXT))
3060
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
3061
3062
if (nmtv->itemOld.mask & TVIF_TEXT) oldItemOldText = COMCTL32_ConvertText(&nmtv->itemOld.pszText);
3063
if (nmtv->itemNew.mask & TVIF_TEXT) oldItemNewText = COMCTL32_ConvertText(&nmtv->itemNew.pszText);
3064
3065
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
3066
COMCTL32_RestoreText(&nmtv->itemOld.pszText, oldItemOldText);
3067
COMCTL32_RestoreText(&nmtv->itemNew.pszText, oldItemNewText);
3068
return ret;
3069
}
3070
case TVN_GETDISPINFOW:
3071
{
3072
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
3073
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
3074
&nmtvdi->item.cchTextMax, ZERO_SEND | CONVERT_RECEIVE);
3075
}
3076
case TVN_SETDISPINFOW:
3077
{
3078
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
3079
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
3080
&nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
3081
}
3082
case TVN_GETINFOTIPW:
3083
{
3084
NMTVGETINFOTIPW *nmtvgit = (NMTVGETINFOTIPW *)hdr;
3085
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtvgit->pszText, &nmtvgit->cchTextMax, CONVERT_RECEIVE);
3086
}
3087
}
3088
/* Other notifications, no need to convert */
3089
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
3090
}
3091
3092
void COMCTL32_OpenThemeForWindow(HWND hwnd, const WCHAR *theme_class)
3093
{
3094
#if __WINE_COMCTL32_VERSION == 6
3095
OpenThemeData(hwnd, theme_class);
3096
#endif
3097
}
3098
3099
void COMCTL32_CloseThemeForWindow(HWND hwnd)
3100
{
3101
#if __WINE_COMCTL32_VERSION == 6
3102
CloseThemeData(GetWindowTheme(hwnd));
3103
#endif
3104
}
3105
3106
/* A helper to handle CCM_SETVERSION messages */
3107
LRESULT COMCTL32_SetVersion(INT *current_version, INT new_version)
3108
{
3109
#if __WINE_COMCTL32_VERSION == 6
3110
return *current_version;
3111
#else
3112
INT old_version;
3113
3114
if (new_version > 5)
3115
return -1;
3116
3117
old_version = *current_version;
3118
*current_version = new_version;
3119
return old_version;
3120
#endif
3121
}
3122
3123
/* A helper to handle WM_THEMECHANGED messages */
3124
LRESULT COMCTL32_ThemeChanged(HWND hwnd, const WCHAR *theme_class, BOOL invalidate, BOOL erase)
3125
{
3126
#if __WINE_COMCTL32_VERSION == 6
3127
if (theme_class)
3128
{
3129
COMCTL32_CloseThemeForWindow(hwnd);
3130
COMCTL32_OpenThemeForWindow(hwnd, theme_class);
3131
}
3132
3133
if (invalidate)
3134
InvalidateRect(hwnd, NULL, erase);
3135
return 0;
3136
#else
3137
return DefWindowProcW(hwnd, WM_THEMECHANGED, 0, 0);
3138
#endif
3139
}
3140
3141
/* A helper to handle WM_NCPAINT messages
3142
*
3143
* If theme_class is specified, open the specified theme class. Otherwise, get the theme class from
3144
* the window.
3145
*/
3146
LRESULT COMCTL32_NCPaint(HWND hwnd, WPARAM wp, LPARAM lp, const WCHAR *theme_class)
3147
{
3148
#if __WINE_COMCTL32_VERSION == 6
3149
HRGN region = (HRGN)wp, clipRgn;
3150
INT cxEdge, cyEdge;
3151
HTHEME theme;
3152
LONG exStyle;
3153
HDC dc;
3154
RECT r;
3155
3156
exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3157
if (!(exStyle & WS_EX_CLIENTEDGE))
3158
return DefWindowProcW(hwnd, WM_NCPAINT, wp, lp);
3159
3160
if (theme_class)
3161
theme = OpenThemeDataForDpi(NULL, theme_class, GetDpiForWindow(hwnd));
3162
else
3163
theme = GetWindowTheme(hwnd);
3164
if (!theme)
3165
return DefWindowProcW(hwnd, WM_NCPAINT, wp, lp);
3166
3167
cxEdge = GetSystemMetrics(SM_CXEDGE);
3168
cyEdge = GetSystemMetrics(SM_CYEDGE);
3169
GetWindowRect(hwnd, &r);
3170
3171
/* New clipping region passed to default proc to exclude border */
3172
clipRgn = CreateRectRgn(r.left + cxEdge, r.top + cyEdge, r.right - cxEdge, r.bottom - cyEdge);
3173
if (region != (HRGN)1)
3174
CombineRgn(clipRgn, clipRgn, region, RGN_AND);
3175
OffsetRect(&r, -r.left, -r.top);
3176
3177
dc = GetDCEx(hwnd, region, DCX_WINDOW | DCX_INTERSECTRGN);
3178
if (IsThemeBackgroundPartiallyTransparent(theme, 0, 0))
3179
DrawThemeParentBackground(hwnd, dc, &r);
3180
DrawThemeBackground(theme, dc, 0, 0, &r, 0);
3181
ReleaseDC(hwnd, dc);
3182
if (theme_class)
3183
CloseThemeData(theme);
3184
3185
/* Call default proc to get the scrollbars etc. also painted */
3186
DefWindowProcW(hwnd, WM_NCPAINT, (WPARAM)clipRgn, 0);
3187
DeleteObject(clipRgn);
3188
return 0;
3189
#else
3190
return DefWindowProcW(hwnd, WM_NCPAINT, wp, lp);
3191
#endif
3192
}
3193
3194
BOOL COMCTL32_IsThemed(HWND hwnd)
3195
{
3196
#if __WINE_COMCTL32_VERSION == 6
3197
return !!GetWindowTheme(hwnd);
3198
#else
3199
return FALSE;
3200
#endif
3201
}
3202
3203