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