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