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