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