Added location of local application data.
[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;
1474     LPVOID  lpTemp, lpDest;
1475     
1476     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1477
1478     if ((!hdsa) || nIndex < 0)
1479         return -1;
1480
1481     /* when nIndex >= nItemCount then append */
1482     if (nIndex >= hdsa->nItemCount)
1483         nIndex = hdsa->nItemCount;
1484
1485     /* do we need to resize ? */
1486     if (hdsa->nItemCount >= hdsa->nMaxCount) {
1487         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1488         nSize = hdsa->nItemSize * nNewItems;
1489
1490         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1491         if (!lpTemp)
1492             return -1;
1493
1494         hdsa->nMaxCount = nNewItems;
1495         hdsa->pData = lpTemp;         
1496     }
1497
1498     /* do we need to move elements ? */
1499     if (nIndex < hdsa->nItemCount) {
1500         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1501         lpDest = (char *) lpTemp + hdsa->nItemSize;
1502         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1503         TRACE("-- move dest=%p src=%p size=%d\n",
1504                lpDest, lpTemp, nSize);
1505         memmove (lpDest, lpTemp, nSize);
1506     }
1507
1508     /* ok, we can put the new Item in */
1509     hdsa->nItemCount++;
1510     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1511     TRACE("-- move dest=%p src=%p size=%d\n",
1512            lpDest, pSrc, hdsa->nItemSize);
1513     memmove (lpDest, pSrc, hdsa->nItemSize);
1514
1515     return nIndex;
1516 }
1517
1518
1519 /**************************************************************************
1520  * DSA_DeleteItem [COMCTL32.326] 
1521  *
1522  * PARAMS
1523  *     hdsa   [I] pointer to the array control structure
1524  *     nIndex [I] index for the element to delete
1525  *
1526  * RETURNS
1527  *     Success: number of the deleted element
1528  *     Failure: -1
1529  */
1530
1531 INT WINAPI
1532 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1533 {
1534     LPVOID lpDest,lpSrc;
1535     INT  nSize;
1536     
1537     TRACE("(%p %d)\n", hdsa, nIndex);
1538
1539     if (!hdsa)
1540         return -1;
1541     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1542         return -1;
1543
1544     /* do we need to move ? */
1545     if (nIndex < hdsa->nItemCount - 1) {
1546         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1547         lpSrc = (char *) lpDest + hdsa->nItemSize;
1548         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1549         TRACE("-- move dest=%p src=%p size=%d\n",
1550                lpDest, lpSrc, nSize);
1551         memmove (lpDest, lpSrc, nSize);
1552     }
1553     
1554     hdsa->nItemCount--;
1555     
1556     /* free memory ? */
1557     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1558         nSize = hdsa->nItemSize * hdsa->nItemCount;
1559
1560         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1561         if (!lpDest)
1562             return -1;
1563
1564         hdsa->nMaxCount = hdsa->nItemCount;
1565         hdsa->pData = lpDest;
1566     }
1567
1568     return nIndex;
1569 }
1570
1571
1572 /**************************************************************************
1573  * DSA_DeleteAllItems [COMCTL32.327]
1574  *
1575  * Removes all items and reinitializes the array.
1576  *
1577  * PARAMS
1578  *     hdsa [I] pointer to the array control structure
1579  *
1580  * RETURNS
1581  *     Success: TRUE
1582  *     Failure: FALSE
1583  */
1584
1585 BOOL WINAPI
1586 DSA_DeleteAllItems (const HDSA hdsa)
1587 {
1588     TRACE("(%p)\n", hdsa);
1589
1590     if (!hdsa) 
1591         return FALSE;
1592     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1593         return FALSE;
1594
1595     hdsa->nItemCount = 0;
1596     hdsa->pData = NULL;
1597     hdsa->nMaxCount = 0;
1598
1599     return TRUE;
1600 }
1601
1602
1603 /**************************************************************************
1604  * The DPA-API is a set of functions to create and manipulate arrays of
1605  * pointers.
1606  */
1607
1608 /**************************************************************************
1609  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1610  *
1611  * PARAMS
1612  *     nGrow [I] number of items by which the array grows when it is filled
1613  *
1614  * RETURNS
1615  *     Success: handle (pointer) to the pointer array.
1616  *     Failure: NULL
1617  */
1618
1619 HDPA WINAPI
1620 DPA_Create (INT nGrow)
1621 {
1622     HDPA hdpa;
1623
1624     TRACE("(%d)\n", nGrow);
1625
1626     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1627     if (hdpa) {
1628         hdpa->nGrow = max(8, nGrow);
1629         hdpa->hHeap = COMCTL32_hHeap;
1630         hdpa->nMaxCount = hdpa->nGrow * 2;
1631         hdpa->ptrs =
1632             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1633     }
1634
1635     TRACE("-- %p\n", hdpa);
1636
1637     return hdpa;
1638 }
1639
1640
1641 /**************************************************************************
1642  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1643  *
1644  * PARAMS
1645  *     hdpa [I] handle (pointer) to the pointer array
1646  *
1647  * RETURNS
1648  *     Success: TRUE
1649  *     Failure: FALSE
1650  */
1651
1652 BOOL WINAPI
1653 DPA_Destroy (const HDPA hdpa)
1654 {
1655     TRACE("(%p)\n", hdpa);
1656
1657     if (!hdpa)
1658         return FALSE;
1659
1660     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1661         return FALSE;
1662
1663     return HeapFree (hdpa->hHeap, 0, hdpa);
1664 }
1665
1666
1667 /**************************************************************************
1668  * DPA_Grow [COMCTL32.330]
1669  *
1670  * Sets the growth amount.
1671  *
1672  * PARAMS
1673  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1674  *     nGrow [I] number of items by which the array grows when it's too small
1675  *
1676  * RETURNS
1677  *     Success: TRUE
1678  *     Failure: FALSE
1679  */
1680
1681 BOOL WINAPI
1682 DPA_Grow (const HDPA hdpa, INT nGrow)
1683 {
1684     TRACE("(%p %d)\n", hdpa, nGrow);
1685
1686     if (!hdpa)
1687         return FALSE;
1688
1689     hdpa->nGrow = max(8, nGrow);
1690
1691     return TRUE;
1692 }
1693
1694
1695 /**************************************************************************
1696  * DPA_Clone [COMCTL32.331]
1697  *
1698  * Copies a pointer array to an other one or creates a copy
1699  *
1700  * PARAMS
1701  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1702  *     hdpaNew [O] handle (pointer) to the destination pointer array
1703  *
1704  * RETURNS
1705  *     Success: pointer to the destination pointer array.
1706  *     Failure: NULL
1707  *
1708  * NOTES
1709  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1710  *       array will be created and it's handle (pointer) is returned.
1711  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1712  *       this implementation just returns NULL.
1713  */
1714
1715 HDPA WINAPI
1716 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1717 {
1718     INT nNewItems, nSize;
1719     HDPA hdpaTemp;
1720
1721     if (!hdpa)
1722         return NULL;
1723
1724     TRACE("(%p %p)\n", hdpa, hdpaNew);
1725
1726     if (!hdpaNew) {
1727         /* create a new DPA */
1728         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1729                                     sizeof(DPA));
1730         hdpaTemp->hHeap = hdpa->hHeap;
1731         hdpaTemp->nGrow = hdpa->nGrow;
1732     }
1733     else
1734         hdpaTemp = hdpaNew;
1735
1736     if (hdpaTemp->ptrs) {
1737         /* remove old pointer array */
1738         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1739         hdpaTemp->ptrs = NULL;
1740         hdpaTemp->nItemCount = 0;
1741         hdpaTemp->nMaxCount = 0;
1742     }
1743
1744     /* create a new pointer array */
1745     nNewItems = hdpaTemp->nGrow *
1746                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1747     nSize = nNewItems * sizeof(LPVOID);
1748     hdpaTemp->ptrs =
1749         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1750     hdpaTemp->nMaxCount = nNewItems;
1751
1752     /* clone the pointer array */
1753     hdpaTemp->nItemCount = hdpa->nItemCount;
1754     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1755              hdpaTemp->nItemCount * sizeof(LPVOID));
1756
1757     return hdpaTemp;
1758 }
1759
1760
1761 /**************************************************************************
1762  * DPA_GetPtr [COMCTL32.332]
1763  *
1764  * Retrieves a pointer from a dynamic pointer array
1765  *
1766  * PARAMS
1767  *     hdpa   [I] handle (pointer) to the pointer array
1768  *     nIndex [I] array index of the desired pointer
1769  *
1770  * RETURNS
1771  *     Success: pointer
1772  *     Failure: NULL
1773  */
1774
1775 LPVOID WINAPI
1776 DPA_GetPtr (const HDPA hdpa, INT i)
1777 {
1778     TRACE("(%p %d)\n", hdpa, i);
1779
1780     if (!hdpa)
1781         return NULL;
1782     if (!hdpa->ptrs) {
1783         WARN("no pointer array.\n");
1784         return NULL;
1785     }
1786     if ((i < 0) || (i >= hdpa->nItemCount)) {
1787         WARN("not enough pointers in array (%d vs %d).\n",i,hdpa->nItemCount);
1788         return NULL;
1789     }
1790
1791     TRACE("-- %p\n", hdpa->ptrs[i]);
1792
1793     return hdpa->ptrs[i];
1794 }
1795
1796
1797 /**************************************************************************
1798  * DPA_GetPtrIndex [COMCTL32.333]
1799  *
1800  * Retrieves the index of the specified pointer
1801  *
1802  * PARAMS
1803  *     hdpa   [I] handle (pointer) to the pointer array
1804  *     p      [I] pointer
1805  *
1806  * RETURNS
1807  *     Success: index of the specified pointer
1808  *     Failure: -1
1809  */
1810
1811 INT WINAPI
1812 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1813 {
1814     INT i;
1815
1816     if (!hdpa->ptrs)
1817         return -1;
1818
1819     for (i = 0; i < hdpa->nItemCount; i++) {
1820         if (hdpa->ptrs[i] == p)
1821             return i;
1822     }
1823
1824     return -1;
1825 }
1826
1827
1828 /**************************************************************************
1829  * DPA_InsertPtr [COMCTL32.334]
1830  *
1831  * Inserts a pointer into a dynamic pointer array
1832  *
1833  * PARAMS
1834  *     hdpa [I] handle (pointer) to the array
1835  *     i    [I] array index
1836  *     p    [I] pointer to insert
1837  *
1838  * RETURNS
1839  *     Success: index of the inserted pointer
1840  *     Failure: -1
1841  */
1842
1843 INT WINAPI
1844 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1845 {
1846     INT   nNewItems, nSize, nIndex = 0;
1847     LPVOID  *lpTemp, *lpDest;
1848
1849     TRACE("(%p %d %p)\n", hdpa, i, p);
1850
1851     if ((!hdpa) || (i < 0))
1852         return -1;
1853
1854     if (!hdpa->ptrs) {
1855         hdpa->ptrs =
1856             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1857                                 2 * hdpa->nGrow * sizeof(LPVOID));
1858         if (!hdpa->ptrs)
1859             return -1;
1860         hdpa->nMaxCount = hdpa->nGrow * 2;
1861         nIndex = 0;
1862     }
1863     else {
1864         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1865             TRACE("-- resizing\n");
1866             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1867             nSize = nNewItems * sizeof(LPVOID);
1868
1869             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1870                                            hdpa->ptrs, nSize);
1871             if (!lpTemp)
1872                 return -1;
1873             hdpa->nMaxCount = nNewItems;
1874             hdpa->ptrs = lpTemp;
1875         }
1876
1877         if (i >= hdpa->nItemCount) {
1878             nIndex = hdpa->nItemCount;
1879             TRACE("-- appending at %d\n", nIndex);
1880         }
1881         else {
1882             TRACE("-- inserting at %d\n", i);
1883             lpTemp = hdpa->ptrs + i;
1884             lpDest = lpTemp + 1;
1885             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1886             TRACE("-- move dest=%p src=%p size=%x\n",
1887                    lpDest, lpTemp, nSize);
1888             memmove (lpDest, lpTemp, nSize);
1889             nIndex = i;
1890         }
1891     }
1892
1893     /* insert item */
1894     hdpa->nItemCount++;
1895     hdpa->ptrs[nIndex] = p;
1896
1897     return nIndex;
1898 }
1899
1900
1901 /**************************************************************************
1902  * DPA_SetPtr [COMCTL32.335]
1903  *
1904  * Sets a pointer in the pointer array
1905  *
1906  * PARAMS
1907  *     hdpa [I] handle (pointer) to the pointer array
1908  *     i    [I] index of the pointer that will be set
1909  *     p    [I] pointer to be set
1910  *
1911  * RETURNS
1912  *     Success: TRUE
1913  *     Failure: FALSE
1914  */
1915
1916 BOOL WINAPI
1917 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1918 {
1919     LPVOID *lpTemp;
1920     
1921     TRACE("(%p %d %p)\n", hdpa, i, p);
1922
1923     if ((!hdpa) || i < 0)
1924         return FALSE;
1925       
1926     if (hdpa->nItemCount <= i) {
1927         /* within the old array */
1928         if (hdpa->nMaxCount > i) {
1929             /* within the allocated space, set a new boundary */
1930             hdpa->nItemCount = i+1;
1931         }
1932         else {
1933             /* resize the block of memory */
1934             INT nNewItems =
1935                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1936             INT nSize = nNewItems * sizeof(LPVOID);
1937
1938             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1939                                            hdpa->ptrs, nSize);
1940             if (!lpTemp)
1941                 return FALSE;
1942
1943             hdpa->nItemCount = nNewItems;
1944             hdpa->ptrs = lpTemp;        
1945         }    
1946     }
1947
1948     /* put the new entry in */
1949     hdpa->ptrs[i] = p;
1950
1951     return TRUE;
1952 }
1953
1954
1955 /**************************************************************************
1956  * DPA_DeletePtr [COMCTL32.336]
1957  *
1958  * Removes a pointer from the pointer array.
1959  *
1960  * PARAMS
1961  *     hdpa [I] handle (pointer) to the pointer array
1962  *     i    [I] index of the pointer that will be deleted
1963  *
1964  * RETURNS
1965  *     Success: deleted pointer
1966  *     Failure: NULL
1967  */
1968
1969 LPVOID WINAPI
1970 DPA_DeletePtr (const HDPA hdpa, INT i)
1971 {
1972     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1973     INT  nSize;
1974     
1975     TRACE("(%p %d)\n", hdpa, i);
1976
1977     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1978         return NULL;
1979
1980     lpTemp = hdpa->ptrs[i];
1981
1982     /* do we need to move ?*/
1983     if (i < hdpa->nItemCount - 1) {
1984         lpDest = hdpa->ptrs + i;
1985         lpSrc = lpDest + 1;
1986         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1987         TRACE("-- move dest=%p src=%p size=%x\n",
1988                lpDest, lpSrc, nSize);
1989         memmove (lpDest, lpSrc, nSize);
1990     }
1991     
1992     hdpa->nItemCount --;
1993     
1994     /* free memory ?*/
1995     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1996         INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
1997         nSize = nNewItems * sizeof(LPVOID);
1998         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1999                                       hdpa->ptrs, nSize);
2000         if (!lpDest)
2001             return NULL;
2002
2003         hdpa->nMaxCount = nNewItems;
2004         hdpa->ptrs = (LPVOID*)lpDest;         
2005     }
2006
2007     return lpTemp;
2008 }
2009
2010
2011 /**************************************************************************
2012  * DPA_DeleteAllPtrs [COMCTL32.337]
2013  *
2014  * Removes all pointers and reinitializes the array.
2015  *
2016  * PARAMS
2017  *     hdpa [I] handle (pointer) to the pointer array
2018  *
2019  * RETURNS
2020  *     Success: TRUE
2021  *     Failure: FALSE
2022  */
2023
2024 BOOL WINAPI
2025 DPA_DeleteAllPtrs (const HDPA hdpa)
2026 {
2027     TRACE("(%p)\n", hdpa);
2028
2029     if (!hdpa) 
2030         return FALSE;
2031
2032     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2033         return FALSE;
2034
2035     hdpa->nItemCount = 0;
2036     hdpa->nMaxCount = hdpa->nGrow * 2;
2037     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2038                                      hdpa->nMaxCount * sizeof(LPVOID));
2039
2040     return TRUE;
2041 }
2042
2043
2044 /**************************************************************************
2045  * DPA_QuickSort [Internal]
2046  *
2047  * Ordinary quicksort (used by DPA_Sort).
2048  *
2049  * PARAMS
2050  *     lpPtrs     [I] pointer to the pointer array
2051  *     l          [I] index of the "left border" of the partition
2052  *     r          [I] index of the "right border" of the partition
2053  *     pfnCompare [I] pointer to the compare function
2054  *     lParam     [I] user defined value (3rd parameter in compare function)
2055  *
2056  * RETURNS
2057  *     NONE
2058  */
2059
2060 static VOID
2061 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2062                PFNDPACOMPARE pfnCompare, LPARAM lParam)
2063 {
2064     INT m;
2065     LPVOID t;
2066
2067     TRACE("l=%i r=%i\n", l, r);
2068  
2069     if (l==r)    /* one element is always sorted */
2070         return;
2071     if (r<l)     /* oops, got it in the wrong order */
2072         {
2073         DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2074         return;
2075         }
2076     m = (l+r)/2; /* divide by two */
2077     DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2078     DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2079
2080     /* join the two sides */
2081     while( (l<=m) && (m<r) ) 
2082     {
2083         if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2084         {
2085             t = lpPtrs[m+1];
2086             memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof lpPtrs[l]);
2087             lpPtrs[l] = t;
2088
2089             m++;
2090         }
2091         l++;
2092     }
2093 }
2094
2095
2096 /**************************************************************************
2097  * DPA_Sort [COMCTL32.338]
2098  *
2099  * Sorts a pointer array using a user defined compare function
2100  *
2101  * PARAMS
2102  *     hdpa       [I] handle (pointer) to the pointer array
2103  *     pfnCompare [I] pointer to the compare function
2104  *     lParam     [I] user defined value (3rd parameter of compare function)
2105  *
2106  * RETURNS
2107  *     Success: TRUE
2108  *     Failure: FALSE
2109  */
2110
2111 BOOL WINAPI
2112 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2113 {
2114     if (!hdpa || !pfnCompare)
2115         return FALSE;
2116
2117     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2118
2119     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2120         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2121                        pfnCompare, lParam);
2122
2123     return TRUE;
2124 }
2125
2126
2127 /**************************************************************************
2128  * DPA_Search [COMCTL32.339]
2129  *
2130  * Searches a pointer array for a specified pointer
2131  *
2132  * PARAMS
2133  *     hdpa       [I] handle (pointer) to the pointer array
2134  *     pFind      [I] pointer to search for
2135  *     nStart     [I] start index
2136  *     pfnCompare [I] pointer to the compare function
2137  *     lParam     [I] user defined value (3rd parameter of compare function)
2138  *     uOptions   [I] search options
2139  *
2140  * RETURNS
2141  *     Success: index of the pointer in the array.
2142  *     Failure: -1
2143  *
2144  * NOTES
2145  *     Binary search taken from R.Sedgewick "Algorithms in C"!
2146  *     Function is NOT tested!
2147  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
2148  */
2149
2150 INT WINAPI
2151 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2152             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2153 {
2154     if (!hdpa || !pfnCompare || !pFind)
2155         return -1;
2156
2157     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2158            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2159
2160     if (uOptions & DPAS_SORTED) {
2161         /* array is sorted --> use binary search */
2162         INT l, r, x, n;
2163         LPVOID *lpPtr;
2164
2165         TRACE("binary search\n");
2166
2167         l = (nStart == -1) ? 0 : nStart;
2168         r = hdpa->nItemCount - 1;
2169         lpPtr = hdpa->ptrs;
2170         while (r >= l) {
2171             x = (l + r) / 2;
2172             n = (pfnCompare)(pFind, lpPtr[x], lParam);
2173             if (n < 0)
2174                 r = x - 1;
2175             else
2176                 l = x + 1;
2177             if (n == 0) {
2178                 TRACE("-- ret=%d\n", n);
2179                 return n;
2180             }
2181         }
2182
2183         if (uOptions & DPAS_INSERTBEFORE) {
2184             TRACE("-- ret=%d\n", r);
2185             return r;
2186         }
2187
2188         if (uOptions & DPAS_INSERTAFTER) {
2189             TRACE("-- ret=%d\n", l);
2190             return l;
2191         }
2192     }
2193     else {
2194         /* array is not sorted --> use linear search */
2195         LPVOID *lpPtr;
2196         INT  nIndex;
2197
2198         TRACE("linear search\n");
2199         
2200         nIndex = (nStart == -1)? 0 : nStart;
2201         lpPtr = hdpa->ptrs;
2202         for (; nIndex < hdpa->nItemCount; nIndex++) {
2203             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2204                 TRACE("-- ret=%d\n", nIndex);
2205                 return nIndex;
2206             }
2207         }
2208     }
2209
2210     TRACE("-- not found: ret=-1\n");
2211     return -1;
2212 }
2213
2214
2215 /**************************************************************************
2216  * DPA_CreateEx [COMCTL32.340]
2217  *
2218  * Creates a dynamic pointer array using the specified size and heap.
2219  *
2220  * PARAMS
2221  *     nGrow [I] number of items by which the array grows when it is filled
2222  *     hHeap [I] handle to the heap where the array is stored
2223  *
2224  * RETURNS
2225  *     Success: handle (pointer) to the pointer array.
2226  *     Failure: NULL
2227  */
2228
2229 HDPA WINAPI
2230 DPA_CreateEx (INT nGrow, HANDLE hHeap)
2231 {
2232     HDPA hdpa;
2233
2234     TRACE("(%d 0x%x)\n", nGrow, hHeap);
2235
2236     if (hHeap)
2237         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
2238     else
2239         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
2240
2241     if (hdpa) {
2242         hdpa->nGrow = min(8, nGrow);
2243         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
2244         hdpa->nMaxCount = hdpa->nGrow * 2;
2245         hdpa->ptrs =
2246             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
2247                                 hdpa->nMaxCount * sizeof(LPVOID));
2248     }
2249
2250     TRACE("-- %p\n", hdpa);
2251
2252     return hdpa;
2253 }
2254
2255
2256 /**************************************************************************
2257  * Notification functions
2258  */
2259
2260 typedef struct tagNOTIFYDATA
2261 {
2262     HWND hwndFrom;
2263     HWND hwndTo;
2264     DWORD  dwParam3;
2265     DWORD  dwParam4;
2266     DWORD  dwParam5;
2267     DWORD  dwParam6;
2268 } NOTIFYDATA, *LPNOTIFYDATA;
2269
2270
2271 /**************************************************************************
2272  * DoNotify [Internal]
2273  */
2274
2275 static LRESULT
2276 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2277 {
2278     NMHDR nmhdr;
2279     LPNMHDR lpNmh = NULL;
2280     UINT idFrom = 0;
2281
2282     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
2283            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2284            lpNotify->dwParam5);
2285
2286     if (!lpNotify->hwndTo)
2287         return 0;
2288
2289     if (lpNotify->hwndFrom == -1) {
2290         lpNmh = lpHdr;
2291         idFrom = lpHdr->idFrom;
2292     }
2293     else {
2294         if (lpNotify->hwndFrom) {
2295             HWND hwndParent = GetParent (lpNotify->hwndFrom);
2296             if (hwndParent) {
2297                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
2298                 if (hwndParent)
2299                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2300             }
2301         }
2302
2303         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2304
2305         lpNmh->hwndFrom = lpNotify->hwndFrom;
2306         lpNmh->idFrom = idFrom;
2307         lpNmh->code = uCode;
2308     }
2309
2310     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2311 }
2312
2313
2314 /**************************************************************************
2315  * SendNotify [COMCTL32.341]
2316  *
2317  * PARAMS
2318  *     hwndFrom [I]
2319  *     hwndTo   [I]
2320  *     uCode    [I]
2321  *     lpHdr    [I]
2322  *
2323  * RETURNS
2324  *     Success: return value from notification
2325  *     Failure: 0
2326  */
2327
2328 LRESULT WINAPI
2329 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
2330                      UINT uCode, LPNMHDR lpHdr)
2331 {
2332     NOTIFYDATA notify;
2333
2334     TRACE("(0x%04x 0x%04x %d %p)\n",
2335            hwndFrom, hwndTo, uCode, lpHdr);
2336
2337     notify.hwndFrom = hwndFrom;
2338     notify.hwndTo   = hwndTo;
2339     notify.dwParam5 = 0;
2340     notify.dwParam6 = 0;
2341
2342     return DoNotify (&notify, uCode, lpHdr);
2343 }
2344
2345
2346 /**************************************************************************
2347  * SendNotifyEx [COMCTL32.342]
2348  *
2349  * PARAMS
2350  *     hwndFrom [I]
2351  *     hwndTo   [I]
2352  *     uCode    [I]
2353  *     lpHdr    [I]
2354  *     dwParam5 [I]
2355  *
2356  * RETURNS
2357  *     Success: return value from notification
2358  *     Failure: 0
2359  */
2360
2361 LRESULT WINAPI
2362 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2363                        LPNMHDR lpHdr, DWORD dwParam5)
2364 {
2365     NOTIFYDATA notify;
2366     HWND hwndNotify;
2367
2368     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
2369            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2370
2371     hwndNotify = hwndTo;
2372     if (!hwndTo) {
2373         if (IsWindow (hwndFrom)) {
2374             hwndNotify = GetParent (hwndFrom);
2375             if (!hwndNotify)
2376                 return 0;
2377         }
2378     }
2379
2380     notify.hwndFrom = hwndFrom;
2381     notify.hwndTo   = hwndNotify;
2382     notify.dwParam5 = dwParam5;
2383     notify.dwParam6 = 0;
2384
2385     return DoNotify (&notify, uCode, lpHdr);
2386 }
2387
2388
2389 /**************************************************************************
2390  * StrChrA [COMCTL32.350]
2391  *
2392  */
2393
2394 LPSTR WINAPI
2395 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
2396 {
2397     return strchr (lpString, cChar);
2398 }
2399
2400
2401 /**************************************************************************
2402  * StrStrIA [COMCTL32.355]
2403  */
2404
2405 LPSTR WINAPI
2406 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
2407 {
2408     INT len1, len2, i;
2409     CHAR  first;
2410
2411     if (*lpStr2 == 0)
2412         return ((LPSTR)lpStr1);
2413     len1 = 0;
2414     while (lpStr1[len1] != 0) ++len1;
2415     len2 = 0;
2416     while (lpStr2[len2] != 0) ++len2;
2417     if (len2 == 0)
2418         return ((LPSTR)(lpStr1 + len1));
2419     first = tolower (*lpStr2);
2420     while (len1 >= len2) {
2421         if (tolower(*lpStr1) == first) {
2422             for (i = 1; i < len2; ++i)
2423                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
2424                     break;
2425             if (i >= len2)
2426                 return ((LPSTR)lpStr1);
2427         }
2428         ++lpStr1; --len1;
2429     }
2430     return (NULL);
2431 }
2432
2433
2434 /**************************************************************************
2435  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
2436  */
2437
2438 INT WINAPI
2439 COMCTL32_StrToIntA (LPSTR lpString)
2440 {
2441     return atoi(lpString);
2442 }
2443
2444 /**************************************************************************
2445  * StrToIntW [COMCTL32.365] Converts a wide char string to a signed integer.
2446  */
2447
2448 INT WINAPI
2449 COMCTL32_StrToIntW (LPWSTR lpString)
2450 {
2451     return _wtoi(lpString);
2452 }
2453
2454
2455 /**************************************************************************
2456  * DPA_EnumCallback [COMCTL32.385]
2457  *
2458  * Enumerates all items in a dynamic pointer array.
2459  *
2460  * PARAMS
2461  *     hdpa     [I] handle to the dynamic pointer array
2462  *     enumProc [I]
2463  *     lParam   [I] 
2464  *
2465  * RETURNS
2466  *     none
2467  */
2468
2469 VOID WINAPI
2470 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2471 {
2472     INT i;
2473
2474     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2475
2476     if (!hdpa)
2477         return;
2478     if (hdpa->nItemCount <= 0)
2479         return;
2480
2481     for (i = 0; i < hdpa->nItemCount; i++) {
2482         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2483             return;
2484     }
2485
2486     return;
2487 }
2488
2489
2490 /**************************************************************************
2491  * DPA_DestroyCallback [COMCTL32.386]
2492  *
2493  * Enumerates all items in a dynamic pointer array and destroys it.
2494  *
2495  * PARAMS
2496  *     hdpa     [I] handle to the dynamic pointer array
2497  *     enumProc [I]
2498  *     lParam   [I]
2499  *
2500  * RETURNS
2501  *     Success: TRUE
2502  *     Failure: FALSE
2503  */
2504
2505 BOOL WINAPI
2506 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2507 {
2508     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2509
2510     DPA_EnumCallback (hdpa, enumProc, lParam);
2511
2512     return DPA_Destroy (hdpa);
2513 }
2514
2515
2516 /**************************************************************************
2517  * DSA_EnumCallback [COMCTL32.387]
2518  *
2519  * Enumerates all items in a dynamic storage array.
2520  *
2521  * PARAMS
2522  *     hdsa     [I] handle to the dynamic storage array
2523  *     enumProc [I]
2524  *     lParam   [I]
2525  *
2526  * RETURNS
2527  *     none
2528  */
2529
2530 VOID WINAPI
2531 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2532 {
2533     INT i;
2534
2535     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2536
2537     if (!hdsa)
2538         return;
2539     if (hdsa->nItemCount <= 0)
2540         return;
2541
2542     for (i = 0; i < hdsa->nItemCount; i++) {
2543         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2544         if ((enumProc)(lpItem, lParam) == 0)
2545             return;
2546     }
2547
2548     return;
2549 }
2550
2551
2552 /**************************************************************************
2553  * DSA_DestroyCallback [COMCTL32.388]
2554  *
2555  * Enumerates all items in a dynamic storage array and destroys it.
2556  *
2557  * PARAMS
2558  *     hdsa     [I] handle to the dynamic storage array
2559  *     enumProc [I]
2560  *     lParam   [I]
2561  *
2562  * RETURNS
2563  *     Success: TRUE
2564  *     Failure: FALSE
2565  */
2566
2567 BOOL WINAPI
2568 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2569 {
2570     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2571
2572     DSA_EnumCallback (hdsa, enumProc, lParam);
2573
2574     return DSA_Destroy (hdsa);
2575 }
2576
2577 /**************************************************************************
2578  * StrCSpnA [COMCTL32.356]
2579  *
2580  */
2581 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2582   return strcspn(lpStr, lpSet);
2583 }
2584
2585 /**************************************************************************
2586  * StrChrW [COMCTL32.358]
2587  *
2588  */
2589 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2590   return strchrW(lpStart, wMatch);
2591 }
2592
2593 /**************************************************************************
2594  * StrCmpNA [COMCTL32.352]
2595  *
2596  */
2597 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2598   return strncmp(lpStr1, lpStr2, nChar);
2599 }
2600
2601 /**************************************************************************
2602  * StrCmpNIA [COMCTL32.353]
2603  *
2604  */
2605 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2606   return strncasecmp(lpStr1, lpStr2, nChar);
2607 }
2608
2609 /**************************************************************************
2610  * StrCmpNW [COMCTL32.360]
2611  *
2612  */
2613 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2614   return strncmpW(lpStr1, lpStr2, nChar);
2615 }
2616
2617 /**************************************************************************
2618  * StrCmpNIW [COMCTL32.361]
2619  *
2620  */
2621 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2622   FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2623   return 0;
2624 }
2625
2626 /**************************************************************************
2627  * StrRChrA [COMCTL32.351]
2628  *
2629  */
2630 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
2631 {
2632     LPCSTR lpGotIt = NULL;
2633     BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
2634
2635     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2636
2637     if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
2638
2639     for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
2640     {
2641         if (*lpStart != LOBYTE(wMatch)) continue;
2642         if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
2643         lpGotIt = lpStart;
2644     }    
2645     return (LPSTR)lpGotIt;
2646 }
2647
2648
2649 /**************************************************************************
2650  * StrRChrW [COMCTL32.359]
2651  *
2652  */
2653 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
2654 {
2655     LPCWSTR lpGotIt = NULL;
2656
2657     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2658     if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
2659
2660     for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
2661         if (*lpStart == wMatch) lpGotIt = lpStart;
2662
2663     return (LPWSTR)lpGotIt;
2664 }
2665
2666
2667 /**************************************************************************
2668  * StrStrA [COMCTL32.354]
2669  *
2670  */
2671 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2672   return strstr(lpFirst, lpSrch);
2673 }
2674
2675 /**************************************************************************
2676  * StrStrW [COMCTL32.362]
2677  *
2678  */
2679 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2680   return strstrW(lpFirst, lpSrch);
2681 }
2682
2683 /**************************************************************************
2684  * StrSpnW [COMCTL32.364]
2685  *
2686  */
2687 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2688   LPWSTR lpLoop = lpStr;
2689
2690   /* validate ptr */
2691   if ((lpStr == 0) || (lpSet == 0)) return 0;
2692
2693 /* while(*lpLoop) { if lpLoop++; } */
2694
2695   for(; (*lpLoop != 0); lpLoop++)
2696     if( strchrW(lpSet, *(WORD*)lpLoop))
2697       return (INT)(lpLoop-lpStr);
2698   
2699   return (INT)(lpLoop-lpStr);
2700 }
2701
2702 /**************************************************************************
2703  * @ [COMCTL32.410]
2704  *
2705  * FIXME: What's this supposed to do?
2706  *        Parameter 1 is an HWND, you're on your own for the rest.
2707  */
2708
2709 BOOL WINAPI COMCTL32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2710
2711    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2712
2713    return TRUE;
2714 }
2715
2716 /**************************************************************************
2717  * @ [COMCTL32.411]
2718  *
2719  * FIXME: What's this supposed to do?
2720  *        Parameter 1 is an HWND, you're on your own for the rest.
2721  */
2722
2723 BOOL WINAPI COMCTL32_411( HWND hw, DWORD b, DWORD c) {
2724
2725    FIXME("(%x, %lx, %lx): stub!\n", hw, b, c);
2726
2727    return TRUE;
2728 }
2729
2730 /**************************************************************************
2731  * @ [COMCTL32.412]
2732  *
2733  * FIXME: What's this supposed to do?
2734  *        Parameter 1 is an HWND, you're on your own for the rest.
2735  */
2736
2737 BOOL WINAPI COMCTL32_412( HWND hwnd, DWORD b, DWORD c)
2738 {
2739     FIXME("(%x, %lx, %lx): stub!\n", hwnd, b, c);
2740
2741     if (IsWindow (hwnd) == FALSE)
2742         return FALSE;
2743
2744     if (b == 0)
2745         return FALSE;
2746
2747
2748     return TRUE;
2749 }
2750
2751 /**************************************************************************
2752  * @ [COMCTL32.413]
2753  *
2754  * FIXME: What's this supposed to do?
2755  *        Parameter 1 is an HWND, you're on your own for the rest.
2756  */
2757
2758 BOOL WINAPI COMCTL32_413( HWND hw, DWORD b, DWORD c, DWORD d) {
2759
2760    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2761
2762    return TRUE;
2763 }
2764
2765
2766 /**************************************************************************
2767  * @ [COMCTL32.415]
2768  *
2769  * FIXME: What's this supposed to do?
2770  *        Parameter 1 is an HWND, you're on your own for the rest.
2771  */
2772
2773 BOOL WINAPI COMCTL32_415( HWND hwnd, DWORD b, DWORD c, DWORD d, DWORD e)
2774 {
2775
2776    FIXME("(%x, %lx, %lx, %lx, %lx): stub!\n", hwnd, b, c, d, e);
2777
2778    return TRUE;
2779 }
2780
2781 /**************************************************************************
2782  * @ [COMCTL32.419]
2783  *
2784  * FIXME: What's this supposed to do?
2785  */
2786
2787 BOOL WINAPI COMCTL32_419( DWORD a, DWORD b, DWORD c, DWORD d)
2788 {
2789
2790    FIXME("(%lx, %lx, %lx, %lx): stub!\n", a, b, c, d);
2791
2792    return TRUE;
2793 }