Fix remaining text file line endings in the tree. (#18)
[reactos.git] / dll / win32 / comctl32 / comctl32undoc.c
1 /*
2 * Undocumented functions from COMCTL32.DLL
3 *
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 * All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
24 * Do NOT rely on names or contents of undocumented structures and types!!!
25 * These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
26 * COMCTL32.DLL (internally).
27 *
28 */
29
30 #include "comctl32.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
33
34 static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 };
35
36 /**************************************************************************
37 * Alloc [COMCTL32.71]
38 *
39 * Allocates memory block from the dll's private heap
40 *
41 * PARAMS
42 * dwSize [I] size of the allocated memory block
43 *
44 * RETURNS
45 * Success: pointer to allocated memory block
46 * Failure: NULL
47 */
48 LPVOID WINAPI Alloc (DWORD dwSize)
49 {
50 return LocalAlloc( LMEM_ZEROINIT, dwSize );
51 }
52
53
54 /**************************************************************************
55 * ReAlloc [COMCTL32.72]
56 *
57 * Changes the size of an allocated memory block or allocates a memory
58 * block using the dll's private heap.
59 *
60 * PARAMS
61 * lpSrc [I] pointer to memory block which will be resized
62 * dwSize [I] new size of the memory block.
63 *
64 * RETURNS
65 * Success: pointer to the resized memory block
66 * Failure: NULL
67 *
68 * NOTES
69 * If lpSrc is a NULL-pointer, then ReAlloc allocates a memory
70 * block like Alloc.
71 */
72 LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize)
73 {
74 if (lpSrc)
75 return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT | LMEM_MOVEABLE );
76 else
77 return LocalAlloc( LMEM_ZEROINIT, dwSize);
78 }
79
80
81 /**************************************************************************
82 * Free [COMCTL32.73]
83 *
84 * Frees an allocated memory block from the dll's private heap.
85 *
86 * PARAMS
87 * lpMem [I] pointer to memory block which will be freed
88 *
89 * RETURNS
90 * Success: TRUE
91 * Failure: FALSE
92 */
93 BOOL WINAPI Free (LPVOID lpMem)
94 {
95 return !LocalFree( lpMem );
96 }
97
98
99 /**************************************************************************
100 * GetSize [COMCTL32.74]
101 *
102 * Retrieves the size of the specified memory block from the dll's
103 * private heap.
104 *
105 * PARAMS
106 * lpMem [I] pointer to an allocated memory block
107 *
108 * RETURNS
109 * Success: size of the specified memory block
110 * Failure: 0
111 */
112 DWORD WINAPI GetSize (LPVOID lpMem)
113 {
114 return LocalSize( lpMem );
115 }
116
117
118 /**************************************************************************
119 * MRU-Functions {COMCTL32}
120 *
121 * NOTES
122 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently
123 * Used) items. It is an undocumented API that is used (at least) by the shell
124 * and explorer to implement their recent documents feature.
125 *
126 * Since these functions are undocumented, they are unsupported by MS and
127 * may change at any time.
128 *
129 * Internally, the list is implemented as a last in, last out list of items
130 * persisted into the system registry under a caller chosen key. Each list
131 * item is given a one character identifier in the Ascii range from 'a' to
132 * '}'. A list of the identifiers in order from newest to oldest is stored
133 * under the same key in a value named "MRUList".
134 *
135 * Items are re-ordered by changing the order of the values in the MRUList
136 * value. When a new item is added, it becomes the new value of the oldest
137 * identifier, and that identifier is moved to the front of the MRUList value.
138 *
139 * Wine stores MRU-lists in the same registry format as Windows, so when
140 * switching between the builtin and native comctl32.dll no problems or
141 * incompatibilities should occur.
142 *
143 * The following undocumented structure is used to create an MRU-list:
144 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
145 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
146 *|
147 *|typedef struct tagMRUINFO
148 *|{
149 *| DWORD cbSize;
150 *| UINT uMax;
151 *| UINT fFlags;
152 *| HKEY hKey;
153 *| LPTSTR lpszSubKey;
154 *| PROC lpfnCompare;
155 *|} MRUINFO, *LPMRUINFO;
156 *
157 * MEMBERS
158 * cbSize [I] The size of the MRUINFO structure. This must be set
159 * to sizeof(MRUINFO) by the caller.
160 * uMax [I] The maximum number of items allowed in the list. Because
161 * of the limited number of identifiers, this should be set to
162 * a value from 1 to 30 by the caller.
163 * fFlags [I] If bit 0 is set, the list will be used to store binary
164 * data, otherwise it is assumed to store strings. If bit 1
165 * is set, every change made to the list will be reflected in
166 * the registry immediately, otherwise changes will only be
167 * written when the list is closed.
168 * hKey [I] The registry key that the list should be written under.
169 * This must be supplied by the caller.
170 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
171 * the list to. This may not be blank.
172 * lpfnCompare [I] A caller supplied comparison function, which may be either
173 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
174 * MRUBinaryCmpFn otherwise.
175 *
176 * FUNCTIONS
177 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
178 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
179 * - Remove items from an MRU-list with DelMRUString().
180 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
181 * - Iterate through an MRU-list with EnumMRUList().
182 * - Free an MRU-list with FreeMRUList().
183 */
184
185 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
186 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
187 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
188
189 typedef struct tagMRUINFOA
190 {
191 DWORD cbSize;
192 UINT uMax;
193 UINT fFlags;
194 HKEY hKey;
195 LPSTR lpszSubKey;
196 union
197 {
198 MRUStringCmpFnA string_cmpfn;
199 MRUBinaryCmpFn binary_cmpfn;
200 } u;
201 } MRUINFOA, *LPMRUINFOA;
202
203 typedef struct tagMRUINFOW
204 {
205 DWORD cbSize;
206 UINT uMax;
207 UINT fFlags;
208 HKEY hKey;
209 LPWSTR lpszSubKey;
210 union
211 {
212 MRUStringCmpFnW string_cmpfn;
213 MRUBinaryCmpFn binary_cmpfn;
214 } u;
215 } MRUINFOW, *LPMRUINFOW;
216
217 /* MRUINFO.fFlags */
218 #define MRU_STRING 0 /* list will contain strings */
219 #define MRU_BINARY 1 /* list will contain binary data */
220 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */
221
222 /* If list is a string list lpfnCompare has the following prototype
223 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
224 * for binary lists the prototype is
225 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
226 * where cbData is the no. of bytes to compare.
227 * Need to check what return value means identical - 0?
228 */
229
230 typedef struct tagWINEMRUITEM
231 {
232 DWORD size; /* size of data stored */
233 DWORD itemFlag; /* flags */
234 BYTE datastart;
235 } WINEMRUITEM, *LPWINEMRUITEM;
236
237 /* itemFlag */
238 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
239
240 typedef struct tagWINEMRULIST
241 {
242 MRUINFOW extview; /* original create information */
243 BOOL isUnicode; /* is compare fn Unicode */
244 DWORD wineFlags; /* internal flags */
245 DWORD cursize; /* current size of realMRU */
246 LPWSTR realMRU; /* pointer to string of index names */
247 LPWINEMRUITEM *array; /* array of pointers to data */
248 /* in 'a' to 'z' order */
249 } WINEMRULIST, *LPWINEMRULIST;
250
251 /* wineFlags */
252 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
253
254 /**************************************************************************
255 * MRU_SaveChanged (internal)
256 *
257 * Local MRU saving code
258 */
259 static void MRU_SaveChanged ( LPWINEMRULIST mp )
260 {
261 UINT i, err;
262 HKEY newkey;
263 WCHAR realname[2];
264 LPWINEMRUITEM witem;
265
266 /* or should we do the following instead of RegOpenKeyEx:
267 */
268
269 /* open the sub key */
270 if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
271 0, KEY_WRITE, &newkey))) {
272 /* not present - what to do ??? */
273 ERR("Could not open key, error=%d, attempting to create\n",
274 err);
275 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
276 0,
277 NULL,
278 REG_OPTION_NON_VOLATILE,
279 KEY_READ | KEY_WRITE,
280 0,
281 &newkey,
282 0))) {
283 ERR("failed to create key /%s/, err=%d\n",
284 debugstr_w(mp->extview.lpszSubKey), err);
285 return;
286 }
287 }
288 if (mp->wineFlags & WMRUF_CHANGED) {
289 mp->wineFlags &= ~WMRUF_CHANGED;
290 err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU,
291 (strlenW(mp->realMRU) + 1)*sizeof(WCHAR));
292 if (err) {
293 ERR("error saving MRUList, err=%d\n", err);
294 }
295 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
296 }
297 realname[1] = 0;
298 for(i=0; i<mp->cursize; i++) {
299 witem = mp->array[i];
300 if (witem->itemFlag & WMRUIF_CHANGED) {
301 witem->itemFlag &= ~WMRUIF_CHANGED;
302 realname[0] = 'a' + i;
303 err = RegSetValueExW(newkey, realname, 0,
304 (mp->extview.fFlags & MRU_BINARY) ?
305 REG_BINARY : REG_SZ,
306 &witem->datastart, witem->size);
307 if (err) {
308 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
309 }
310 TRACE("saving value for name /%s/ size=%d\n",
311 debugstr_w(realname), witem->size);
312 }
313 }
314 RegCloseKey( newkey );
315 }
316
317 /**************************************************************************
318 * FreeMRUList [COMCTL32.152]
319 *
320 * Frees a most-recently-used items list.
321 *
322 * PARAMS
323 * hMRUList [I] Handle to list.
324 *
325 * RETURNS
326 * Nothing.
327 */
328 void WINAPI FreeMRUList (HANDLE hMRUList)
329 {
330 LPWINEMRULIST mp = hMRUList;
331 UINT i;
332
333 TRACE("(%p)\n", hMRUList);
334 if (!hMRUList)
335 return;
336
337 if (mp->wineFlags & WMRUF_CHANGED) {
338 /* need to open key and then save the info */
339 MRU_SaveChanged( mp );
340 }
341
342 for(i=0; i<mp->extview.uMax; i++)
343 Free(mp->array[i]);
344
345 Free(mp->realMRU);
346 Free(mp->array);
347 Free(mp->extview.lpszSubKey);
348 Free(mp);
349 }
350
351
352 /**************************************************************************
353 * FindMRUData [COMCTL32.169]
354 *
355 * Searches binary list for item that matches lpData of length cbData.
356 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
357 * corresponding to item's reg. name will be stored in it ('a' -> 0).
358 *
359 * PARAMS
360 * hList [I] list handle
361 * lpData [I] data to find
362 * cbData [I] length of data
363 * lpRegNum [O] position in registry (maybe NULL)
364 *
365 * RETURNS
366 * Position in list 0 -> MRU. -1 if item not found.
367 */
368 INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData,
369 LPINT lpRegNum)
370 {
371 const WINEMRULIST *mp = hList;
372 INT ret;
373 UINT i;
374 LPSTR dataA = NULL;
375
376 if (!mp || !mp->extview.u.string_cmpfn)
377 return -1;
378
379 if(!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode) {
380 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
381 NULL, 0, NULL, NULL);
382 dataA = Alloc(len);
383 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
384 }
385
386 for(i=0; i<mp->cursize; i++) {
387 if (mp->extview.fFlags & MRU_BINARY) {
388 if (!mp->extview.u.binary_cmpfn(lpData, &mp->array[i]->datastart, cbData))
389 break;
390 }
391 else {
392 if(mp->isUnicode) {
393 if (!mp->extview.u.string_cmpfn(lpData, (LPWSTR)&mp->array[i]->datastart))
394 break;
395 } else {
396 DWORD len = WideCharToMultiByte(CP_ACP, 0,
397 (LPWSTR)&mp->array[i]->datastart, -1,
398 NULL, 0, NULL, NULL);
399 LPSTR itemA = Alloc(len);
400 INT cmp;
401 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
402 itemA, len, NULL, NULL);
403
404 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
405 Free(itemA);
406 if(!cmp)
407 break;
408 }
409 }
410 }
411 Free(dataA);
412 if (i < mp->cursize)
413 ret = i;
414 else
415 ret = -1;
416 if (lpRegNum && (ret != -1))
417 *lpRegNum = 'a' + i;
418
419 TRACE("(%p, %p, %d, %p) returning %d\n",
420 hList, lpData, cbData, lpRegNum, ret);
421
422 return ret;
423 }
424
425
426 /**************************************************************************
427 * AddMRUData [COMCTL32.167]
428 *
429 * Add item to MRU binary list. If item already exists in list then it is
430 * simply moved up to the top of the list and not added again. If list is
431 * full then the least recently used item is removed to make room.
432 *
433 * PARAMS
434 * hList [I] Handle to list.
435 * lpData [I] ptr to data to add.
436 * cbData [I] no. of bytes of data.
437 *
438 * RETURNS
439 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
440 * -1 on error.
441 */
442 INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
443 {
444 LPWINEMRULIST mp = hList;
445 LPWINEMRUITEM witem;
446 INT i, replace;
447
448 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) {
449 /* Item exists, just move it to the front */
450 LPWSTR pos = strchrW(mp->realMRU, replace + 'a');
451 while (pos > mp->realMRU)
452 {
453 pos[0] = pos[-1];
454 pos--;
455 }
456 }
457 else {
458 /* either add a new entry or replace oldest */
459 if (mp->cursize < mp->extview.uMax) {
460 /* Add in a new item */
461 replace = mp->cursize;
462 mp->cursize++;
463 }
464 else {
465 /* get the oldest entry and replace data */
466 replace = mp->realMRU[mp->cursize - 1] - 'a';
467 Free(mp->array[replace]);
468 }
469
470 /* Allocate space for new item and move in the data */
471 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
472 witem->itemFlag |= WMRUIF_CHANGED;
473 witem->size = cbData;
474 memcpy( &witem->datastart, lpData, cbData);
475
476 /* now rotate MRU list */
477 for(i=mp->cursize-1; i>=1; i--)
478 mp->realMRU[i] = mp->realMRU[i-1];
479 }
480
481 /* The new item gets the front spot */
482 mp->wineFlags |= WMRUF_CHANGED;
483 mp->realMRU[0] = replace + 'a';
484
485 TRACE("(%p, %p, %d) adding data, /%c/ now most current\n",
486 hList, lpData, cbData, replace+'a');
487
488 if (!(mp->extview.fFlags & MRU_CACHEWRITE)) {
489 /* save changed stuff right now */
490 MRU_SaveChanged( mp );
491 }
492
493 return replace;
494 }
495
496 /**************************************************************************
497 * AddMRUStringW [COMCTL32.401]
498 *
499 * Add an item to an MRU string list.
500 *
501 * PARAMS
502 * hList [I] Handle to list.
503 * lpszString [I] The string to add.
504 *
505 * RETURNS
506 * Success: The number corresponding to the registry name where the string
507 * has been stored (0 maps to 'a', 1 to 'b' and so on).
508 * Failure: -1, if hList is NULL or memory allocation fails. If lpszString
509 * is invalid, the function returns 0, and GetLastError() returns
510 * ERROR_INVALID_PARAMETER. The last error value is set only in
511 * this case.
512 *
513 * NOTES
514 * -If lpszString exists in the list already, it is moved to the top of the
515 * MRU list (it is not duplicated).
516 * -If the list is full the least recently used list entry is replaced with
517 * lpszString.
518 * -If this function returns 0 you should check the last error value to
519 * ensure the call really succeeded.
520 */
521 INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
522 {
523 TRACE("(%p,%s)\n", hList, debugstr_w(lpszString));
524
525 if (!hList)
526 return -1;
527
528 if (!lpszString || IsBadStringPtrW(lpszString, -1))
529 {
530 SetLastError(ERROR_INVALID_PARAMETER);
531 return 0;
532 }
533
534 return AddMRUData(hList, lpszString,
535 (strlenW(lpszString) + 1) * sizeof(WCHAR));
536 }
537
538 /**************************************************************************
539 * AddMRUStringA [COMCTL32.153]
540 *
541 * See AddMRUStringW.
542 */
543 INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString)
544 {
545 DWORD len;
546 LPWSTR stringW;
547 INT ret;
548
549 TRACE("(%p,%s)\n", hList, debugstr_a(lpszString));
550
551 if (!hList)
552 return -1;
553
554 if (IsBadStringPtrA(lpszString, -1))
555 {
556 SetLastError(ERROR_INVALID_PARAMETER);
557 return 0;
558 }
559
560 len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR);
561 stringW = Alloc(len);
562 if (!stringW)
563 return -1;
564
565 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len/sizeof(WCHAR));
566 ret = AddMRUData(hList, stringW, len);
567 Free(stringW);
568 return ret;
569 }
570
571 /**************************************************************************
572 * DelMRUString [COMCTL32.156]
573 *
574 * Removes item from either string or binary list (despite its name)
575 *
576 * PARAMS
577 * hList [I] list handle
578 * nItemPos [I] item position to remove 0 -> MRU
579 *
580 * RETURNS
581 * TRUE if successful, FALSE if nItemPos is out of range.
582 */
583 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
584 {
585 FIXME("(%p, %d): stub\n", hList, nItemPos);
586 return TRUE;
587 }
588
589 /**************************************************************************
590 * FindMRUStringW [COMCTL32.402]
591 *
592 * See FindMRUStringA.
593 */
594 INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
595 {
596 return FindMRUData(hList, lpszString,
597 (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum);
598 }
599
600 /**************************************************************************
601 * FindMRUStringA [COMCTL32.155]
602 *
603 * Searches string list for item that matches lpszString.
604 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
605 * corresponding to item's reg. name will be stored in it ('a' -> 0).
606 *
607 * PARAMS
608 * hList [I] list handle
609 * lpszString [I] string to find
610 * lpRegNum [O] position in registry (maybe NULL)
611 *
612 * RETURNS
613 * Position in list 0 -> MRU. -1 if item not found.
614 */
615 INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
616 {
617 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
618 LPWSTR stringW = Alloc(len * sizeof(WCHAR));
619 INT ret;
620
621 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
622 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
623 Free(stringW);
624 return ret;
625 }
626
627 /*************************************************************************
628 * create_mru_list (internal)
629 */
630 static HANDLE create_mru_list(LPWINEMRULIST mp)
631 {
632 UINT i, err;
633 HKEY newkey;
634 DWORD datasize, dwdisp;
635 WCHAR realname[2];
636 LPWINEMRUITEM witem;
637 DWORD type;
638
639 /* get space to save indices that will turn into names
640 * but in order of most to least recently used
641 */
642 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
643
644 /* get space to save pointers to actual data in order of
645 * 'a' to 'z' (0 to n).
646 */
647 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
648
649 /* open the sub key */
650 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
651 0,
652 NULL,
653 REG_OPTION_NON_VOLATILE,
654 KEY_READ | KEY_WRITE,
655 0,
656 &newkey,
657 &dwdisp))) {
658 /* error - what to do ??? */
659 ERR("(%u %u %x %p %s %p): Could not open key, error=%d\n",
660 mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
661 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
662 mp->extview.u.string_cmpfn, err);
663 return 0;
664 }
665
666 /* get values from key 'MRUList' */
667 if (newkey) {
668 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
669 if (RegQueryValueExW( newkey, strMRUList, 0, &type,
670 (LPBYTE)mp->realMRU, &datasize)) {
671 /* not present - set size to 1 (will become 0 later) */
672 datasize = 1;
673 *mp->realMRU = 0;
674 }
675 else
676 datasize /= sizeof(WCHAR);
677
678 TRACE("MRU list = %s, datasize = %d\n", debugstr_w(mp->realMRU), datasize);
679
680 mp->cursize = datasize - 1;
681 /* datasize now has number of items in the MRUList */
682
683 /* get actual values for each entry */
684 realname[1] = 0;
685 for(i=0; i<mp->cursize; i++) {
686 realname[0] = 'a' + i;
687 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
688 /* not present - what to do ??? */
689 ERR("Key %s not found 1\n", debugstr_w(realname));
690 }
691 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
692 witem->size = datasize;
693 if(RegQueryValueExW( newkey, realname, 0, &type,
694 &witem->datastart, &datasize)) {
695 /* not present - what to do ??? */
696 ERR("Key %s not found 2\n", debugstr_w(realname));
697 }
698 }
699 RegCloseKey( newkey );
700 }
701 else
702 mp->cursize = 0;
703
704 TRACE("(%u %u %x %p %s %p): Current Size = %d\n",
705 mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
706 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
707 mp->extview.u.string_cmpfn, mp->cursize);
708 return mp;
709 }
710
711 /**************************************************************************
712 * CreateMRUListLazyW [COMCTL32.404]
713 *
714 * See CreateMRUListLazyA.
715 */
716 HANDLE WINAPI CreateMRUListLazyW (const MRUINFOW *infoW, DWORD dwParam2,
717 DWORD dwParam3, DWORD dwParam4)
718 {
719 LPWINEMRULIST mp;
720
721 /* Native does not check for a NULL lpcml */
722 if (!infoW->hKey || IsBadStringPtrW(infoW->lpszSubKey, -1))
723 return NULL;
724
725 mp = Alloc(sizeof(WINEMRULIST));
726 memcpy(&mp->extview, infoW, sizeof(MRUINFOW));
727 mp->extview.lpszSubKey = Alloc((strlenW(infoW->lpszSubKey) + 1) * sizeof(WCHAR));
728 strcpyW(mp->extview.lpszSubKey, infoW->lpszSubKey);
729 mp->isUnicode = TRUE;
730
731 return create_mru_list(mp);
732 }
733
734 /**************************************************************************
735 * CreateMRUListLazyA [COMCTL32.157]
736 *
737 * Creates a most-recently-used list.
738 *
739 * PARAMS
740 * lpcml [I] ptr to CREATEMRULIST structure.
741 * dwParam2 [I] Unknown
742 * dwParam3 [I] Unknown
743 * dwParam4 [I] Unknown
744 *
745 * RETURNS
746 * Handle to MRU list.
747 */
748 HANDLE WINAPI CreateMRUListLazyA (const MRUINFOA *lpcml, DWORD dwParam2,
749 DWORD dwParam3, DWORD dwParam4)
750 {
751 LPWINEMRULIST mp;
752 DWORD len;
753
754 /* Native does not check for a NULL lpcml */
755
756 if (!lpcml->hKey || IsBadStringPtrA(lpcml->lpszSubKey, -1))
757 return 0;
758
759 mp = Alloc(sizeof(WINEMRULIST));
760 memcpy(&mp->extview, lpcml, sizeof(MRUINFOA));
761 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
762 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
763 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
764 mp->extview.lpszSubKey, len);
765 mp->isUnicode = FALSE;
766 return create_mru_list(mp);
767 }
768
769 /**************************************************************************
770 * CreateMRUListW [COMCTL32.400]
771 *
772 * See CreateMRUListA.
773 */
774 HANDLE WINAPI CreateMRUListW (const MRUINFOW *infoW)
775 {
776 return CreateMRUListLazyW(infoW, 0, 0, 0);
777 }
778
779 /**************************************************************************
780 * CreateMRUListA [COMCTL32.151]
781 *
782 * Creates a most-recently-used list.
783 *
784 * PARAMS
785 * lpcml [I] ptr to CREATEMRULIST structure.
786 *
787 * RETURNS
788 * Handle to MRU list.
789 */
790 HANDLE WINAPI CreateMRUListA (const MRUINFOA *lpcml)
791 {
792 return CreateMRUListLazyA (lpcml, 0, 0, 0);
793 }
794
795
796 /**************************************************************************
797 * EnumMRUListW [COMCTL32.403]
798 *
799 * Enumerate item in a most-recently-used list
800 *
801 * PARAMS
802 * hList [I] list handle
803 * nItemPos [I] item position to enumerate
804 * lpBuffer [O] buffer to receive item
805 * nBufferSize [I] size of buffer
806 *
807 * RETURNS
808 * For binary lists specifies how many bytes were copied to buffer, for
809 * string lists specifies full length of string. Enumerating past the end
810 * of list returns -1.
811 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
812 * the list.
813 */
814 INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
815 DWORD nBufferSize)
816 {
817 const WINEMRULIST *mp = hList;
818 const WINEMRUITEM *witem;
819 INT desired, datasize;
820
821 if (!mp) return -1;
822 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
823 if (nItemPos >= mp->cursize) return -1;
824 desired = mp->realMRU[nItemPos];
825 desired -= 'a';
826 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
827 witem = mp->array[desired];
828 datasize = min( witem->size, nBufferSize );
829 memcpy( lpBuffer, &witem->datastart, datasize);
830 TRACE("(%p, %d, %p, %d): returning len=%d\n",
831 hList, nItemPos, lpBuffer, nBufferSize, datasize);
832 return datasize;
833 }
834
835 /**************************************************************************
836 * EnumMRUListA [COMCTL32.154]
837 *
838 * See EnumMRUListW.
839 */
840 INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
841 DWORD nBufferSize)
842 {
843 const WINEMRULIST *mp = hList;
844 LPWINEMRUITEM witem;
845 INT desired, datasize;
846 DWORD lenA;
847
848 if (!mp) return -1;
849 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
850 if (nItemPos >= mp->cursize) return -1;
851 desired = mp->realMRU[nItemPos];
852 desired -= 'a';
853 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
854 witem = mp->array[desired];
855 if(mp->extview.fFlags & MRU_BINARY) {
856 datasize = min( witem->size, nBufferSize );
857 memcpy( lpBuffer, &witem->datastart, datasize);
858 } else {
859 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
860 NULL, 0, NULL, NULL);
861 datasize = min( lenA, nBufferSize );
862 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
863 lpBuffer, datasize, NULL, NULL);
864 ((char *)lpBuffer)[ datasize - 1 ] = '\0';
865 datasize = lenA - 1;
866 }
867 TRACE("(%p, %d, %p, %d): returning len=%d\n",
868 hList, nItemPos, lpBuffer, nBufferSize, datasize);
869 return datasize;
870 }
871
872 /**************************************************************************
873 * Str_GetPtrWtoA [internal]
874 *
875 * Converts a unicode string into a multi byte string
876 *
877 * PARAMS
878 * lpSrc [I] Pointer to the unicode source string
879 * lpDest [O] Pointer to caller supplied storage for the multi byte string
880 * nMaxLen [I] Size, in bytes, of the destination buffer
881 *
882 * RETURNS
883 * Length, in bytes, of the converted string.
884 */
885
886 INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
887 {
888 INT len;
889
890 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
891
892 if (!lpDest && lpSrc)
893 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
894
895 if (nMaxLen == 0)
896 return 0;
897
898 if (lpSrc == NULL) {
899 lpDest[0] = '\0';
900 return 0;
901 }
902
903 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
904 if (len >= nMaxLen)
905 len = nMaxLen - 1;
906
907 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
908 lpDest[len] = '\0';
909
910 return len;
911 }
912
913 /**************************************************************************
914 * Str_GetPtrAtoW [internal]
915 *
916 * Converts a multibyte string into a unicode string
917 *
918 * PARAMS
919 * lpSrc [I] Pointer to the multibyte source string
920 * lpDest [O] Pointer to caller supplied storage for the unicode string
921 * nMaxLen [I] Size, in characters, of the destination buffer
922 *
923 * RETURNS
924 * Length, in characters, of the converted string.
925 */
926
927 INT Str_GetPtrAtoW (LPCSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
928 {
929 INT len;
930
931 TRACE("(%s %p %d)\n", debugstr_a(lpSrc), lpDest, nMaxLen);
932
933 if (!lpDest && lpSrc)
934 return MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, 0, 0);
935
936 if (nMaxLen == 0)
937 return 0;
938
939 if (lpSrc == NULL) {
940 lpDest[0] = '\0';
941 return 0;
942 }
943
944 len = MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, 0, 0);
945 if (len >= nMaxLen)
946 len = nMaxLen - 1;
947
948 MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, lpDest, len);
949 lpDest[len] = '\0';
950
951 return len;
952 }
953
954
955 /**************************************************************************
956 * Str_SetPtrAtoW [internal]
957 *
958 * Converts a multi byte string to a unicode string.
959 * If the pointer to the destination buffer is NULL a buffer is allocated.
960 * If the destination buffer is too small to keep the converted multi byte
961 * string the destination buffer is reallocated. If the source pointer is
962 * NULL, the destination buffer is freed.
963 *
964 * PARAMS
965 * lppDest [I/O] pointer to a pointer to the destination buffer
966 * lpSrc [I] pointer to a multi byte string
967 *
968 * RETURNS
969 * TRUE: conversion successful
970 * FALSE: error
971 */
972 BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
973 {
974 TRACE("(%p %s)\n", lppDest, lpSrc);
975
976 if (lpSrc) {
977 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
978 LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR));
979
980 if (!ptr)
981 return FALSE;
982 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
983 *lppDest = ptr;
984 }
985 else {
986 Free (*lppDest);
987 *lppDest = NULL;
988 }
989
990 return TRUE;
991 }
992
993 /**************************************************************************
994 * Str_SetPtrWtoA [internal]
995 *
996 * Converts a unicode string to a multi byte string.
997 * If the pointer to the destination buffer is NULL a buffer is allocated.
998 * If the destination buffer is too small to keep the converted wide
999 * string the destination buffer is reallocated. If the source pointer is
1000 * NULL, the destination buffer is freed.
1001 *
1002 * PARAMS
1003 * lppDest [I/O] pointer to a pointer to the destination buffer
1004 * lpSrc [I] pointer to a wide string
1005 *
1006 * RETURNS
1007 * TRUE: conversion successful
1008 * FALSE: error
1009 */
1010 BOOL Str_SetPtrWtoA (LPSTR *lppDest, LPCWSTR lpSrc)
1011 {
1012 TRACE("(%p %s)\n", lppDest, debugstr_w(lpSrc));
1013
1014 if (lpSrc) {
1015 INT len = WideCharToMultiByte(CP_ACP,0,lpSrc,-1,NULL,0,NULL,FALSE);
1016 LPSTR ptr = ReAlloc (*lppDest, len*sizeof(CHAR));
1017
1018 if (!ptr)
1019 return FALSE;
1020 WideCharToMultiByte(CP_ACP,0,lpSrc,-1,ptr,len,NULL,FALSE);
1021 *lppDest = ptr;
1022 }
1023 else {
1024 Free (*lppDest);
1025 *lppDest = NULL;
1026 }
1027
1028 return TRUE;
1029 }
1030
1031
1032 /**************************************************************************
1033 * Notification functions
1034 */
1035
1036 typedef struct tagNOTIFYDATA
1037 {
1038 HWND hwndFrom;
1039 HWND hwndTo;
1040 DWORD dwParam3;
1041 DWORD dwParam4;
1042 DWORD dwParam5;
1043 DWORD dwParam6;
1044 } NOTIFYDATA, *LPNOTIFYDATA;
1045
1046
1047 /**************************************************************************
1048 * DoNotify [Internal]
1049 */
1050
1051 static LRESULT DoNotify (const NOTIFYDATA *lpNotify, UINT uCode, LPNMHDR lpHdr)
1052 {
1053 NMHDR nmhdr;
1054 LPNMHDR lpNmh = NULL;
1055 UINT idFrom = 0;
1056
1057 TRACE("(%p %p %d %p 0x%08x)\n",
1058 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1059 lpNotify->dwParam5);
1060
1061 if (!lpNotify->hwndTo)
1062 return 0;
1063
1064 if (lpNotify->hwndFrom == (HWND)-1) {
1065 lpNmh = lpHdr;
1066 idFrom = lpHdr->idFrom;
1067 }
1068 else {
1069 if (lpNotify->hwndFrom)
1070 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1071
1072 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1073
1074 lpNmh->hwndFrom = lpNotify->hwndFrom;
1075 lpNmh->idFrom = idFrom;
1076 lpNmh->code = uCode;
1077 }
1078
1079 return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1080 }
1081
1082
1083 /**************************************************************************
1084 * SendNotify [COMCTL32.341]
1085 *
1086 * Sends a WM_NOTIFY message to the specified window.
1087 *
1088 * PARAMS
1089 * hwndTo [I] Window to receive the message
1090 * hwndFrom [I] Window that the message is from (see notes)
1091 * uCode [I] Notification code
1092 * lpHdr [I] The NMHDR and any additional information to send or NULL
1093 *
1094 * RETURNS
1095 * Success: return value from notification
1096 * Failure: 0
1097 *
1098 * NOTES
1099 * If hwndFrom is -1 then the identifier of the control sending the
1100 * message is taken from the NMHDR structure.
1101 * If hwndFrom is not -1 then lpHdr can be NULL.
1102 */
1103 LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
1104 {
1105 NOTIFYDATA notify;
1106
1107 TRACE("(%p %p %d %p)\n",
1108 hwndTo, hwndFrom, uCode, lpHdr);
1109
1110 notify.hwndFrom = hwndFrom;
1111 notify.hwndTo = hwndTo;
1112 notify.dwParam5 = 0;
1113 notify.dwParam6 = 0;
1114
1115 return DoNotify (&notify, uCode, lpHdr);
1116 }
1117
1118
1119 /**************************************************************************
1120 * SendNotifyEx [COMCTL32.342]
1121 *
1122 * Sends a WM_NOTIFY message to the specified window.
1123 *
1124 * PARAMS
1125 * hwndFrom [I] Window to receive the message
1126 * hwndTo [I] Window that the message is from
1127 * uCode [I] Notification code
1128 * lpHdr [I] The NMHDR and any additional information to send or NULL
1129 * dwParam5 [I] Unknown
1130 *
1131 * RETURNS
1132 * Success: return value from notification
1133 * Failure: 0
1134 *
1135 * NOTES
1136 * If hwndFrom is -1 then the identifier of the control sending the
1137 * message is taken from the NMHDR structure.
1138 * If hwndFrom is not -1 then lpHdr can be NULL.
1139 */
1140 LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1141 LPNMHDR lpHdr, DWORD dwParam5)
1142 {
1143 NOTIFYDATA notify;
1144 HWND hwndNotify;
1145
1146 TRACE("(%p %p %d %p 0x%08x)\n",
1147 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1148
1149 hwndNotify = hwndTo;
1150 if (!hwndTo) {
1151 if (IsWindow (hwndFrom)) {
1152 hwndNotify = GetParent (hwndFrom);
1153 if (!hwndNotify)
1154 return 0;
1155 }
1156 }
1157
1158 notify.hwndFrom = hwndFrom;
1159 notify.hwndTo = hwndNotify;
1160 notify.dwParam5 = dwParam5;
1161 notify.dwParam6 = 0;
1162
1163 return DoNotify (&notify, uCode, lpHdr);
1164 }