Sync to Wine-20050524:
[reactos.git] / reactos / lib / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdarg.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <limits.h>
36
37 #define COBJMACROS
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wingdi.h"
44 #include "winuser.h"
45 #include "winnls.h"
46 #include "winreg.h"
47 #include "commctrl.h"
48 #include "objbase.h"
49 #include "winerror.h"
50
51 #include "wine/unicode.h"
52 #include "comctl32.h"
53
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
57
58 struct _DSA
59 {
60 INT nItemCount;
61 LPVOID pData;
62 INT nMaxCount;
63 INT nItemSize;
64 INT nGrow;
65 };
66
67 struct _DPA
68 {
69 INT nItemCount;
70 LPVOID *ptrs;
71 HANDLE hHeap;
72 INT nGrow;
73 INT nMaxCount;
74 };
75
76 typedef struct _STREAMDATA
77 {
78 DWORD dwSize;
79 DWORD dwData2;
80 DWORD dwItems;
81 } STREAMDATA, *PSTREAMDATA;
82
83 typedef struct _LOADDATA
84 {
85 INT nCount;
86 PVOID ptr;
87 } LOADDATA, *LPLOADDATA;
88
89 typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
90
91 static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 };
92
93 /**************************************************************************
94 * DPA_LoadStream [COMCTL32.9]
95 *
96 * Loads a dynamic pointer array from a stream
97 *
98 * PARAMS
99 * phDpa [O] pointer to a handle to a dynamic pointer array
100 * loadProc [I] pointer to a callback function
101 * pStream [I] pointer to a stream
102 * lParam [I] application specific value
103 *
104 * RETURNS
105 * Success: TRUE
106 * Failure: FALSE
107 *
108 * NOTES
109 * No more information available yet!
110 */
111 HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc,
112 IStream *pStream, LPARAM lParam)
113 {
114 HRESULT errCode;
115 LARGE_INTEGER position;
116 ULARGE_INTEGER newPosition;
117 STREAMDATA streamData;
118 LOADDATA loadData;
119 ULONG ulRead;
120 HDPA hDpa;
121 PVOID *ptr;
122
123 FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
124 phDpa, loadProc, pStream, lParam);
125
126 if (!phDpa || !loadProc || !pStream)
127 return E_INVALIDARG;
128
129 *phDpa = (HDPA)NULL;
130
131 position.QuadPart = 0;
132
133 /*
134 * Zero out our streamData
135 */
136 memset(&streamData,0,sizeof(STREAMDATA));
137
138 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
139 if (errCode != S_OK)
140 return errCode;
141
142 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
143 if (errCode != S_OK)
144 return errCode;
145
146 FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
147 streamData.dwSize, streamData.dwData2, streamData.dwItems);
148
149 if ( ulRead < sizeof(STREAMDATA) ||
150 lParam < sizeof(STREAMDATA) ||
151 streamData.dwSize < sizeof(STREAMDATA) ||
152 streamData.dwData2 < 1) {
153 errCode = E_FAIL;
154 }
155
156 if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
157 return E_OUTOFMEMORY;
158
159 /* create the dpa */
160 hDpa = DPA_Create (streamData.dwItems);
161 if (!hDpa)
162 return E_OUTOFMEMORY;
163
164 if (!DPA_Grow (hDpa, streamData.dwItems))
165 return E_OUTOFMEMORY;
166
167 /* load data from the stream into the dpa */
168 ptr = hDpa->ptrs;
169 for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
170 errCode = (loadProc)(&loadData, pStream, lParam);
171 if (errCode != S_OK) {
172 errCode = S_FALSE;
173 break;
174 }
175
176 *ptr = loadData.ptr;
177 ptr++;
178 }
179
180 /* set the number of items */
181 hDpa->nItemCount = loadData.nCount;
182
183 /* store the handle to the dpa */
184 *phDpa = hDpa;
185 FIXME ("new hDpa=%p, errorcode=%lx\n", hDpa, errCode);
186
187 return errCode;
188 }
189
190
191 /**************************************************************************
192 * DPA_SaveStream [COMCTL32.10]
193 *
194 * Saves a dynamic pointer array to a stream
195 *
196 * PARAMS
197 * hDpa [I] handle to a dynamic pointer array
198 * loadProc [I] pointer to a callback function
199 * pStream [I] pointer to a stream
200 * lParam [I] application specific value
201 *
202 * RETURNS
203 * Success: TRUE
204 * Failure: FALSE
205 *
206 * NOTES
207 * No more information available yet!
208 */
209 HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc,
210 IStream *pStream, LPARAM lParam)
211 {
212
213 FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
214 hDpa, loadProc, pStream, lParam);
215
216 return E_FAIL;
217 }
218
219
220 /**************************************************************************
221 * DPA_Merge [COMCTL32.11]
222 *
223 * Merge two dynamic pointers arrays.
224 *
225 * PARAMS
226 * hdpa1 [I] handle to a dynamic pointer array
227 * hdpa2 [I] handle to a dynamic pointer array
228 * dwFlags [I] flags
229 * pfnCompare [I] pointer to sort function
230 * pfnMerge [I] pointer to merge function
231 * lParam [I] application specific value
232 *
233 * RETURNS
234 * Success: TRUE
235 * Failure: FALSE
236 *
237 * NOTES
238 * No more information available yet!
239 */
240 BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
241 PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge,
242 LPARAM lParam)
243 {
244 INT nCount;
245 LPVOID *pWork1, *pWork2;
246 INT nResult, i;
247 INT nIndex;
248
249 TRACE("%p %p %08lx %p %p %08lx)\n",
250 hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
251
252 if (IsBadWritePtr (hdpa1, sizeof(*hdpa1)))
253 return FALSE;
254
255 if (IsBadWritePtr (hdpa2, sizeof(*hdpa2)))
256 return FALSE;
257
258 if (IsBadCodePtr ((FARPROC)pfnCompare))
259 return FALSE;
260
261 if (IsBadCodePtr ((FARPROC)pfnMerge))
262 return FALSE;
263
264 if (!(dwFlags & DPAM_NOSORT)) {
265 TRACE("sorting dpa's!\n");
266 if (hdpa1->nItemCount > 0)
267 DPA_Sort (hdpa1, pfnCompare, lParam);
268 TRACE ("dpa 1 sorted!\n");
269 if (hdpa2->nItemCount > 0)
270 DPA_Sort (hdpa2, pfnCompare, lParam);
271 TRACE ("dpa 2 sorted!\n");
272 }
273
274 if (hdpa2->nItemCount < 1)
275 return TRUE;
276
277 TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
278 hdpa1->nItemCount, hdpa2->nItemCount);
279
280
281 /* working but untrusted implementation */
282
283 pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
284 pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
285
286 nIndex = hdpa1->nItemCount - 1;
287 nCount = hdpa2->nItemCount - 1;
288
289 do
290 {
291 if (nIndex < 0) {
292 if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) {
293 /* Now insert the remaining new items into DPA 1 */
294 TRACE("%d items to be inserted at start of DPA 1\n",
295 nCount+1);
296 for (i=nCount; i>=0; i--) {
297 PVOID ptr;
298
299 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
300 if (!ptr)
301 return FALSE;
302 DPA_InsertPtr (hdpa1, 0, ptr);
303 pWork2--;
304 }
305 }
306 break;
307 }
308 nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
309 TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
310 nResult, nIndex, nCount);
311
312 if (nResult == 0)
313 {
314 PVOID ptr;
315
316 ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam);
317 if (!ptr)
318 return FALSE;
319
320 nCount--;
321 pWork2--;
322 *pWork1 = ptr;
323 nIndex--;
324 pWork1--;
325 }
326 else if (nResult > 0)
327 {
328 /* item in DPA 1 missing from DPA 2 */
329 if (dwFlags & DPAM_DELETE)
330 {
331 /* Now delete the extra item in DPA1 */
332 PVOID ptr;
333
334 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
335
336 (pfnMerge)(2, ptr, NULL, lParam);
337 }
338 nIndex--;
339 pWork1--;
340 }
341 else
342 {
343 /* new item in DPA 2 */
344 if (dwFlags & DPAM_INSERT)
345 {
346 /* Now insert the new item in DPA 1 */
347 PVOID ptr;
348
349 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
350 if (!ptr)
351 return FALSE;
352 DPA_InsertPtr (hdpa1, nIndex+1, ptr);
353 }
354 nCount--;
355 pWork2--;
356 }
357
358 }
359 while (nCount >= 0);
360
361 return TRUE;
362 }
363
364
365 /**************************************************************************
366 * Alloc [COMCTL32.71]
367 *
368 * Allocates memory block from the dll's private heap
369 *
370 * PARAMS
371 * dwSize [I] size of the allocated memory block
372 *
373 * RETURNS
374 * Success: pointer to allocated memory block
375 * Failure: NULL
376 */
377 LPVOID WINAPI Alloc (DWORD dwSize)
378 {
379 return LocalAlloc( LMEM_ZEROINIT, dwSize );
380 }
381
382
383 /**************************************************************************
384 * ReAlloc [COMCTL32.72]
385 *
386 * Changes the size of an allocated memory block or allocates a memory
387 * block using the dll's private heap.
388 *
389 * PARAMS
390 * lpSrc [I] pointer to memory block which will be resized
391 * dwSize [I] new size of the memory block.
392 *
393 * RETURNS
394 * Success: pointer to the resized memory block
395 * Failure: NULL
396 *
397 * NOTES
398 * If lpSrc is a NULL-pointer, then ReAlloc allocates a memory
399 * block like Alloc.
400 */
401 LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize)
402 {
403 if (lpSrc)
404 return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT );
405 else
406 return LocalAlloc( LMEM_ZEROINIT, dwSize);
407 }
408
409
410 /**************************************************************************
411 * Free [COMCTL32.73]
412 *
413 * Frees an allocated memory block from the dll's private heap.
414 *
415 * PARAMS
416 * lpMem [I] pointer to memory block which will be freed
417 *
418 * RETURNS
419 * Success: TRUE
420 * Failure: FALSE
421 */
422 BOOL WINAPI Free (LPVOID lpMem)
423 {
424 return !LocalFree( lpMem );
425 }
426
427
428 /**************************************************************************
429 * GetSize [COMCTL32.74]
430 *
431 * Retrieves the size of the specified memory block from the dll's
432 * private heap.
433 *
434 * PARAMS
435 * lpMem [I] pointer to an allocated memory block
436 *
437 * RETURNS
438 * Success: size of the specified memory block
439 * Failure: 0
440 */
441 DWORD WINAPI GetSize (LPVOID lpMem)
442 {
443 return LocalSize( lpMem );
444 }
445
446
447 /**************************************************************************
448 * MRU-Functions {COMCTL32}
449 *
450 * NOTES
451 * The MRU-Api is a set of functions to manipulate lists of M.R.U. (Most Recently
452 * Used) items. It is an undocumented Api that is used (at least) by the shell
453 * and explorer to implement their recent documents feature.
454 *
455 * Since these functions are undocumented, they are unsupported by MS and
456 * may change at any time.
457 *
458 * Internally, the list is implemented as a last in, last out list of items
459 * persisted into the system registry under a caller chosen key. Each list
460 * item is given a one character identifier in the Ascii range from 'a' to
461 * '}'. A list of the identifiers in order from newest to oldest is stored
462 * under the same key in a value named "MRUList".
463 *
464 * Items are re-ordered by changing the order of the values in the MRUList
465 * value. When a new item is added, it becomes the new value of the oldest
466 * identifier, and that identifier is moved to the front of the MRUList value.
467 *
468 * Wine stores MRU-lists in the same registry format as Windows, so when
469 * switching between the builtin and native comctl32.dll no problems or
470 * incompatibilities should occur.
471 *
472 * The following undocumented structure is used to create an MRU-list:
473 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
474 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
475 *|
476 *|typedef struct tagCREATEMRULIST
477 *|{
478 *| DWORD cbSize;
479 *| DWORD nMaxItems;
480 *| DWORD dwFlags;
481 *| HKEY hKey;
482 *| LPCTSTR lpszSubKey;
483 *| PROC lpfnCompare;
484 *|} CREATEMRULIST, *LPCREATEMRULIST;
485 *
486 * MEMBERS
487 * cbSize [I] The size of the CREATEMRULIST structure. This must be set
488 * to sizeof(CREATEMRULIST) by the caller.
489 * nMaxItems [I] The maximum number of items allowed in the list. Because
490 * of the limited number of identifiers, this should be set to
491 * a value from 1 to 30 by the caller.
492 * dwFlags [I] If bit 0 is set, the list will be used to store binary
493 * data, otherwise it is assumed to store strings. If bit 1
494 * is set, every change made to the list will be reflected in
495 * the registry immediately, otherwise changes will only be
496 * written when the list is closed.
497 * hKey [I] The registry key that the list should be written under.
498 * This must be supplied by the caller.
499 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write
500 * the list to. This may not be blank.
501 * lpfnCompare [I] A caller supplied comparison function, which may be either
502 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
503 * MRUBinaryCmpFn otherwise.
504 *
505 * FUNCTIONS
506 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
507 * - Add items to an MRU-list with AddMRUString() or AddMRUData().
508 * - Remove items from an MRU-list with DelMRUString().
509 * - Find data in an MRU-list with FindMRUString() or FindMRUData().
510 * - Iterate through an MRU-list with EnumMRUList().
511 * - Free an MRU-list with FreeMRUList().
512 */
513
514 typedef struct tagCREATEMRULISTA
515 {
516 DWORD cbSize;
517 DWORD nMaxItems;
518 DWORD dwFlags;
519 HKEY hKey;
520 LPCSTR lpszSubKey;
521 PROC lpfnCompare;
522 } CREATEMRULISTA, *LPCREATEMRULISTA;
523
524 typedef struct tagCREATEMRULISTW
525 {
526 DWORD cbSize;
527 DWORD nMaxItems;
528 DWORD dwFlags;
529 HKEY hKey;
530 LPCWSTR lpszSubKey;
531 PROC lpfnCompare;
532 } CREATEMRULISTW, *LPCREATEMRULISTW;
533
534 /* dwFlags */
535 #define MRUF_STRING_LIST 0 /* list will contain strings */
536 #define MRUF_BINARY_LIST 1 /* list will contain binary data */
537 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
538
539 /* If list is a string list lpfnCompare has the following prototype
540 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
541 * for binary lists the prototype is
542 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
543 * where cbData is the no. of bytes to compare.
544 * Need to check what return value means identical - 0?
545 */
546
547 typedef struct tagWINEMRUITEM
548 {
549 DWORD size; /* size of data stored */
550 DWORD itemFlag; /* flags */
551 BYTE datastart;
552 } WINEMRUITEM, *LPWINEMRUITEM;
553
554 /* itemFlag */
555 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
556
557 typedef struct tagWINEMRULIST
558 {
559 CREATEMRULISTW extview; /* original create information */
560 BOOL isUnicode; /* is compare fn Unicode */
561 DWORD wineFlags; /* internal flags */
562 DWORD cursize; /* current size of realMRU */
563 LPWSTR realMRU; /* pointer to string of index names */
564 LPWINEMRUITEM *array; /* array of pointers to data */
565 /* in 'a' to 'z' order */
566 } WINEMRULIST, *LPWINEMRULIST;
567
568 /* wineFlags */
569 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
570
571 /**************************************************************************
572 * MRU_SaveChanged (internal)
573 *
574 * Local MRU saving code
575 */
576 static void MRU_SaveChanged ( LPWINEMRULIST mp )
577 {
578 UINT i, err;
579 HKEY newkey;
580 WCHAR realname[2];
581 LPWINEMRUITEM witem;
582 static const WCHAR emptyW[] = {'\0'};
583
584 /* or should we do the following instead of RegOpenKeyEx:
585 */
586
587 /* open the sub key */
588 if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
589 0, KEY_WRITE, &newkey))) {
590 /* not present - what to do ??? */
591 ERR("Could not open key, error=%d, attempting to create\n",
592 err);
593 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
594 0,
595 emptyW,
596 REG_OPTION_NON_VOLATILE,
597 KEY_READ | KEY_WRITE,
598 0,
599 &newkey,
600 0))) {
601 ERR("failed to create key /%s/, err=%d\n",
602 debugstr_w(mp->extview.lpszSubKey), err);
603 return;
604 }
605 }
606 if (mp->wineFlags & WMRUF_CHANGED) {
607 mp->wineFlags &= ~WMRUF_CHANGED;
608 err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU,
609 (strlenW(mp->realMRU) + 1)*sizeof(WCHAR));
610 if (err) {
611 ERR("error saving MRUList, err=%d\n", err);
612 }
613 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
614 }
615 realname[1] = 0;
616 for(i=0; i<mp->cursize; i++) {
617 witem = mp->array[i];
618 if (witem->itemFlag & WMRUIF_CHANGED) {
619 witem->itemFlag &= ~WMRUIF_CHANGED;
620 realname[0] = 'a' + i;
621 err = RegSetValueExW(newkey, realname, 0,
622 (mp->extview.dwFlags & MRUF_BINARY_LIST) ?
623 REG_BINARY : REG_SZ,
624 &witem->datastart, witem->size);
625 if (err) {
626 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
627 }
628 TRACE("saving value for name /%s/ size=%ld\n",
629 debugstr_w(realname), witem->size);
630 }
631 }
632 RegCloseKey( newkey );
633 }
634
635 /**************************************************************************
636 * FreeMRUList [COMCTL32.152]
637 *
638 * Frees a most-recently-used items list.
639 *
640 * PARAMS
641 * hMRUList [I] Handle to list.
642 *
643 * RETURNS
644 * Nothing.
645 */
646 void WINAPI FreeMRUList (HANDLE hMRUList)
647 {
648 LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList;
649 UINT i;
650
651 TRACE("(%p)\n", hMRUList);
652 if (!hMRUList)
653 return;
654
655 if (mp->wineFlags & WMRUF_CHANGED) {
656 /* need to open key and then save the info */
657 MRU_SaveChanged( mp );
658 }
659
660 for(i=0; i<mp->extview.nMaxItems; i++) {
661 if (mp->array[i])
662 Free(mp->array[i]);
663 }
664 Free(mp->realMRU);
665 Free(mp->array);
666 Free((LPWSTR)mp->extview.lpszSubKey);
667 Free(mp);
668 }
669
670
671 /**************************************************************************
672 * FindMRUData [COMCTL32.169]
673 *
674 * Searches binary list for item that matches lpData of length cbData.
675 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
676 * corresponding to item's reg. name will be stored in it ('a' -> 0).
677 *
678 * PARAMS
679 * hList [I] list handle
680 * lpData [I] data to find
681 * cbData [I] length of data
682 * lpRegNum [O] position in registry (maybe NULL)
683 *
684 * RETURNS
685 * Position in list 0 -> MRU. -1 if item not found.
686 */
687 INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData,
688 LPINT lpRegNum)
689 {
690 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
691 INT ret;
692 UINT i;
693 LPSTR dataA = NULL;
694
695 if (!mp->extview.lpfnCompare) {
696 ERR("MRU list not properly created. No compare procedure.\n");
697 return -1;
698 }
699
700 if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
701 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
702 NULL, 0, NULL, NULL);
703 dataA = Alloc(len);
704 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
705 }
706
707 for(i=0; i<mp->cursize; i++) {
708 if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
709 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
710 cbData))
711 break;
712 }
713 else {
714 if(mp->isUnicode) {
715 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
716 break;
717 } else {
718 DWORD len = WideCharToMultiByte(CP_ACP, 0,
719 (LPWSTR)&mp->array[i]->datastart, -1,
720 NULL, 0, NULL, NULL);
721 LPSTR itemA = Alloc(len);
722 INT cmp;
723 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
724 itemA, len, NULL, NULL);
725
726 cmp = mp->extview.lpfnCompare(dataA, itemA);
727 Free(itemA);
728 if(!cmp)
729 break;
730 }
731 }
732 }
733 if(dataA)
734 Free(dataA);
735 if (i < mp->cursize)
736 ret = i;
737 else
738 ret = -1;
739 if (lpRegNum && (ret != -1))
740 *lpRegNum = 'a' + i;
741
742 TRACE("(%p, %p, %ld, %p) returning %d\n",
743 hList, lpData, cbData, lpRegNum, ret);
744
745 return ret;
746 }
747
748
749 /**************************************************************************
750 * AddMRUData [COMCTL32.167]
751 *
752 * Add item to MRU binary list. If item already exists in list then it is
753 * simply moved up to the top of the list and not added again. If list is
754 * full then the least recently used item is removed to make room.
755 *
756 * PARAMS
757 * hList [I] Handle to list.
758 * lpData [I] ptr to data to add.
759 * cbData [I] no. of bytes of data.
760 *
761 * RETURNS
762 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
763 * -1 on error.
764 */
765 INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
766 {
767 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
768 LPWINEMRUITEM witem;
769 INT i, replace;
770
771 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) {
772 /* Item exists, just move it to the front */
773 LPWSTR pos = strchrW(mp->realMRU, replace + 'a');
774 while (pos > mp->realMRU)
775 {
776 pos[0] = pos[-1];
777 pos--;
778 }
779 }
780 else {
781 /* either add a new entry or replace oldest */
782 if (mp->cursize < mp->extview.nMaxItems) {
783 /* Add in a new item */
784 replace = mp->cursize;
785 mp->cursize++;
786 }
787 else {
788 /* get the oldest entry and replace data */
789 replace = mp->realMRU[mp->cursize - 1] - 'a';
790 Free(mp->array[replace]);
791 }
792
793 /* Allocate space for new item and move in the data */
794 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
795 witem->itemFlag |= WMRUIF_CHANGED;
796 witem->size = cbData;
797 memcpy( &witem->datastart, lpData, cbData);
798
799 /* now rotate MRU list */
800 for(i=mp->cursize-1; i>=1; i--)
801 mp->realMRU[i] = mp->realMRU[i-1];
802 }
803
804 /* The new item gets the front spot */
805 mp->wineFlags |= WMRUF_CHANGED;
806 mp->realMRU[0] = replace + 'a';
807
808 TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n",
809 hList, lpData, cbData, replace+'a');
810
811 if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
812 /* save changed stuff right now */
813 MRU_SaveChanged( mp );
814 }
815
816 return replace;
817 }
818
819 /**************************************************************************
820 * AddMRUStringW [COMCTL32.401]
821 *
822 * Add an item to an MRU string list.
823 *
824 * PARAMS
825 * hList [I] Handle to list.
826 * lpszString [I] The string to add.
827 *
828 * RETURNS
829 * Success: The number corresponding to the registry name where the string
830 * has been stored (0 maps to 'a', 1 to 'b' and so on).
831 * Failure: -1, if hList is NULL or memory allocation fails. If lpszString
832 * is invalid, the function returns 0, and GetLastError() returns
833 * ERROR_INVALID_PARAMETER. The last error value is set only in
834 * this case.
835 *
836 * NOTES
837 * -If lpszString exists in the list already, it is moved to the top of the
838 * MRU list (it is not duplicated).
839 * -If the list is full the least recently used list entry is replaced with
840 * lpszString.
841 * -If this function returns 0 you should check the last error value to
842 * ensure the call really succeeded.
843 */
844 INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
845 {
846 TRACE("(%p,%s)\n", hList, debugstr_w(lpszString));
847
848 if (!hList)
849 return -1;
850
851 if (!lpszString || IsBadStringPtrW(lpszString, -1))
852 {
853 SetLastError(ERROR_INVALID_PARAMETER);
854 return 0;
855 }
856
857 return AddMRUData(hList, lpszString,
858 (strlenW(lpszString) + 1) * sizeof(WCHAR));
859 }
860
861 /**************************************************************************
862 * AddMRUStringA [COMCTL32.153]
863 *
864 * See AddMRUStringW.
865 */
866 INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString)
867 {
868 DWORD len;
869 LPWSTR stringW;
870 INT ret;
871
872 TRACE("(%p,%s)\n", hList, debugstr_a(lpszString));
873
874 if (!hList)
875 return -1;
876
877 if (IsBadStringPtrA(lpszString, -1))
878 {
879 SetLastError(ERROR_INVALID_PARAMETER);
880 return 0;
881 }
882
883 len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR);
884 stringW = Alloc(len);
885 if (!stringW)
886 return -1;
887
888 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
889 ret = AddMRUData(hList, stringW, len);
890 Free(stringW);
891 return ret;
892 }
893
894 /**************************************************************************
895 * DelMRUString [COMCTL32.156]
896 *
897 * Removes item from either string or binary list (despite its name)
898 *
899 * PARAMS
900 * hList [I] list handle
901 * nItemPos [I] item position to remove 0 -> MRU
902 *
903 * RETURNS
904 * TRUE if successful, FALSE if nItemPos is out of range.
905 */
906 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
907 {
908 FIXME("(%p, %d): stub\n", hList, nItemPos);
909 return TRUE;
910 }
911
912 /**************************************************************************
913 * FindMRUStringW [COMCTL32.402]
914 *
915 * See FindMRUStringA.
916 */
917 INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
918 {
919 return FindMRUData(hList, lpszString,
920 (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum);
921 }
922
923 /**************************************************************************
924 * FindMRUStringA [COMCTL32.155]
925 *
926 * Searches string list for item that matches lpszString.
927 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
928 * corresponding to item's reg. name will be stored in it ('a' -> 0).
929 *
930 * PARAMS
931 * hList [I] list handle
932 * lpszString [I] string to find
933 * lpRegNum [O] position in registry (maybe NULL)
934 *
935 * RETURNS
936 * Position in list 0 -> MRU. -1 if item not found.
937 */
938 INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
939 {
940 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
941 LPWSTR stringW = Alloc(len * sizeof(WCHAR));
942 INT ret;
943
944 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
945 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
946 Free(stringW);
947 return ret;
948 }
949
950 /*************************************************************************
951 * CreateMRUListLazy_common (internal)
952 */
953 static HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
954 {
955 UINT i, err;
956 HKEY newkey;
957 DWORD datasize, dwdisp;
958 WCHAR realname[2];
959 LPWINEMRUITEM witem;
960 DWORD type;
961 static const WCHAR emptyW[] = {'\0'};
962
963 /* get space to save indices that will turn into names
964 * but in order of most to least recently used
965 */
966 mp->realMRU = Alloc((mp->extview.nMaxItems + 2) * sizeof(WCHAR));
967
968 /* get space to save pointers to actual data in order of
969 * 'a' to 'z' (0 to n).
970 */
971 mp->array = Alloc(mp->extview.nMaxItems * sizeof(LPVOID));
972
973 /* open the sub key */
974 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
975 0,
976 emptyW,
977 REG_OPTION_NON_VOLATILE,
978 KEY_READ | KEY_WRITE,
979 0,
980 &newkey,
981 &dwdisp))) {
982 /* error - what to do ??? */
983 ERR("(%lu %lu %lx %lx \"%s\" %p): Could not open key, error=%d\n",
984 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
985 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
986 mp->extview.lpfnCompare, err);
987 return 0;
988 }
989
990 /* get values from key 'MRUList' */
991 if (newkey) {
992 datasize = mp->extview.nMaxItems + 1;
993 if((err=RegQueryValueExW( newkey, strMRUList, 0, &type,
994 (LPBYTE)mp->realMRU, &datasize))) {
995 /* not present - set size to 1 (will become 0 later) */
996 datasize = 1;
997 *mp->realMRU = 0;
998 }
999
1000 TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
1001
1002 mp->cursize = datasize - 1;
1003 /* datasize now has number of items in the MRUList */
1004
1005 /* get actual values for each entry */
1006 realname[1] = 0;
1007 for(i=0; i<mp->cursize; i++) {
1008 realname[0] = 'a' + i;
1009 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
1010 /* not present - what to do ??? */
1011 ERR("Key %s not found 1\n", debugstr_w(realname));
1012 }
1013 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
1014 witem->size = datasize;
1015 if(RegQueryValueExW( newkey, realname, 0, &type,
1016 &witem->datastart, &datasize)) {
1017 /* not present - what to do ??? */
1018 ERR("Key %s not found 2\n", debugstr_w(realname));
1019 }
1020 }
1021 RegCloseKey( newkey );
1022 }
1023 else
1024 mp->cursize = 0;
1025
1026 TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n",
1027 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
1028 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
1029 mp->extview.lpfnCompare, mp->cursize);
1030 return (HANDLE)mp;
1031 }
1032
1033 /**************************************************************************
1034 * CreateMRUListLazyW [COMCTL32.404]
1035 *
1036 * See CreateMRUListLazyA.
1037 */
1038 HANDLE WINAPI CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2,
1039 DWORD dwParam3, DWORD dwParam4)
1040 {
1041 LPWINEMRULIST mp;
1042
1043 /* Native does not check for a NULL lpcml */
1044
1045 if (lpcml->cbSize != sizeof(CREATEMRULISTW) || !lpcml->hKey ||
1046 IsBadStringPtrW(lpcml->lpszSubKey, -1))
1047 return NULL;
1048
1049 mp = Alloc(sizeof(WINEMRULIST));
1050 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
1051 mp->extview.lpszSubKey = Alloc((strlenW(lpcml->lpszSubKey) + 1) * sizeof(WCHAR));
1052 strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
1053 mp->isUnicode = TRUE;
1054
1055 return CreateMRUListLazy_common(mp);
1056 }
1057
1058 /**************************************************************************
1059 * CreateMRUListLazyA [COMCTL32.157]
1060 *
1061 * Creates a most-recently-used list.
1062 *
1063 * PARAMS
1064 * lpcml [I] ptr to CREATEMRULIST structure.
1065 * dwParam2 [I] Unknown
1066 * dwParam3 [I] Unknown
1067 * dwParam4 [I] Unknown
1068 *
1069 * RETURNS
1070 * Handle to MRU list.
1071 */
1072 HANDLE WINAPI CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2,
1073 DWORD dwParam3, DWORD dwParam4)
1074 {
1075 LPWINEMRULIST mp;
1076 DWORD len;
1077
1078 /* Native does not check for a NULL lpcml */
1079
1080 if (lpcml->cbSize != sizeof(CREATEMRULISTA) || !lpcml->hKey ||
1081 IsBadStringPtrA(lpcml->lpszSubKey, -1))
1082 return 0;
1083
1084 mp = Alloc(sizeof(WINEMRULIST));
1085 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
1086 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
1087 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
1088 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
1089 (LPWSTR)mp->extview.lpszSubKey, len);
1090 mp->isUnicode = FALSE;
1091 return CreateMRUListLazy_common(mp);
1092 }
1093
1094 /**************************************************************************
1095 * CreateMRUListW [COMCTL32.400]
1096 *
1097 * See CreateMRUListA.
1098 */
1099 HANDLE WINAPI CreateMRUListW (LPCREATEMRULISTW lpcml)
1100 {
1101 return CreateMRUListLazyW(lpcml, 0, 0, 0);
1102 }
1103
1104 /**************************************************************************
1105 * CreateMRUListA [COMCTL32.151]
1106 *
1107 * Creates a most-recently-used list.
1108 *
1109 * PARAMS
1110 * lpcml [I] ptr to CREATEMRULIST structure.
1111 *
1112 * RETURNS
1113 * Handle to MRU list.
1114 */
1115 HANDLE WINAPI CreateMRUListA (LPCREATEMRULISTA lpcml)
1116 {
1117 return CreateMRUListLazyA (lpcml, 0, 0, 0);
1118 }
1119
1120
1121 /**************************************************************************
1122 * EnumMRUListW [COMCTL32.403]
1123 *
1124 * Enumerate item in a most-recenty-used list
1125 *
1126 * PARAMS
1127 * hList [I] list handle
1128 * nItemPos [I] item position to enumerate
1129 * lpBuffer [O] buffer to receive item
1130 * nBufferSize [I] size of buffer
1131 *
1132 * RETURNS
1133 * For binary lists specifies how many bytes were copied to buffer, for
1134 * string lists specifies full length of string. Enumerating past the end
1135 * of list returns -1.
1136 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
1137 * the list.
1138 */
1139 INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1140 DWORD nBufferSize)
1141 {
1142 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1143 LPWINEMRUITEM witem;
1144 INT desired, datasize;
1145
1146 if (nItemPos >= mp->cursize) return -1;
1147 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1148 desired = mp->realMRU[nItemPos];
1149 desired -= 'a';
1150 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1151 witem = mp->array[desired];
1152 datasize = min( witem->size, nBufferSize );
1153 memcpy( lpBuffer, &witem->datastart, datasize);
1154 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1155 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1156 return datasize;
1157 }
1158
1159 /**************************************************************************
1160 * EnumMRUListA [COMCTL32.154]
1161 *
1162 * See EnumMRUListW.
1163 */
1164 INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1165 DWORD nBufferSize)
1166 {
1167 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1168 LPWINEMRUITEM witem;
1169 INT desired, datasize;
1170 DWORD lenA;
1171
1172 if (nItemPos >= mp->cursize) return -1;
1173 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1174 desired = mp->realMRU[nItemPos];
1175 desired -= 'a';
1176 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1177 witem = mp->array[desired];
1178 if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
1179 datasize = min( witem->size, nBufferSize );
1180 memcpy( lpBuffer, &witem->datastart, datasize);
1181 } else {
1182 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1183 NULL, 0, NULL, NULL);
1184 datasize = min( witem->size, nBufferSize );
1185 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1186 lpBuffer, datasize, NULL, NULL);
1187 }
1188 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1189 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1190 return datasize;
1191 }
1192
1193
1194 /**************************************************************************
1195 * Str_GetPtrA [COMCTL32.233]
1196 *
1197 * Copies a string into a destination buffer.
1198 *
1199 * PARAMS
1200 * lpSrc [I] Source string
1201 * lpDest [O] Destination buffer
1202 * nMaxLen [I] Size of buffer in characters
1203 *
1204 * RETURNS
1205 * The number of characters copied.
1206 */
1207 INT WINAPI Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1208 {
1209 INT len;
1210
1211 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1212
1213 if (!lpDest && lpSrc)
1214 return strlen (lpSrc);
1215
1216 if (nMaxLen == 0)
1217 return 0;
1218
1219 if (lpSrc == NULL) {
1220 lpDest[0] = '\0';
1221 return 0;
1222 }
1223
1224 len = strlen (lpSrc);
1225 if (len >= nMaxLen)
1226 len = nMaxLen - 1;
1227
1228 RtlMoveMemory (lpDest, lpSrc, len);
1229 lpDest[len] = '\0';
1230
1231 return len;
1232 }
1233
1234
1235 /**************************************************************************
1236 * Str_SetPtrA [COMCTL32.234]
1237 *
1238 * Makes a copy of a string, allocating memory if necessary.
1239 *
1240 * PARAMS
1241 * lppDest [O] Pointer to destination string
1242 * lpSrc [I] Source string
1243 *
1244 * RETURNS
1245 * Success: TRUE
1246 * Failure: FALSE
1247 *
1248 * NOTES
1249 * Set lpSrc to NULL to free the memory allocated by a previous call
1250 * to this function.
1251 */
1252 BOOL WINAPI Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
1253 {
1254 TRACE("(%p %p)\n", lppDest, lpSrc);
1255
1256 if (lpSrc) {
1257 LPSTR ptr = ReAlloc (*lppDest, strlen (lpSrc) + 1);
1258 if (!ptr)
1259 return FALSE;
1260 strcpy (ptr, lpSrc);
1261 *lppDest = ptr;
1262 }
1263 else {
1264 if (*lppDest) {
1265 Free (*lppDest);
1266 *lppDest = NULL;
1267 }
1268 }
1269
1270 return TRUE;
1271 }
1272
1273
1274 /**************************************************************************
1275 * Str_GetPtrW [COMCTL32.235]
1276 *
1277 * See Str_GetPtrA.
1278 */
1279 INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
1280 {
1281 INT len;
1282
1283 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1284
1285 if (!lpDest && lpSrc)
1286 return strlenW (lpSrc);
1287
1288 if (nMaxLen == 0)
1289 return 0;
1290
1291 if (lpSrc == NULL) {
1292 lpDest[0] = L'\0';
1293 return 0;
1294 }
1295
1296 len = strlenW (lpSrc);
1297 if (len >= nMaxLen)
1298 len = nMaxLen - 1;
1299
1300 RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
1301 lpDest[len] = L'\0';
1302
1303 return len;
1304 }
1305
1306
1307 /**************************************************************************
1308 * Str_SetPtrW [COMCTL32.236]
1309 *
1310 * See Str_SetPtrA.
1311 */
1312 BOOL WINAPI Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
1313 {
1314 TRACE("(%p %p)\n", lppDest, lpSrc);
1315
1316 if (lpSrc) {
1317 INT len = strlenW (lpSrc) + 1;
1318 LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR));
1319 if (!ptr)
1320 return FALSE;
1321 strcpyW (ptr, lpSrc);
1322 *lppDest = ptr;
1323 }
1324 else {
1325 if (*lppDest) {
1326 Free (*lppDest);
1327 *lppDest = NULL;
1328 }
1329 }
1330
1331 return TRUE;
1332 }
1333
1334
1335 /**************************************************************************
1336 * Str_GetPtrWtoA [internal]
1337 *
1338 * Converts a unicode string into a multi byte string
1339 *
1340 * PARAMS
1341 * lpSrc [I] Pointer to the unicode source string
1342 * lpDest [O] Pointer to caller supplied storage for the multi byte string
1343 * nMaxLen [I] Size, in bytes, of the destination buffer
1344 *
1345 * RETURNS
1346 * Length, in bytes, of the converted string.
1347 */
1348
1349 INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1350 {
1351 INT len;
1352
1353 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
1354
1355 if (!lpDest && lpSrc)
1356 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1357
1358 if (nMaxLen == 0)
1359 return 0;
1360
1361 if (lpSrc == NULL) {
1362 lpDest[0] = '\0';
1363 return 0;
1364 }
1365
1366 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1367 if (len >= nMaxLen)
1368 len = nMaxLen - 1;
1369
1370 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
1371 lpDest[len] = '\0';
1372
1373 return len;
1374 }
1375
1376
1377 /**************************************************************************
1378 * Str_SetPtrAtoW [internal]
1379 *
1380 * Converts a multi byte string to a unicode string.
1381 * If the pointer to the destination buffer is NULL a buffer is allocated.
1382 * If the destination buffer is too small to keep the converted multi byte
1383 * string the destination buffer is reallocated. If the source pointer is
1384 * NULL, the destination buffer is freed.
1385 *
1386 * PARAMS
1387 * lppDest [I/O] pointer to a pointer to the destination buffer
1388 * lpSrc [I] pointer to a multi byte string
1389 *
1390 * RETURNS
1391 * TRUE: conversion successful
1392 * FALSE: error
1393 */
1394 BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1395 {
1396 TRACE("(%p %s)\n", lppDest, lpSrc);
1397
1398 if (lpSrc) {
1399 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1400 LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR));
1401
1402 if (!ptr)
1403 return FALSE;
1404 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
1405 *lppDest = ptr;
1406 }
1407 else {
1408 if (*lppDest) {
1409 Free (*lppDest);
1410 *lppDest = NULL;
1411 }
1412 }
1413
1414 return TRUE;
1415 }
1416
1417
1418 /**************************************************************************
1419 * DSA_Create [COMCTL32.320]
1420 *
1421 * Creates a dynamic storage array
1422 *
1423 * PARAMS
1424 * nSize [I] size of the array elements
1425 * nGrow [I] number of elements by which the array grows when it is filled
1426 *
1427 * RETURNS
1428 * Success: pointer to an array control structure. Use this like a handle.
1429 * Failure: NULL
1430 *
1431 * NOTES
1432 * The DSA_ functions can be used to create and manipulate arrays of
1433 * fixed-size memory blocks. These arrays can store any kind of data
1434 * (e.g. strings and icons).
1435 */
1436 HDSA WINAPI DSA_Create (INT nSize, INT nGrow)
1437 {
1438 HDSA hdsa;
1439
1440 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
1441
1442 hdsa = Alloc (sizeof(*hdsa));
1443 if (hdsa)
1444 {
1445 hdsa->nItemCount = 0;
1446 hdsa->pData = NULL;
1447 hdsa->nMaxCount = 0;
1448 hdsa->nItemSize = nSize;
1449 hdsa->nGrow = max(1, nGrow);
1450 }
1451
1452 return hdsa;
1453 }
1454
1455
1456 /**************************************************************************
1457 * DSA_Destroy [COMCTL32.321]
1458 *
1459 * Destroys a dynamic storage array
1460 *
1461 * PARAMS
1462 * hdsa [I] pointer to the array control structure
1463 *
1464 * RETURNS
1465 * Success: TRUE
1466 * Failure: FALSE
1467 */
1468 BOOL WINAPI DSA_Destroy (const HDSA hdsa)
1469 {
1470 TRACE("(%p)\n", hdsa);
1471
1472 if (!hdsa)
1473 return FALSE;
1474
1475 if (hdsa->pData && (!Free (hdsa->pData)))
1476 return FALSE;
1477
1478 return Free (hdsa);
1479 }
1480
1481
1482 /**************************************************************************
1483 * DSA_GetItem [COMCTL32.322]
1484 *
1485 * Copies the specified item into a caller-supplied buffer.
1486 *
1487 * PARAMS
1488 * hdsa [I] pointer to the array control structure
1489 * nIndex [I] number of the Item to get
1490 * pDest [O] destination buffer. Has to be >= dwElementSize.
1491 *
1492 * RETURNS
1493 * Success: TRUE
1494 * Failure: FALSE
1495 */
1496 BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
1497 {
1498 LPVOID pSrc;
1499
1500 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
1501
1502 if (!hdsa)
1503 return FALSE;
1504 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1505 return FALSE;
1506
1507 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1508 memmove (pDest, pSrc, hdsa->nItemSize);
1509
1510 return TRUE;
1511 }
1512
1513
1514 /**************************************************************************
1515 * DSA_GetItemPtr [COMCTL32.323]
1516 *
1517 * Retrieves a pointer to the specified item.
1518 *
1519 * PARAMS
1520 * hdsa [I] pointer to the array control structure
1521 * nIndex [I] index of the desired item
1522 *
1523 * RETURNS
1524 * Success: pointer to an item
1525 * Failure: NULL
1526 */
1527 LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1528 {
1529 LPVOID pSrc;
1530
1531 TRACE("(%p %d)\n", hdsa, nIndex);
1532
1533 if (!hdsa)
1534 return NULL;
1535 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1536 return NULL;
1537
1538 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1539
1540 TRACE("-- ret=%p\n", pSrc);
1541
1542 return pSrc;
1543 }
1544
1545
1546 /**************************************************************************
1547 * DSA_SetItem [COMCTL32.325]
1548 *
1549 * Sets the contents of an item in the array.
1550 *
1551 * PARAMS
1552 * hdsa [I] pointer to the array control structure
1553 * nIndex [I] index for the item
1554 * pSrc [I] pointer to the new item data
1555 *
1556 * RETURNS
1557 * Success: TRUE
1558 * Failure: FALSE
1559 */
1560 BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1561 {
1562 INT nSize, nNewItems;
1563 LPVOID pDest, lpTemp;
1564
1565 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1566
1567 if ((!hdsa) || nIndex < 0)
1568 return FALSE;
1569
1570 if (hdsa->nItemCount <= nIndex) {
1571 /* within the old array */
1572 if (hdsa->nMaxCount > nIndex) {
1573 /* within the allocated space, set a new boundary */
1574 hdsa->nItemCount = nIndex + 1;
1575 }
1576 else {
1577 /* resize the block of memory */
1578 nNewItems =
1579 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1580 nSize = hdsa->nItemSize * nNewItems;
1581
1582 lpTemp = ReAlloc (hdsa->pData, nSize);
1583 if (!lpTemp)
1584 return FALSE;
1585
1586 hdsa->nMaxCount = nNewItems;
1587 hdsa->nItemCount = nIndex + 1;
1588 hdsa->pData = lpTemp;
1589 }
1590 }
1591
1592 /* put the new entry in */
1593 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1594 TRACE("-- move dest=%p src=%p size=%d\n",
1595 pDest, pSrc, hdsa->nItemSize);
1596 memmove (pDest, pSrc, hdsa->nItemSize);
1597
1598 return TRUE;
1599 }
1600
1601
1602 /**************************************************************************
1603 * DSA_InsertItem [COMCTL32.324]
1604 *
1605 * Inserts an item into the array at the specified index.
1606 *
1607 * PARAMS
1608 * hdsa [I] pointer to the array control structure
1609 * nIndex [I] index for the new item
1610 * pSrc [I] pointer to the element
1611 *
1612 * RETURNS
1613 * Success: position of the new item
1614 * Failure: -1
1615 */
1616 INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1617 {
1618 INT nNewItems, nSize;
1619 LPVOID lpTemp, lpDest;
1620
1621 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1622
1623 if ((!hdsa) || nIndex < 0)
1624 return -1;
1625
1626 /* when nIndex >= nItemCount then append */
1627 if (nIndex >= hdsa->nItemCount)
1628 nIndex = hdsa->nItemCount;
1629
1630 /* do we need to resize ? */
1631 if (hdsa->nItemCount >= hdsa->nMaxCount) {
1632 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1633 nSize = hdsa->nItemSize * nNewItems;
1634
1635 lpTemp = ReAlloc (hdsa->pData, nSize);
1636 if (!lpTemp)
1637 return -1;
1638
1639 hdsa->nMaxCount = nNewItems;
1640 hdsa->pData = lpTemp;
1641 }
1642
1643 /* do we need to move elements ? */
1644 if (nIndex < hdsa->nItemCount) {
1645 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1646 lpDest = (char *) lpTemp + hdsa->nItemSize;
1647 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1648 TRACE("-- move dest=%p src=%p size=%d\n",
1649 lpDest, lpTemp, nSize);
1650 memmove (lpDest, lpTemp, nSize);
1651 }
1652
1653 /* ok, we can put the new Item in */
1654 hdsa->nItemCount++;
1655 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1656 TRACE("-- move dest=%p src=%p size=%d\n",
1657 lpDest, pSrc, hdsa->nItemSize);
1658 memmove (lpDest, pSrc, hdsa->nItemSize);
1659
1660 return nIndex;
1661 }
1662
1663
1664 /**************************************************************************
1665 * DSA_DeleteItem [COMCTL32.326]
1666 *
1667 * Deletes the specified item from the array.
1668 *
1669 * PARAMS
1670 * hdsa [I] pointer to the array control structure
1671 * nIndex [I] index for the element to delete
1672 *
1673 * RETURNS
1674 * Success: number of the deleted element
1675 * Failure: -1
1676 */
1677 INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1678 {
1679 LPVOID lpDest,lpSrc;
1680 INT nSize;
1681
1682 TRACE("(%p %d)\n", hdsa, nIndex);
1683
1684 if (!hdsa)
1685 return -1;
1686 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1687 return -1;
1688
1689 /* do we need to move ? */
1690 if (nIndex < hdsa->nItemCount - 1) {
1691 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1692 lpSrc = (char *) lpDest + hdsa->nItemSize;
1693 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1694 TRACE("-- move dest=%p src=%p size=%d\n",
1695 lpDest, lpSrc, nSize);
1696 memmove (lpDest, lpSrc, nSize);
1697 }
1698
1699 hdsa->nItemCount--;
1700
1701 /* free memory ? */
1702 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1703 nSize = hdsa->nItemSize * hdsa->nItemCount;
1704
1705 lpDest = ReAlloc (hdsa->pData, nSize);
1706 if (!lpDest)
1707 return -1;
1708
1709 hdsa->nMaxCount = hdsa->nItemCount;
1710 hdsa->pData = lpDest;
1711 }
1712
1713 return nIndex;
1714 }
1715
1716
1717 /**************************************************************************
1718 * DSA_DeleteAllItems [COMCTL32.327]
1719 *
1720 * Removes all items and reinitializes the array.
1721 *
1722 * PARAMS
1723 * hdsa [I] pointer to the array control structure
1724 *
1725 * RETURNS
1726 * Success: TRUE
1727 * Failure: FALSE
1728 */
1729 BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa)
1730 {
1731 TRACE("(%p)\n", hdsa);
1732
1733 if (!hdsa)
1734 return FALSE;
1735 if (hdsa->pData && (!Free (hdsa->pData)))
1736 return FALSE;
1737
1738 hdsa->nItemCount = 0;
1739 hdsa->pData = NULL;
1740 hdsa->nMaxCount = 0;
1741
1742 return TRUE;
1743 }
1744
1745
1746 /**************************************************************************
1747 * DPA_Destroy [COMCTL32.329]
1748 *
1749 * Destroys a dynamic pointer array
1750 *
1751 * PARAMS
1752 * hdpa [I] handle (pointer) to the pointer array
1753 *
1754 * RETURNS
1755 * Success: TRUE
1756 * Failure: FALSE
1757 */
1758 BOOL WINAPI DPA_Destroy (const HDPA hdpa)
1759 {
1760 TRACE("(%p)\n", hdpa);
1761
1762 if (!hdpa)
1763 return FALSE;
1764
1765 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1766 return FALSE;
1767
1768 return HeapFree (hdpa->hHeap, 0, hdpa);
1769 }
1770
1771
1772 /**************************************************************************
1773 * DPA_Grow [COMCTL32.330]
1774 *
1775 * Sets the growth amount.
1776 *
1777 * PARAMS
1778 * hdpa [I] handle (pointer) to the existing (source) pointer array
1779 * nGrow [I] number of items by which the array grows when it's too small
1780 *
1781 * RETURNS
1782 * Success: TRUE
1783 * Failure: FALSE
1784 */
1785 BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow)
1786 {
1787 TRACE("(%p %d)\n", hdpa, nGrow);
1788
1789 if (!hdpa)
1790 return FALSE;
1791
1792 hdpa->nGrow = max(8, nGrow);
1793
1794 return TRUE;
1795 }
1796
1797
1798 /**************************************************************************
1799 * DPA_Clone [COMCTL32.331]
1800 *
1801 * Copies a pointer array to an other one or creates a copy
1802 *
1803 * PARAMS
1804 * hdpa [I] handle (pointer) to the existing (source) pointer array
1805 * hdpaNew [O] handle (pointer) to the destination pointer array
1806 *
1807 * RETURNS
1808 * Success: pointer to the destination pointer array.
1809 * Failure: NULL
1810 *
1811 * NOTES
1812 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1813 * array will be created and it's handle (pointer) is returned.
1814 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1815 * this implementation just returns NULL.
1816 */
1817 HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1818 {
1819 INT nNewItems, nSize;
1820 HDPA hdpaTemp;
1821
1822 if (!hdpa)
1823 return NULL;
1824
1825 TRACE("(%p %p)\n", hdpa, hdpaNew);
1826
1827 if (!hdpaNew) {
1828 /* create a new DPA */
1829 hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1830 sizeof(*hdpaTemp));
1831 hdpaTemp->hHeap = hdpa->hHeap;
1832 hdpaTemp->nGrow = hdpa->nGrow;
1833 }
1834 else
1835 hdpaTemp = hdpaNew;
1836
1837 if (hdpaTemp->ptrs) {
1838 /* remove old pointer array */
1839 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1840 hdpaTemp->ptrs = NULL;
1841 hdpaTemp->nItemCount = 0;
1842 hdpaTemp->nMaxCount = 0;
1843 }
1844
1845 /* create a new pointer array */
1846 nNewItems = hdpaTemp->nGrow *
1847 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1848 nSize = nNewItems * sizeof(LPVOID);
1849 hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1850 hdpaTemp->nMaxCount = nNewItems;
1851
1852 /* clone the pointer array */
1853 hdpaTemp->nItemCount = hdpa->nItemCount;
1854 memmove (hdpaTemp->ptrs, hdpa->ptrs,
1855 hdpaTemp->nItemCount * sizeof(LPVOID));
1856
1857 return hdpaTemp;
1858 }
1859
1860
1861 /**************************************************************************
1862 * DPA_GetPtr [COMCTL32.332]
1863 *
1864 * Retrieves a pointer from a dynamic pointer array
1865 *
1866 * PARAMS
1867 * hdpa [I] handle (pointer) to the pointer array
1868 * nIndex [I] array index of the desired pointer
1869 *
1870 * RETURNS
1871 * Success: pointer
1872 * Failure: NULL
1873 */
1874 LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex)
1875 {
1876 TRACE("(%p %d)\n", hdpa, nIndex);
1877
1878 if (!hdpa)
1879 return NULL;
1880 if (!hdpa->ptrs) {
1881 WARN("no pointer array.\n");
1882 return NULL;
1883 }
1884 if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
1885 WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
1886 return NULL;
1887 }
1888
1889 TRACE("-- %p\n", hdpa->ptrs[nIndex]);
1890
1891 return hdpa->ptrs[nIndex];
1892 }
1893
1894
1895 /**************************************************************************
1896 * DPA_GetPtrIndex [COMCTL32.333]
1897 *
1898 * Retrieves the index of the specified pointer
1899 *
1900 * PARAMS
1901 * hdpa [I] handle (pointer) to the pointer array
1902 * p [I] pointer
1903 *
1904 * RETURNS
1905 * Success: index of the specified pointer
1906 * Failure: -1
1907 */
1908 INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1909 {
1910 INT i;
1911
1912 if (!hdpa || !hdpa->ptrs)
1913 return -1;
1914
1915 for (i = 0; i < hdpa->nItemCount; i++) {
1916 if (hdpa->ptrs[i] == p)
1917 return i;
1918 }
1919
1920 return -1;
1921 }
1922
1923
1924 /**************************************************************************
1925 * DPA_InsertPtr [COMCTL32.334]
1926 *
1927 * Inserts a pointer into a dynamic pointer array
1928 *
1929 * PARAMS
1930 * hdpa [I] handle (pointer) to the array
1931 * i [I] array index
1932 * p [I] pointer to insert
1933 *
1934 * RETURNS
1935 * Success: index of the inserted pointer
1936 * Failure: -1
1937 */
1938 INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1939 {
1940 TRACE("(%p %d %p)\n", hdpa, i, p);
1941
1942 if (!hdpa || i < 0) return -1;
1943
1944 if (i >= 0x7fff)
1945 i = hdpa->nItemCount;
1946
1947 if (i >= hdpa->nItemCount)
1948 return DPA_SetPtr(hdpa, i, p) ? i : -1;
1949
1950 /* create empty spot at the end */
1951 if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
1952 memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
1953 hdpa->ptrs[i] = p;
1954 return i;
1955 }
1956
1957 /**************************************************************************
1958 * DPA_SetPtr [COMCTL32.335]
1959 *
1960 * Sets a pointer in the pointer array
1961 *
1962 * PARAMS
1963 * hdpa [I] handle (pointer) to the pointer array
1964 * i [I] index of the pointer that will be set
1965 * p [I] pointer to be set
1966 *
1967 * RETURNS
1968 * Success: TRUE
1969 * Failure: FALSE
1970 */
1971 BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1972 {
1973 LPVOID *lpTemp;
1974
1975 TRACE("(%p %d %p)\n", hdpa, i, p);
1976
1977 if (!hdpa || i < 0 || i > 0x7fff)
1978 return FALSE;
1979
1980 if (hdpa->nItemCount <= i) {
1981 /* within the old array */
1982 if (hdpa->nMaxCount <= i) {
1983 /* resize the block of memory */
1984 INT nNewItems =
1985 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1986 INT nSize = nNewItems * sizeof(LPVOID);
1987
1988 if (hdpa->ptrs)
1989 lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
1990 else
1991 lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
1992
1993 if (!lpTemp)
1994 return FALSE;
1995
1996 hdpa->nMaxCount = nNewItems;
1997 hdpa->ptrs = lpTemp;
1998 }
1999 hdpa->nItemCount = i+1;
2000 }
2001
2002 /* put the new entry in */
2003 hdpa->ptrs[i] = p;
2004
2005 return TRUE;
2006 }
2007
2008
2009 /**************************************************************************
2010 * DPA_DeletePtr [COMCTL32.336]
2011 *
2012 * Removes a pointer from the pointer array.
2013 *
2014 * PARAMS
2015 * hdpa [I] handle (pointer) to the pointer array
2016 * i [I] index of the pointer that will be deleted
2017 *
2018 * RETURNS
2019 * Success: deleted pointer
2020 * Failure: NULL
2021 */
2022 LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i)
2023 {
2024 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
2025 INT nSize;
2026
2027 TRACE("(%p %d)\n", hdpa, i);
2028
2029 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
2030 return NULL;
2031
2032 lpTemp = hdpa->ptrs[i];
2033
2034 /* do we need to move ?*/
2035 if (i < hdpa->nItemCount - 1) {
2036 lpDest = hdpa->ptrs + i;
2037 lpSrc = lpDest + 1;
2038 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
2039 TRACE("-- move dest=%p src=%p size=%x\n",
2040 lpDest, lpSrc, nSize);
2041 memmove (lpDest, lpSrc, nSize);
2042 }
2043
2044 hdpa->nItemCount --;
2045
2046 /* free memory ?*/
2047 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
2048 INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
2049 nSize = nNewItems * sizeof(LPVOID);
2050 lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2051 hdpa->ptrs, nSize);
2052 if (!lpDest)
2053 return NULL;
2054
2055 hdpa->nMaxCount = nNewItems;
2056 hdpa->ptrs = (LPVOID*)lpDest;
2057 }
2058
2059 return lpTemp;
2060 }
2061
2062
2063 /**************************************************************************
2064 * DPA_DeleteAllPtrs [COMCTL32.337]
2065 *
2066 * Removes all pointers and reinitializes the array.
2067 *
2068 * PARAMS
2069 * hdpa [I] handle (pointer) to the pointer array
2070 *
2071 * RETURNS
2072 * Success: TRUE
2073 * Failure: FALSE
2074 */
2075 BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa)
2076 {
2077 TRACE("(%p)\n", hdpa);
2078
2079 if (!hdpa)
2080 return FALSE;
2081
2082 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2083 return FALSE;
2084
2085 hdpa->nItemCount = 0;
2086 hdpa->nMaxCount = hdpa->nGrow * 2;
2087 hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2088 hdpa->nMaxCount * sizeof(LPVOID));
2089
2090 return TRUE;
2091 }
2092
2093
2094 /**************************************************************************
2095 * DPA_QuickSort [Internal]
2096 *
2097 * Ordinary quicksort (used by DPA_Sort).
2098 *
2099 * PARAMS
2100 * lpPtrs [I] pointer to the pointer array
2101 * l [I] index of the "left border" of the partition
2102 * r [I] index of the "right border" of the partition
2103 * pfnCompare [I] pointer to the compare function
2104 * lParam [I] user defined value (3rd parameter in compare function)
2105 *
2106 * RETURNS
2107 * NONE
2108 */
2109 static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2110 PFNDPACOMPARE pfnCompare, LPARAM lParam)
2111 {
2112 INT m;
2113 LPVOID t;
2114
2115 TRACE("l=%i r=%i\n", l, r);
2116
2117 if (l==r) /* one element is always sorted */
2118 return;
2119 if (r<l) /* oops, got it in the wrong order */
2120 {
2121 DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2122 return;
2123 }
2124 m = (l+r)/2; /* divide by two */
2125 DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2126 DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2127
2128 /* join the two sides */
2129 while( (l<=m) && (m<r) )
2130 {
2131 if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2132 {
2133 t = lpPtrs[m+1];
2134 memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
2135 lpPtrs[l] = t;
2136
2137 m++;
2138 }
2139 l++;
2140 }
2141 }
2142
2143
2144 /**************************************************************************
2145 * DPA_Sort [COMCTL32.338]
2146 *
2147 * Sorts a pointer array using a user defined compare function
2148 *
2149 * PARAMS
2150 * hdpa [I] handle (pointer) to the pointer array
2151 * pfnCompare [I] pointer to the compare function
2152 * lParam [I] user defined value (3rd parameter of compare function)
2153 *
2154 * RETURNS
2155 * Success: TRUE
2156 * Failure: FALSE
2157 */
2158 BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2159 {
2160 if (!hdpa || !pfnCompare)
2161 return FALSE;
2162
2163 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2164
2165 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2166 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2167 pfnCompare, lParam);
2168
2169 return TRUE;
2170 }
2171
2172
2173 /**************************************************************************
2174 * DPA_Search [COMCTL32.339]
2175 *
2176 * Searches a pointer array for a specified pointer
2177 *
2178 * PARAMS
2179 * hdpa [I] handle (pointer) to the pointer array
2180 * pFind [I] pointer to search for
2181 * nStart [I] start index
2182 * pfnCompare [I] pointer to the compare function
2183 * lParam [I] user defined value (3rd parameter of compare function)
2184 * uOptions [I] search options
2185 *
2186 * RETURNS
2187 * Success: index of the pointer in the array.
2188 * Failure: -1
2189 *
2190 * NOTES
2191 * Binary search taken from R.Sedgewick "Algorithms in C"!
2192 * Function is NOT tested!
2193 * If something goes wrong, blame HIM not ME! (Eric Kohl)
2194 */
2195 INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2196 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2197 {
2198 if (!hdpa || !pfnCompare || !pFind)
2199 return -1;
2200
2201 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2202 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2203
2204 if (uOptions & DPAS_SORTED) {
2205 /* array is sorted --> use binary search */
2206 INT l, r, x, n;
2207 LPVOID *lpPtr;
2208
2209 TRACE("binary search\n");
2210
2211 l = (nStart == -1) ? 0 : nStart;
2212 r = hdpa->nItemCount - 1;
2213 lpPtr = hdpa->ptrs;
2214 while (r >= l) {
2215 x = (l + r) / 2;
2216 n = (pfnCompare)(pFind, lpPtr[x], lParam);
2217 if (n < 0)
2218 r = x - 1;
2219 else
2220 l = x + 1;
2221 if (n == 0) {
2222 TRACE("-- ret=%d\n", n);
2223 return n;
2224 }
2225 }
2226
2227 if (uOptions & DPAS_INSERTBEFORE) {
2228 if (r == -1) r = 0;
2229 TRACE("-- ret=%d\n", r);
2230 return r;
2231 }
2232
2233 if (uOptions & DPAS_INSERTAFTER) {
2234 TRACE("-- ret=%d\n", l);
2235 return l;
2236 }
2237 }
2238 else {
2239 /* array is not sorted --> use linear search */
2240 LPVOID *lpPtr;
2241 INT nIndex;
2242
2243 TRACE("linear search\n");
2244
2245 nIndex = (nStart == -1)? 0 : nStart;
2246 lpPtr = hdpa->ptrs;
2247 for (; nIndex < hdpa->nItemCount; nIndex++) {
2248 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2249 TRACE("-- ret=%d\n", nIndex);
2250 return nIndex;
2251 }
2252 }
2253 }
2254
2255 TRACE("-- not found: ret=-1\n");
2256 return -1;
2257 }
2258
2259
2260 /**************************************************************************
2261 * DPA_CreateEx [COMCTL32.340]
2262 *
2263 * Creates a dynamic pointer array using the specified size and heap.
2264 *
2265 * PARAMS
2266 * nGrow [I] number of items by which the array grows when it is filled
2267 * hHeap [I] handle to the heap where the array is stored
2268 *
2269 * RETURNS
2270 * Success: handle (pointer) to the pointer array.
2271 * Failure: NULL
2272 *
2273 * NOTES
2274 * The DPA_ functions can be used to create and manipulate arrays of
2275 * pointers.
2276 */
2277 HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)
2278 {
2279 HDPA hdpa;
2280
2281 TRACE("(%d %p)\n", nGrow, hHeap);
2282
2283 if (hHeap)
2284 hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
2285 else
2286 hdpa = Alloc (sizeof(*hdpa));
2287
2288 if (hdpa) {
2289 hdpa->nGrow = max(8, nGrow);
2290 hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
2291 hdpa->nMaxCount = hdpa->nGrow * 2;
2292 hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2293 hdpa->nMaxCount * sizeof(LPVOID));
2294 }
2295
2296 TRACE("-- %p\n", hdpa);
2297
2298 return hdpa;
2299 }
2300
2301
2302 /**************************************************************************
2303 * DPA_Create [COMCTL32.328]
2304 *
2305 * Creates a dynamic pointer array.
2306 *
2307 * PARAMS
2308 * nGrow [I] number of items by which the array grows when it is filled
2309 *
2310 * RETURNS
2311 * Success: handle (pointer) to the pointer array.
2312 * Failure: NULL
2313 *
2314 * NOTES
2315 * The DPA_ functions can be used to create and manipulate arrays of
2316 * pointers.
2317 */
2318 HDPA WINAPI DPA_Create (INT nGrow)
2319 {
2320 return DPA_CreateEx( nGrow, 0 );
2321 }
2322
2323
2324 /**************************************************************************
2325 * Notification functions
2326 */
2327
2328 typedef struct tagNOTIFYDATA
2329 {
2330 HWND hwndFrom;
2331 HWND hwndTo;
2332 DWORD dwParam3;
2333 DWORD dwParam4;
2334 DWORD dwParam5;
2335 DWORD dwParam6;
2336 } NOTIFYDATA, *LPNOTIFYDATA;
2337
2338
2339 /**************************************************************************
2340 * DoNotify [Internal]
2341 */
2342
2343 static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2344 {
2345 NMHDR nmhdr;
2346 LPNMHDR lpNmh = NULL;
2347 UINT idFrom = 0;
2348
2349 TRACE("(%p %p %d %p 0x%08lx)\n",
2350 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2351 lpNotify->dwParam5);
2352
2353 if (!lpNotify->hwndTo)
2354 return 0;
2355
2356 if (lpNotify->hwndFrom == (HWND)-1) {
2357 lpNmh = lpHdr;
2358 idFrom = lpHdr->idFrom;
2359 }
2360 else {
2361 if (lpNotify->hwndFrom)
2362 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2363
2364 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2365
2366 lpNmh->hwndFrom = lpNotify->hwndFrom;
2367 lpNmh->idFrom = idFrom;
2368 lpNmh->code = uCode;
2369 }
2370
2371 return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2372 }
2373
2374
2375 /**************************************************************************
2376 * SendNotify [COMCTL32.341]
2377 *
2378 * Sends a WM_NOTIFY message to the specified window.
2379 *
2380 * PARAMS
2381 * hwndTo [I] Window to receive the message
2382 * hwndFrom [I] Window that the message is from (see notes)
2383 * uCode [I] Notification code
2384 * lpHdr [I] The NMHDR and any additional information to send or NULL
2385 *
2386 * RETURNS
2387 * Success: return value from notification
2388 * Failure: 0
2389 *
2390 * NOTES
2391 * If hwndFrom is -1 then the identifier of the control sending the
2392 * message is taken from the NMHDR structure.
2393 * If hwndFrom is not -1 then lpHdr can be NULL.
2394 */
2395 LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
2396 {
2397 NOTIFYDATA notify;
2398
2399 TRACE("(%p %p %d %p)\n",
2400 hwndTo, hwndFrom, uCode, lpHdr);
2401
2402 notify.hwndFrom = hwndFrom;
2403 notify.hwndTo = hwndTo;
2404 notify.dwParam5 = 0;
2405 notify.dwParam6 = 0;
2406
2407 return DoNotify (&notify, uCode, lpHdr);
2408 }
2409
2410
2411 /**************************************************************************
2412 * SendNotifyEx [COMCTL32.342]
2413 *
2414 * Sends a WM_NOTIFY message to the specified window.
2415 *
2416 * PARAMS
2417 * hwndFrom [I] Window to receive the message
2418 * hwndTo [I] Window that the message is from
2419 * uCode [I] Notification code
2420 * lpHdr [I] The NMHDR and any additional information to send or NULL
2421 * dwParam5 [I] Unknown
2422 *
2423 * RETURNS
2424 * Success: return value from notification
2425 * Failure: 0
2426 *
2427 * NOTES
2428 * If hwndFrom is -1 then the identifier of the control sending the
2429 * message is taken from the NMHDR structure.
2430 * If hwndFrom is not -1 then lpHdr can be NULL.
2431 */
2432 LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2433 LPNMHDR lpHdr, DWORD dwParam5)
2434 {
2435 NOTIFYDATA notify;
2436 HWND hwndNotify;
2437
2438 TRACE("(%p %p %d %p 0x%08lx)\n",
2439 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2440
2441 hwndNotify = hwndTo;
2442 if (!hwndTo) {
2443 if (IsWindow (hwndFrom)) {
2444 hwndNotify = GetParent (hwndFrom);
2445 if (!hwndNotify)
2446 return 0;
2447 }
2448 }
2449
2450 notify.hwndFrom = hwndFrom;
2451 notify.hwndTo = hwndNotify;
2452 notify.dwParam5 = dwParam5;
2453 notify.dwParam6 = 0;
2454
2455 return DoNotify (&notify, uCode, lpHdr);
2456 }
2457
2458
2459
2460
2461 /**************************************************************************
2462 * DPA_EnumCallback [COMCTL32.385]
2463 *
2464 * Enumerates all items in a dynamic pointer array.
2465 *
2466 * PARAMS
2467 * hdpa [I] handle to the dynamic pointer array
2468 * enumProc [I]
2469 * lParam [I]
2470 *
2471 * RETURNS
2472 * none
2473 */
2474 VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
2475 LPVOID lParam)
2476 {
2477 INT i;
2478
2479 TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
2480
2481 if (!hdpa)
2482 return;
2483 if (hdpa->nItemCount <= 0)
2484 return;
2485
2486 for (i = 0; i < hdpa->nItemCount; i++) {
2487 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2488 return;
2489 }
2490
2491 return;
2492 }
2493
2494
2495 /**************************************************************************
2496 * DPA_DestroyCallback [COMCTL32.386]
2497 *
2498 * Enumerates all items in a dynamic pointer array and destroys it.
2499 *
2500 * PARAMS
2501 * hdpa [I] handle to the dynamic pointer array
2502 * enumProc [I]
2503 * lParam [I]
2504 *
2505 * RETURNS
2506 * none
2507 */
2508 void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
2509 LPVOID lParam)
2510 {
2511 TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
2512
2513 DPA_EnumCallback (hdpa, enumProc, lParam);
2514 DPA_Destroy (hdpa);
2515 }
2516
2517
2518 /**************************************************************************
2519 * DSA_EnumCallback [COMCTL32.387]
2520 *
2521 * Enumerates all items in a dynamic storage array.
2522 *
2523 * PARAMS
2524 * hdsa [I] handle to the dynamic storage array
2525 * enumProc [I]
2526 * lParam [I]
2527 *
2528 * RETURNS
2529 * none
2530 */
2531 VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
2532 LPVOID lParam)
2533 {
2534 INT i;
2535
2536 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
2537
2538 if (!hdsa)
2539 return;
2540 if (hdsa->nItemCount <= 0)
2541 return;
2542
2543 for (i = 0; i < hdsa->nItemCount; i++) {
2544 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2545 if ((enumProc)(lpItem, lParam) == 0)
2546 return;
2547 }
2548
2549 return;
2550 }
2551
2552
2553 /**************************************************************************
2554 * DSA_DestroyCallback [COMCTL32.388]
2555 *
2556 * Enumerates all items in a dynamic storage array and destroys it.
2557 *
2558 * PARAMS
2559 * hdsa [I] handle to the dynamic storage array
2560 * enumProc [I]
2561 * lParam [I]
2562 *
2563 * RETURNS
2564 * none
2565 */
2566 void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
2567 LPVOID lParam)
2568 {
2569 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
2570
2571 DSA_EnumCallback (hdsa, enumProc, lParam);
2572 DSA_Destroy (hdsa);
2573 }