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