Use system metrics values in TOOLBAR_DrawPattern instead of hardcoded
[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     UINT i, ret;
635     LPSTR dataA = NULL;
636
637     if (!mp->extview.lpfnCompare) {
638         ERR("MRU list not properly created. No compare procedure.\n");
639         return -1;
640     }
641
642     if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
643         DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
644                                         NULL, 0, NULL, NULL);
645         dataA = Alloc(len);
646         WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
647     }
648
649     for(i=0; i<mp->cursize; i++) {
650         if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
651             if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
652                                          cbData))
653                 break;
654         }
655         else {
656             if(mp->isUnicode) {
657                 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
658                     break;
659             } else {
660                 DWORD len = WideCharToMultiByte(CP_ACP, 0,
661                                                 (LPWSTR)&mp->array[i]->datastart, -1,
662                                                 NULL, 0, NULL, NULL);
663                 LPSTR itemA = Alloc(len);
664                 INT cmp;
665                 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
666                                     itemA, len, NULL, NULL);
667
668                 cmp = mp->extview.lpfnCompare(dataA, itemA);
669                 Free(itemA);
670                 if(!cmp)
671                     break;
672             }
673         }
674     }
675     if(dataA)
676         Free(dataA);
677     if (i < mp->cursize)
678         ret = i;
679     else
680         ret = -1;
681     if (lpRegNum && (ret != -1))
682         *lpRegNum = 'a' + i;
683
684     TRACE("(%p, %p, %ld, %p) returning %d\n",
685            hList, lpData, cbData, lpRegNum, ret);
686
687     return ret;
688 }
689
690
691 /**************************************************************************
692  *              AddMRUData [COMCTL32.167]
693  *
694  * Add item to MRU binary list.  If item already exists in list then it is
695  * simply moved up to the top of the list and not added again.  If list is
696  * full then the least recently used item is removed to make room.
697  *
698  * PARAMS
699  *     hList [I] Handle to list.
700  *     lpData [I] ptr to data to add.
701  *     cbData [I] no. of bytes of data.
702  *
703  * RETURNS
704  *     No. corresponding to registry name where value is stored 'a' -> 0 etc.
705  *     -1 on error.
706  */
707 INT WINAPI
708 AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
709 {
710     LPWINEMRULIST mp = (LPWINEMRULIST)hList;
711     LPWINEMRUITEM witem;
712     INT i, replace, ret;
713
714     if ((replace = FindMRUData (hList, lpData, cbData, NULL)) < 0) {
715         /* either add a new entry or replace oldest */
716         if (mp->cursize < mp->extview.nMaxItems) {
717             /* Add in a new item */
718             replace = mp->cursize;
719             mp->cursize++;
720         }
721         else {
722             /* get the oldest entry and replace data */
723             replace = mp->realMRU[mp->cursize - 1] - 'a';
724             Free(mp->array[replace]);
725         }
726     }
727     else {
728         /* free up the old data */
729         Free(mp->array[replace]);
730     }
731
732     /* Allocate space for new item and move in the data */
733     mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
734     witem->itemFlag |= WMRUIF_CHANGED;
735     witem->size = cbData;
736     memcpy( &witem->datastart, lpData, cbData);
737
738     /* now rotate MRU list */
739     mp->wineFlags |= WMRUF_CHANGED;
740     for(i=mp->cursize-1; i>=1; i--) {
741         mp->realMRU[i] = mp->realMRU[i-1];
742     }
743     mp->realMRU[0] = replace + 'a';
744     TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n",
745           hList, lpData, cbData, replace+'a');
746     ret = replace;
747
748     if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
749         /* save changed stuff right now */
750         MRU_SaveChanged( mp );
751     }
752
753     return ret;
754 }
755
756 /**************************************************************************
757  *              AddMRUStringW [COMCTL32.401]
758  *
759  * Add item to MRU string list.  If item already exists in list them it is
760  * simply moved up to the top of the list and not added again.  If list is
761  * full then the least recently used item is removed to make room.
762  *
763  * PARAMS
764  *     hList [I] Handle to list.
765  *     lpszString [I] ptr to string to add.
766  *
767  * RETURNS
768  *     No. corresponding to registry name where value is stored 'a' -> 0 etc.
769  *     -1 on error.
770  */
771 INT WINAPI
772 AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
773 {
774     FIXME("(%p, %s) empty stub!\n", hList, debugstr_w(lpszString));
775
776     return 0;
777 }
778
779 /**************************************************************************
780  *              AddMRUStringA [COMCTL32.153]
781  *
782  * See AddMRUStringW.
783  */
784 INT WINAPI
785 AddMRUStringA(HANDLE hList, LPCSTR lpszString)
786 {
787     FIXME("(%p, %s) empty stub!\n", hList, debugstr_a(lpszString));
788
789     return 0;
790 }
791
792 /**************************************************************************
793  *              DelMRUString [COMCTL32.156]
794  *
795  * Removes item from either string or binary list (despite its name)
796  *
797  * PARAMS
798  *    hList [I] list handle
799  *    nItemPos [I] item position to remove 0 -> MRU
800  *
801  * RETURNS
802  *    TRUE if successful, FALSE if nItemPos is out of range.
803  */
804 BOOL WINAPI
805 DelMRUString(HANDLE hList, INT nItemPos)
806 {
807     FIXME("(%p, %d): stub\n", hList, nItemPos);
808     return TRUE;
809 }
810
811 /**************************************************************************
812  *                  FindMRUStringW [COMCTL32.402]
813  *
814  * See FindMRUStringA.
815  */
816 INT WINAPI
817 FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
818 {
819   FIXME("stub\n");
820   return -1;
821 }
822
823 /**************************************************************************
824  *                  FindMRUStringA [COMCTL32.155]
825  *
826  * Searches string list for item that matches lpszString.
827  * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
828  * corresponding to item's reg. name will be stored in it ('a' -> 0).
829  *
830  * PARAMS
831  *    hList [I] list handle
832  *    lpszString [I] string to find
833  *    lpRegNum [O] position in registry (maybe NULL)
834  *
835  * RETURNS
836  *    Position in list 0 -> MRU.  -1 if item not found.
837  */
838 INT WINAPI
839 FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
840 {
841     DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
842     LPWSTR stringW = Alloc(len * sizeof(WCHAR));
843     INT ret;
844
845     MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
846     ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
847     Free(stringW);
848     return ret;
849 }
850
851 /*************************************************************************
852  *                 CreateMRUListLazy_common (internal)
853  */
854 HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
855 {
856     UINT i, err;
857     HKEY newkey;
858     DWORD datasize, dwdisp;
859     WCHAR realname[2];
860     LPWINEMRUITEM witem;
861     DWORD type;
862     static const WCHAR emptyW[] = {'\0'};
863
864     /* get space to save indices that will turn into names
865      * but in order of most to least recently used
866      */
867     mp->realMRU = Alloc(mp->extview.nMaxItems + 2);
868
869     /* get space to save pointers to actual data in order of
870      * 'a' to 'z' (0 to n).
871      */
872     mp->array = Alloc(mp->extview.nMaxItems * sizeof(LPVOID));
873
874     /* open the sub key */
875     if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
876                                 0,
877                                 emptyW,
878                                 REG_OPTION_NON_VOLATILE,
879                                 KEY_READ | KEY_WRITE,
880                                 0,
881                                 &newkey,
882                                 &dwdisp))) {
883         /* error - what to do ??? */
884         ERR("(%lu %lu %lx %lx \"%s\" %p): Can not open key, error=%d\n",
885             mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
886             (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
887                                  mp->extview.lpfnCompare, err);
888         return 0;
889     }
890
891     /* get values from key 'MRUList' */
892     if (newkey) {
893         datasize = mp->extview.nMaxItems + 1;
894         if((err=RegQueryValueExA( newkey, "MRUList", 0, &type, mp->realMRU,
895                                   &datasize))) {
896             /* not present - set size to 1 (will become 0 later) */
897             datasize = 1;
898             *mp->realMRU = 0;
899         }
900
901         TRACE("MRU list = %s\n", mp->realMRU);
902
903         mp->cursize = datasize - 1;
904         /* datasize now has number of items in the MRUList */
905
906         /* get actual values for each entry */
907         realname[1] = 0;
908         for(i=0; i<mp->cursize; i++) {
909             realname[0] = 'a' + i;
910             if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
911                 /* not present - what to do ??? */
912                 ERR("Key %s not found 1\n", debugstr_w(realname));
913             }
914             mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
915             witem->size = datasize;
916             if(RegQueryValueExW( newkey, realname, 0, &type,
917                                  &witem->datastart, &datasize)) {
918                 /* not present - what to do ??? */
919                 ERR("Key %s not found 2\n", debugstr_w(realname));
920             }
921         }
922         RegCloseKey( newkey );
923     }
924     else
925         mp->cursize = 0;
926
927     TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n",
928           mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
929           (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
930           mp->extview.lpfnCompare, mp->cursize);
931     return (HANDLE)mp;
932 }
933
934 /**************************************************************************
935  *                  CreateMRUListLazyW [COMCTL32.404]
936  *
937  * See CreateMRUListLazyA.
938  */
939 HANDLE WINAPI
940 CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
941 {
942     LPWINEMRULIST mp;
943
944     if (lpcml == NULL)
945         return 0;
946
947     if (lpcml->cbSize < sizeof(CREATEMRULISTW))
948         return 0;
949
950     mp = Alloc(sizeof(WINEMRULIST));
951     memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
952     mp->extview.lpszSubKey = Alloc((strlenW(lpcml->lpszSubKey) + 1) * sizeof(WCHAR));
953     strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
954     mp->isUnicode = TRUE;
955
956     return CreateMRUListLazy_common(mp);
957 }
958
959 /**************************************************************************
960  *                  CreateMRUListLazyA [COMCTL32.157]
961  *
962  * Creates a most-recently-used list.
963  *
964  * PARAMS
965  *     lpcml    [I] ptr to CREATEMRULIST structure.
966  *     dwParam2 [I] Unknown
967  *     dwParam3 [I] Unknown
968  *     dwParam4 [I] Unknown
969  *
970  * RETURNS
971  *     Handle to MRU list.
972  */
973 HANDLE WINAPI
974 CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
975 {
976     LPWINEMRULIST mp;
977     DWORD len;
978
979     if (lpcml == NULL)
980         return 0;
981
982     if (lpcml->cbSize < sizeof(CREATEMRULISTA))
983         return 0;
984
985     mp = Alloc(sizeof(WINEMRULIST));
986     memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
987     len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
988     mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
989     MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
990                         (LPWSTR)mp->extview.lpszSubKey, len);
991     mp->isUnicode = FALSE;
992     return CreateMRUListLazy_common(mp);
993 }
994
995 /**************************************************************************
996  *              CreateMRUListW [COMCTL32.400]
997  *
998  * See CreateMRUListA.
999  */
1000 HANDLE WINAPI
1001 CreateMRUListW (LPCREATEMRULISTW lpcml)
1002 {
1003     return CreateMRUListLazyW(lpcml, 0, 0, 0);
1004 }
1005
1006 /**************************************************************************
1007  *              CreateMRUListA [COMCTL32.151]
1008  *
1009  * Creates a most-recently-used list.
1010  *
1011  * PARAMS
1012  *     lpcml [I] ptr to CREATEMRULIST structure.
1013  *
1014  * RETURNS
1015  *     Handle to MRU list.
1016  */
1017 HANDLE WINAPI
1018 CreateMRUListA (LPCREATEMRULISTA lpcml)
1019 {
1020      return CreateMRUListLazyA (lpcml, 0, 0, 0);
1021 }
1022
1023
1024 /**************************************************************************
1025  *                EnumMRUListW [COMCTL32.403]
1026  *
1027  * Enumerate item in a most-recenty-used list
1028  *
1029  * PARAMS
1030  *    hList [I] list handle
1031  *    nItemPos [I] item position to enumerate
1032  *    lpBuffer [O] buffer to receive item
1033  *    nBufferSize [I] size of buffer
1034  *
1035  * RETURNS
1036  *    For binary lists specifies how many bytes were copied to buffer, for
1037  *    string lists specifies full length of string.  Enumerating past the end
1038  *    of list returns -1.
1039  *    If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
1040  *    the list.
1041  */
1042 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1043 DWORD nBufferSize)
1044 {
1045     LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1046     LPWINEMRUITEM witem;
1047     INT desired, datasize;
1048
1049     if (nItemPos >= mp->cursize) return -1;
1050     if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1051     desired = mp->realMRU[nItemPos];
1052     desired -= 'a';
1053     TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1054     witem = mp->array[desired];
1055     datasize = min( witem->size, nBufferSize );
1056     memcpy( lpBuffer, &witem->datastart, datasize);
1057     TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1058           hList, nItemPos, lpBuffer, nBufferSize, datasize);
1059     return datasize;
1060 }
1061
1062 /**************************************************************************
1063  *                EnumMRUListA [COMCTL32.154]
1064  *
1065  * See EnumMRUListW.
1066  */
1067 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1068 DWORD nBufferSize)
1069 {
1070     LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1071     LPWINEMRUITEM witem;
1072     INT desired, datasize;
1073     DWORD lenA;
1074
1075     if (nItemPos >= mp->cursize) return -1;
1076     if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1077     desired = mp->realMRU[nItemPos];
1078     desired -= 'a';
1079     TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1080     witem = mp->array[desired];
1081     if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
1082         datasize = min( witem->size, nBufferSize );
1083         memcpy( lpBuffer, &witem->datastart, datasize);
1084     } else {
1085         lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1086                                    NULL, 0, NULL, NULL);
1087         datasize = min( witem->size, nBufferSize );
1088         WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1089                             lpBuffer, datasize, NULL, NULL);
1090     }
1091     TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1092           hList, nItemPos, lpBuffer, nBufferSize, datasize);
1093     return datasize;
1094 }
1095
1096
1097 /**************************************************************************
1098  * Str_GetPtrA [COMCTL32.233]
1099  *
1100  * Copies a string into a destination buffer.
1101  *
1102  * PARAMS
1103  *     lpSrc   [I] Source string
1104  *     lpDest  [O] Destination buffer
1105  *     nMaxLen [I] Size of buffer in characters
1106  *
1107  * RETURNS
1108  *     The number of characters copied.
1109  */
1110
1111 INT WINAPI
1112 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1113 {
1114     INT len;
1115
1116     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1117
1118     if (!lpDest && lpSrc)
1119         return strlen (lpSrc);
1120
1121     if (nMaxLen == 0)
1122         return 0;
1123
1124     if (lpSrc == NULL) {
1125         lpDest[0] = '\0';
1126         return 0;
1127     }
1128
1129     len = strlen (lpSrc);
1130     if (len >= nMaxLen)
1131         len = nMaxLen - 1;
1132
1133     RtlMoveMemory (lpDest, lpSrc, len);
1134     lpDest[len] = '\0';
1135
1136     return len;
1137 }
1138
1139
1140 /**************************************************************************
1141  * Str_SetPtrA [COMCTL32.234]
1142  *
1143  * Makes a copy of a string, allocating memory if necessary.
1144  *
1145  * PARAMS
1146  *     lppDest [O] Pointer to destination string
1147  *     lpSrc   [I] Source string
1148  *
1149  * RETURNS
1150  *     Success: TRUE
1151  *     Failure: FALSE
1152  *
1153  * NOTES
1154  *     Set lpSrc to NULL to free the memory allocated by a previous call
1155  *     to this function.
1156  */
1157
1158 BOOL WINAPI
1159 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
1160 {
1161     TRACE("(%p %p)\n", lppDest, lpSrc);
1162
1163     if (lpSrc) {
1164         LPSTR ptr = ReAlloc (*lppDest, strlen (lpSrc) + 1);
1165         if (!ptr)
1166             return FALSE;
1167         strcpy (ptr, lpSrc);
1168         *lppDest = ptr;
1169     }
1170     else {
1171         if (*lppDest) {
1172             Free (*lppDest);
1173             *lppDest = NULL;
1174         }
1175     }
1176
1177     return TRUE;
1178 }
1179
1180
1181 /**************************************************************************
1182  * Str_GetPtrW [COMCTL32.235]
1183  *
1184  * See Str_GetPtrA.
1185  */
1186
1187 INT WINAPI
1188 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
1189 {
1190     INT len;
1191
1192     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1193
1194     if (!lpDest && lpSrc)
1195         return strlenW (lpSrc);
1196
1197     if (nMaxLen == 0)
1198         return 0;
1199
1200     if (lpSrc == NULL) {
1201         lpDest[0] = L'\0';
1202         return 0;
1203     }
1204
1205     len = strlenW (lpSrc);
1206     if (len >= nMaxLen)
1207         len = nMaxLen - 1;
1208
1209     RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
1210     lpDest[len] = L'\0';
1211
1212     return len;
1213 }
1214
1215
1216 /**************************************************************************
1217  * Str_SetPtrW [COMCTL32.236]
1218  *
1219  * See Str_SetPtrA.
1220  */
1221
1222 BOOL WINAPI
1223 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
1224 {
1225     TRACE("(%p %p)\n", lppDest, lpSrc);
1226
1227     if (lpSrc) {
1228         INT len = strlenW (lpSrc) + 1;
1229         LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR));
1230         if (!ptr)
1231             return FALSE;
1232         strcpyW (ptr, lpSrc);
1233         *lppDest = ptr;
1234     }
1235     else {
1236         if (*lppDest) {
1237             Free (*lppDest);
1238             *lppDest = NULL;
1239         }
1240     }
1241
1242     return TRUE;
1243 }
1244
1245
1246 /**************************************************************************
1247  * Str_GetPtrWtoA [internal]
1248  *
1249  * Converts a unicode string into a multi byte string
1250  *
1251  * PARAMS
1252  *     lpSrc   [I] Pointer to the unicode source string
1253  *     lpDest  [O] Pointer to caller supplied storage for the multi byte string
1254  *     nMaxLen [I] Size, in bytes, of the destination buffer
1255  *
1256  * RETURNS
1257  *     Length, in bytes, of the converted string.
1258  */
1259
1260 INT
1261 Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1262 {
1263     INT len;
1264
1265     TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
1266
1267     if (!lpDest && lpSrc)
1268         return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1269
1270     if (nMaxLen == 0)
1271         return 0;
1272
1273     if (lpSrc == NULL) {
1274         lpDest[0] = '\0';
1275         return 0;
1276     }
1277
1278     len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1279     if (len >= nMaxLen)
1280         len = nMaxLen - 1;
1281
1282     WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
1283     lpDest[len] = '\0';
1284
1285     return len;
1286 }
1287
1288
1289 /**************************************************************************
1290  * Str_SetPtrAtoW [internal]
1291  *
1292  * Converts a multi byte string to a unicode string.
1293  * If the pointer to the destination buffer is NULL a buffer is allocated.
1294  * If the destination buffer is too small to keep the converted multi byte
1295  * string the destination buffer is reallocated. If the source pointer is
1296  * NULL, the destination buffer is freed.
1297  *
1298  * PARAMS
1299  *     lppDest [I/O] pointer to a pointer to the destination buffer
1300  *     lpSrc   [I] pointer to a multi byte string
1301  *
1302  * RETURNS
1303  *     TRUE: conversion successful
1304  *     FALSE: error
1305  */
1306
1307 BOOL
1308 Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1309 {
1310     TRACE("(%p %s)\n", lppDest, lpSrc);
1311
1312     if (lpSrc) {
1313         INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1314         LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR));
1315
1316         if (!ptr)
1317             return FALSE;
1318         MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
1319         *lppDest = ptr;
1320     }
1321     else {
1322         if (*lppDest) {
1323             Free (*lppDest);
1324             *lppDest = NULL;
1325         }
1326     }
1327
1328     return TRUE;
1329 }
1330
1331
1332 /**************************************************************************
1333  * DSA_Create [COMCTL32.320]
1334  *
1335  * Creates a dynamic storage array
1336  *
1337  * PARAMS
1338  *     nSize [I] size of the array elements
1339  *     nGrow [I] number of elements by which the array grows when it is filled
1340  *
1341  * RETURNS
1342  *     Success: pointer to an array control structure. Use this like a handle.
1343  *     Failure: NULL
1344  *
1345  * NOTES
1346  *     The DSA_ functions can be used to create and manipulate arrays of
1347  *     fixed-size memory blocks. These arrays can store any kind of data
1348  *     (e.g. strings and icons).
1349  */
1350
1351 HDSA WINAPI
1352 DSA_Create (INT nSize, INT nGrow)
1353 {
1354     HDSA hdsa;
1355
1356     TRACE("(size=%d grow=%d)\n", nSize, nGrow);
1357
1358     hdsa = Alloc (sizeof(*hdsa));
1359     if (hdsa)
1360     {
1361         hdsa->nItemCount = 0;
1362         hdsa->pData = NULL;
1363         hdsa->nMaxCount = 0;
1364         hdsa->nItemSize = nSize;
1365         hdsa->nGrow = max(1, nGrow);
1366     }
1367
1368     return hdsa;
1369 }
1370
1371
1372 /**************************************************************************
1373  * DSA_Destroy [COMCTL32.321]
1374  * 
1375  * Destroys a dynamic storage array
1376  *
1377  * PARAMS
1378  *     hdsa [I] pointer to the array control structure
1379  *
1380  * RETURNS
1381  *     Success: TRUE
1382  *     Failure: FALSE
1383  */
1384
1385 BOOL WINAPI
1386 DSA_Destroy (const HDSA hdsa)
1387 {
1388     TRACE("(%p)\n", hdsa);
1389
1390     if (!hdsa)
1391         return FALSE;
1392
1393     if (hdsa->pData && (!Free (hdsa->pData)))
1394         return FALSE;
1395
1396     return Free (hdsa);
1397 }
1398
1399
1400 /**************************************************************************
1401  * DSA_GetItem [COMCTL32.322]
1402  *
1403  * Copies the specified item into a caller-supplied buffer.
1404  *
1405  * PARAMS
1406  *     hdsa   [I] pointer to the array control structure
1407  *     nIndex [I] number of the Item to get
1408  *     pDest  [O] destination buffer. Has to be >= dwElementSize.
1409  *
1410  * RETURNS
1411  *     Success: TRUE
1412  *     Failure: FALSE
1413  */
1414
1415 BOOL WINAPI
1416 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
1417 {
1418     LPVOID pSrc;
1419
1420     TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
1421
1422     if (!hdsa)
1423         return FALSE;
1424     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1425         return FALSE;
1426
1427     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1428     memmove (pDest, pSrc, hdsa->nItemSize);
1429
1430     return TRUE;
1431 }
1432
1433
1434 /**************************************************************************
1435  * DSA_GetItemPtr [COMCTL32.323]
1436  *
1437  * Retrieves a pointer to the specified item.
1438  *
1439  * PARAMS
1440  *     hdsa   [I] pointer to the array control structure
1441  *     nIndex [I] index of the desired item
1442  *
1443  * RETURNS
1444  *     Success: pointer to an item
1445  *     Failure: NULL
1446  */
1447
1448 LPVOID WINAPI
1449 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1450 {
1451     LPVOID pSrc;
1452
1453     TRACE("(%p %d)\n", hdsa, nIndex);
1454
1455     if (!hdsa)
1456         return NULL;
1457     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1458         return NULL;
1459
1460     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1461
1462     TRACE("-- ret=%p\n", pSrc);
1463
1464     return pSrc;
1465 }
1466
1467
1468 /**************************************************************************
1469  * DSA_SetItem [COMCTL32.325]
1470  *
1471  * Sets the contents of an item in the array.
1472  *
1473  * PARAMS
1474  *     hdsa   [I] pointer to the array control structure
1475  *     nIndex [I] index for the item
1476  *     pSrc   [I] pointer to the new item data
1477  *
1478  * RETURNS
1479  *     Success: TRUE
1480  *     Failure: FALSE
1481  */
1482
1483 BOOL WINAPI
1484 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1485 {
1486     INT  nSize, nNewItems;
1487     LPVOID pDest, lpTemp;
1488
1489     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1490
1491     if ((!hdsa) || nIndex < 0)
1492         return FALSE;
1493
1494     if (hdsa->nItemCount <= nIndex) {
1495         /* within the old array */
1496         if (hdsa->nMaxCount > nIndex) {
1497             /* within the allocated space, set a new boundary */
1498             hdsa->nItemCount = nIndex + 1;
1499         }
1500         else {
1501             /* resize the block of memory */
1502             nNewItems =
1503                 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1504             nSize = hdsa->nItemSize * nNewItems;
1505
1506             lpTemp = ReAlloc (hdsa->pData, nSize);
1507             if (!lpTemp)
1508                 return FALSE;
1509
1510             hdsa->nMaxCount = nNewItems;
1511             hdsa->nItemCount = nIndex + 1;
1512             hdsa->pData = lpTemp;
1513         }
1514     }
1515
1516     /* put the new entry in */
1517     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1518     TRACE("-- move dest=%p src=%p size=%d\n",
1519            pDest, pSrc, hdsa->nItemSize);
1520     memmove (pDest, pSrc, hdsa->nItemSize);
1521
1522     return TRUE;
1523 }
1524
1525
1526 /**************************************************************************
1527  * DSA_InsertItem [COMCTL32.324]
1528  *
1529  * Inserts an item into the array at the specified index.
1530  *
1531  * PARAMS
1532  *     hdsa   [I] pointer to the array control structure
1533  *     nIndex [I] index for the new item
1534  *     pSrc   [I] pointer to the element
1535  *
1536  * RETURNS
1537  *     Success: position of the new item
1538  *     Failure: -1
1539  */
1540
1541 INT WINAPI
1542 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1543 {
1544     INT   nNewItems, nSize;
1545     LPVOID  lpTemp, lpDest;
1546
1547     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1548
1549     if ((!hdsa) || nIndex < 0)
1550         return -1;
1551
1552     /* when nIndex >= nItemCount then append */
1553     if (nIndex >= hdsa->nItemCount)
1554         nIndex = hdsa->nItemCount;
1555
1556     /* do we need to resize ? */
1557     if (hdsa->nItemCount >= hdsa->nMaxCount) {
1558         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1559         nSize = hdsa->nItemSize * nNewItems;
1560
1561         lpTemp = ReAlloc (hdsa->pData, nSize);
1562         if (!lpTemp)
1563             return -1;
1564
1565         hdsa->nMaxCount = nNewItems;
1566         hdsa->pData = lpTemp;
1567     }
1568
1569     /* do we need to move elements ? */
1570     if (nIndex < hdsa->nItemCount) {
1571         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1572         lpDest = (char *) lpTemp + hdsa->nItemSize;
1573         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1574         TRACE("-- move dest=%p src=%p size=%d\n",
1575                lpDest, lpTemp, nSize);
1576         memmove (lpDest, lpTemp, nSize);
1577     }
1578
1579     /* ok, we can put the new Item in */
1580     hdsa->nItemCount++;
1581     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1582     TRACE("-- move dest=%p src=%p size=%d\n",
1583            lpDest, pSrc, hdsa->nItemSize);
1584     memmove (lpDest, pSrc, hdsa->nItemSize);
1585
1586     return nIndex;
1587 }
1588
1589
1590 /**************************************************************************
1591  * DSA_DeleteItem [COMCTL32.326]
1592  *
1593  * Deletes the specified item from the array.
1594  *
1595  * PARAMS
1596  *     hdsa   [I] pointer to the array control structure
1597  *     nIndex [I] index for the element to delete
1598  *
1599  * RETURNS
1600  *     Success: number of the deleted element
1601  *     Failure: -1
1602  */
1603
1604 INT WINAPI
1605 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1606 {
1607     LPVOID lpDest,lpSrc;
1608     INT  nSize;
1609
1610     TRACE("(%p %d)\n", hdsa, nIndex);
1611
1612     if (!hdsa)
1613         return -1;
1614     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1615         return -1;
1616
1617     /* do we need to move ? */
1618     if (nIndex < hdsa->nItemCount - 1) {
1619         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1620         lpSrc = (char *) lpDest + hdsa->nItemSize;
1621         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1622         TRACE("-- move dest=%p src=%p size=%d\n",
1623                lpDest, lpSrc, nSize);
1624         memmove (lpDest, lpSrc, nSize);
1625     }
1626
1627     hdsa->nItemCount--;
1628
1629     /* free memory ? */
1630     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1631         nSize = hdsa->nItemSize * hdsa->nItemCount;
1632
1633         lpDest = ReAlloc (hdsa->pData, nSize);
1634         if (!lpDest)
1635             return -1;
1636
1637         hdsa->nMaxCount = hdsa->nItemCount;
1638         hdsa->pData = lpDest;
1639     }
1640
1641     return nIndex;
1642 }
1643
1644
1645 /**************************************************************************
1646  * DSA_DeleteAllItems [COMCTL32.327]
1647  *
1648  * Removes all items and reinitializes the array.
1649  *
1650  * PARAMS
1651  *     hdsa [I] pointer to the array control structure
1652  *
1653  * RETURNS
1654  *     Success: TRUE
1655  *     Failure: FALSE
1656  */
1657
1658 BOOL WINAPI
1659 DSA_DeleteAllItems (const HDSA hdsa)
1660 {
1661     TRACE("(%p)\n", hdsa);
1662
1663     if (!hdsa)
1664         return FALSE;
1665     if (hdsa->pData && (!Free (hdsa->pData)))
1666         return FALSE;
1667
1668     hdsa->nItemCount = 0;
1669     hdsa->pData = NULL;
1670     hdsa->nMaxCount = 0;
1671
1672     return TRUE;
1673 }
1674
1675
1676 /**************************************************************************
1677  * DPA_Destroy [COMCTL32.329]
1678  *
1679  * Destroys a dynamic pointer array
1680  *
1681  * PARAMS
1682  *     hdpa [I] handle (pointer) to the pointer array
1683  *
1684  * RETURNS
1685  *     Success: TRUE
1686  *     Failure: FALSE
1687  */
1688
1689 BOOL WINAPI
1690 DPA_Destroy (const HDPA hdpa)
1691 {
1692     TRACE("(%p)\n", hdpa);
1693
1694     if (!hdpa)
1695         return FALSE;
1696
1697     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1698         return FALSE;
1699
1700     return HeapFree (hdpa->hHeap, 0, hdpa);
1701 }
1702
1703
1704 /**************************************************************************
1705  * DPA_Grow [COMCTL32.330]
1706  *
1707  * Sets the growth amount.
1708  *
1709  * PARAMS
1710  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1711  *     nGrow [I] number of items by which the array grows when it's too small
1712  *
1713  * RETURNS
1714  *     Success: TRUE
1715  *     Failure: FALSE
1716  */
1717
1718 BOOL WINAPI
1719 DPA_Grow (const HDPA hdpa, INT nGrow)
1720 {
1721     TRACE("(%p %d)\n", hdpa, nGrow);
1722
1723     if (!hdpa)
1724         return FALSE;
1725
1726     hdpa->nGrow = max(8, nGrow);
1727
1728     return TRUE;
1729 }
1730
1731
1732 /**************************************************************************
1733  * DPA_Clone [COMCTL32.331]
1734  *
1735  * Copies a pointer array to an other one or creates a copy
1736  *
1737  * PARAMS
1738  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1739  *     hdpaNew [O] handle (pointer) to the destination pointer array
1740  *
1741  * RETURNS
1742  *     Success: pointer to the destination pointer array.
1743  *     Failure: NULL
1744  *
1745  * NOTES
1746  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1747  *       array will be created and it's handle (pointer) is returned.
1748  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1749  *       this implementation just returns NULL.
1750  */
1751
1752 HDPA WINAPI
1753 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1754 {
1755     INT nNewItems, nSize;
1756     HDPA hdpaTemp;
1757
1758     if (!hdpa)
1759         return NULL;
1760
1761     TRACE("(%p %p)\n", hdpa, hdpaNew);
1762
1763     if (!hdpaNew) {
1764         /* create a new DPA */
1765         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1766                                     sizeof(*hdpaTemp));
1767         hdpaTemp->hHeap = hdpa->hHeap;
1768         hdpaTemp->nGrow = hdpa->nGrow;
1769     }
1770     else
1771         hdpaTemp = hdpaNew;
1772
1773     if (hdpaTemp->ptrs) {
1774         /* remove old pointer array */
1775         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1776         hdpaTemp->ptrs = NULL;
1777         hdpaTemp->nItemCount = 0;
1778         hdpaTemp->nMaxCount = 0;
1779     }
1780
1781     /* create a new pointer array */
1782     nNewItems = hdpaTemp->nGrow *
1783                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1784     nSize = nNewItems * sizeof(LPVOID);
1785     hdpaTemp->ptrs =
1786         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1787     hdpaTemp->nMaxCount = nNewItems;
1788
1789     /* clone the pointer array */
1790     hdpaTemp->nItemCount = hdpa->nItemCount;
1791     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1792              hdpaTemp->nItemCount * sizeof(LPVOID));
1793
1794     return hdpaTemp;
1795 }
1796
1797
1798 /**************************************************************************
1799  * DPA_GetPtr [COMCTL32.332]
1800  *
1801  * Retrieves a pointer from a dynamic pointer array
1802  *
1803  * PARAMS
1804  *     hdpa   [I] handle (pointer) to the pointer array
1805  *     nIndex [I] array index of the desired pointer
1806  *
1807  * RETURNS
1808  *     Success: pointer
1809  *     Failure: NULL
1810  */
1811
1812 LPVOID WINAPI
1813 DPA_GetPtr (const HDPA hdpa, INT nIndex)
1814 {
1815     TRACE("(%p %d)\n", hdpa, nIndex);
1816
1817     if (!hdpa)
1818         return NULL;
1819     if (!hdpa->ptrs) {
1820         WARN("no pointer array.\n");
1821         return NULL;
1822     }
1823     if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
1824         WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
1825         return NULL;
1826     }
1827
1828     TRACE("-- %p\n", hdpa->ptrs[nIndex]);
1829
1830     return hdpa->ptrs[nIndex];
1831 }
1832
1833
1834 /**************************************************************************
1835  * DPA_GetPtrIndex [COMCTL32.333]
1836  *
1837  * Retrieves the index of the specified pointer
1838  *
1839  * PARAMS
1840  *     hdpa   [I] handle (pointer) to the pointer array
1841  *     p      [I] pointer
1842  *
1843  * RETURNS
1844  *     Success: index of the specified pointer
1845  *     Failure: -1
1846  */
1847
1848 INT WINAPI
1849 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1850 {
1851     INT i;
1852
1853     if (!hdpa || !hdpa->ptrs)
1854         return -1;
1855
1856     for (i = 0; i < hdpa->nItemCount; i++) {
1857         if (hdpa->ptrs[i] == p)
1858             return i;
1859     }
1860
1861     return -1;
1862 }
1863
1864
1865 /**************************************************************************
1866  * DPA_InsertPtr [COMCTL32.334]
1867  *
1868  * Inserts a pointer into a dynamic pointer array
1869  *
1870  * PARAMS
1871  *     hdpa [I] handle (pointer) to the array
1872  *     i    [I] array index
1873  *     p    [I] pointer to insert
1874  *
1875  * RETURNS
1876  *     Success: index of the inserted pointer
1877  *     Failure: -1
1878  */
1879
1880 INT WINAPI
1881 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1882 {
1883     TRACE("(%p %d %p)\n", hdpa, i, p);
1884
1885     if (!hdpa || i < 0) return -1;
1886
1887     if (i >= 0x7fff)
1888         i = hdpa->nItemCount;
1889
1890     if (i >= hdpa->nItemCount)
1891         return DPA_SetPtr(hdpa, i, p) ? i : -1;
1892
1893     /* create empty spot at the end */
1894     if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
1895     memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
1896     hdpa->ptrs[i] = p;
1897     return i;
1898 }
1899
1900 /**************************************************************************
1901  * DPA_SetPtr [COMCTL32.335]
1902  *
1903  * Sets a pointer in the pointer array
1904  *
1905  * PARAMS
1906  *     hdpa [I] handle (pointer) to the pointer array
1907  *     i    [I] index of the pointer that will be set
1908  *     p    [I] pointer to be set
1909  *
1910  * RETURNS
1911  *     Success: TRUE
1912  *     Failure: FALSE
1913  */
1914
1915 BOOL WINAPI
1916 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1917 {
1918     LPVOID *lpTemp;
1919
1920     TRACE("(%p %d %p)\n", hdpa, i, p);
1921
1922     if (!hdpa || i < 0 || i > 0x7fff)
1923         return FALSE;
1924
1925     if (hdpa->nItemCount <= i) {
1926         /* within the old array */
1927         if (hdpa->nMaxCount <= i) {
1928             /* resize the block of memory */
1929             INT nNewItems =
1930                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1931             INT nSize = nNewItems * sizeof(LPVOID);
1932
1933             if (hdpa->ptrs)
1934                 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
1935             else
1936                 lpTemp = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
1937             
1938             if (!lpTemp)
1939                 return FALSE;
1940
1941             hdpa->nMaxCount = nNewItems;
1942             hdpa->ptrs = lpTemp;
1943         }
1944         hdpa->nItemCount = i+1;
1945     }
1946
1947     /* put the new entry in */
1948     hdpa->ptrs[i] = p;
1949
1950     return TRUE;
1951 }
1952
1953
1954 /**************************************************************************
1955  * DPA_DeletePtr [COMCTL32.336]
1956  *
1957  * Removes a pointer from the pointer array.
1958  *
1959  * PARAMS
1960  *     hdpa [I] handle (pointer) to the pointer array
1961  *     i    [I] index of the pointer that will be deleted
1962  *
1963  * RETURNS
1964  *     Success: deleted pointer
1965  *     Failure: NULL
1966  */
1967
1968 LPVOID WINAPI
1969 DPA_DeletePtr (const HDPA hdpa, INT i)
1970 {
1971     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1972     INT  nSize;
1973
1974     TRACE("(%p %d)\n", hdpa, i);
1975
1976     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1977         return NULL;
1978
1979     lpTemp = hdpa->ptrs[i];
1980
1981     /* do we need to move ?*/
1982     if (i < hdpa->nItemCount - 1) {
1983         lpDest = hdpa->ptrs + i;
1984         lpSrc = lpDest + 1;
1985         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1986         TRACE("-- move dest=%p src=%p size=%x\n",
1987                lpDest, lpSrc, nSize);
1988         memmove (lpDest, lpSrc, nSize);
1989     }
1990
1991     hdpa->nItemCount --;
1992
1993     /* free memory ?*/
1994     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1995         INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
1996         nSize = nNewItems * sizeof(LPVOID);
1997         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1998                                       hdpa->ptrs, nSize);
1999         if (!lpDest)
2000             return NULL;
2001
2002         hdpa->nMaxCount = nNewItems;
2003         hdpa->ptrs = (LPVOID*)lpDest;
2004     }
2005
2006     return lpTemp;
2007 }
2008
2009
2010 /**************************************************************************
2011  * DPA_DeleteAllPtrs [COMCTL32.337]
2012  *
2013  * Removes all pointers and reinitializes the array.
2014  *
2015  * PARAMS
2016  *     hdpa [I] handle (pointer) to the pointer array
2017  *
2018  * RETURNS
2019  *     Success: TRUE
2020  *     Failure: FALSE
2021  */
2022
2023 BOOL WINAPI
2024 DPA_DeleteAllPtrs (const HDPA hdpa)
2025 {
2026     TRACE("(%p)\n", hdpa);
2027
2028     if (!hdpa)
2029         return FALSE;
2030
2031     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2032         return FALSE;
2033
2034     hdpa->nItemCount = 0;
2035     hdpa->nMaxCount = hdpa->nGrow * 2;
2036     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2037                                      hdpa->nMaxCount * sizeof(LPVOID));
2038
2039     return TRUE;
2040 }
2041
2042
2043 /**************************************************************************
2044  * DPA_QuickSort [Internal]
2045  *
2046  * Ordinary quicksort (used by DPA_Sort).
2047  *
2048  * PARAMS
2049  *     lpPtrs     [I] pointer to the pointer array
2050  *     l          [I] index of the "left border" of the partition
2051  *     r          [I] index of the "right border" of the partition
2052  *     pfnCompare [I] pointer to the compare function
2053  *     lParam     [I] user defined value (3rd parameter in compare function)
2054  *
2055  * RETURNS
2056  *     NONE
2057  */
2058
2059 static VOID
2060 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2061                PFNDPACOMPARE pfnCompare, LPARAM lParam)
2062 {
2063     INT m;
2064     LPVOID t;
2065
2066     TRACE("l=%i r=%i\n", l, r);
2067
2068     if (l==r)    /* one element is always sorted */
2069         return;
2070     if (r<l)     /* oops, got it in the wrong order */
2071         {
2072         DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2073         return;
2074         }
2075     m = (l+r)/2; /* divide by two */
2076     DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2077     DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2078
2079     /* join the two sides */
2080     while( (l<=m) && (m<r) )
2081     {
2082         if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2083         {
2084             t = lpPtrs[m+1];
2085             memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
2086             lpPtrs[l] = t;
2087
2088             m++;
2089         }
2090         l++;
2091     }
2092 }
2093
2094
2095 /**************************************************************************
2096  * DPA_Sort [COMCTL32.338]
2097  *
2098  * Sorts a pointer array using a user defined compare function
2099  *
2100  * PARAMS
2101  *     hdpa       [I] handle (pointer) to the pointer array
2102  *     pfnCompare [I] pointer to the compare function
2103  *     lParam     [I] user defined value (3rd parameter of compare function)
2104  *
2105  * RETURNS
2106  *     Success: TRUE
2107  *     Failure: FALSE
2108  */
2109
2110 BOOL WINAPI
2111 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2112 {
2113     if (!hdpa || !pfnCompare)
2114         return FALSE;
2115
2116     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2117
2118     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2119         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2120                        pfnCompare, lParam);
2121
2122     return TRUE;
2123 }
2124
2125
2126 /**************************************************************************
2127  * DPA_Search [COMCTL32.339]
2128  *
2129  * Searches a pointer array for a specified pointer
2130  *
2131  * PARAMS
2132  *     hdpa       [I] handle (pointer) to the pointer array
2133  *     pFind      [I] pointer to search for
2134  *     nStart     [I] start index
2135  *     pfnCompare [I] pointer to the compare function
2136  *     lParam     [I] user defined value (3rd parameter of compare function)
2137  *     uOptions   [I] search options
2138  *
2139  * RETURNS
2140  *     Success: index of the pointer in the array.
2141  *     Failure: -1
2142  *
2143  * NOTES
2144  *     Binary search taken from R.Sedgewick "Algorithms in C"!
2145  *     Function is NOT tested!
2146  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
2147  */
2148
2149 INT WINAPI
2150 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2151             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2152 {
2153     if (!hdpa || !pfnCompare || !pFind)
2154         return -1;
2155
2156     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2157            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2158
2159     if (uOptions & DPAS_SORTED) {
2160         /* array is sorted --> use binary search */
2161         INT l, r, x, n;
2162         LPVOID *lpPtr;
2163
2164         TRACE("binary search\n");
2165
2166         l = (nStart == -1) ? 0 : nStart;
2167         r = hdpa->nItemCount - 1;
2168         lpPtr = hdpa->ptrs;
2169         while (r >= l) {
2170             x = (l + r) / 2;
2171             n = (pfnCompare)(pFind, lpPtr[x], lParam);
2172             if (n < 0)
2173                 r = x - 1;
2174             else
2175                 l = x + 1;
2176             if (n == 0) {
2177                 TRACE("-- ret=%d\n", n);
2178                 return n;
2179             }
2180         }
2181
2182         if (uOptions & DPAS_INSERTBEFORE) {
2183             if (r == -1) r = 0;
2184             TRACE("-- ret=%d\n", r);
2185             return r;
2186         }
2187
2188         if (uOptions & DPAS_INSERTAFTER) {
2189             TRACE("-- ret=%d\n", l);
2190             return l;
2191         }
2192     }
2193     else {
2194         /* array is not sorted --> use linear search */
2195         LPVOID *lpPtr;
2196         INT  nIndex;
2197
2198         TRACE("linear search\n");
2199
2200         nIndex = (nStart == -1)? 0 : nStart;
2201         lpPtr = hdpa->ptrs;
2202         for (; nIndex < hdpa->nItemCount; nIndex++) {
2203             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2204                 TRACE("-- ret=%d\n", nIndex);
2205                 return nIndex;
2206             }
2207         }
2208     }
2209
2210     TRACE("-- not found: ret=-1\n");
2211     return -1;
2212 }
2213
2214
2215 /**************************************************************************
2216  * DPA_CreateEx [COMCTL32.340]
2217  *
2218  * Creates a dynamic pointer array using the specified size and heap.
2219  *
2220  * PARAMS
2221  *     nGrow [I] number of items by which the array grows when it is filled
2222  *     hHeap [I] handle to the heap where the array is stored
2223  *
2224  * RETURNS
2225  *     Success: handle (pointer) to the pointer array.
2226  *     Failure: NULL
2227  *
2228  * NOTES
2229  *     The DPA_ functions can be used to create and manipulate arrays of
2230  *     pointers.
2231  */
2232
2233 HDPA WINAPI
2234 DPA_CreateEx (INT nGrow, HANDLE hHeap)
2235 {
2236     HDPA hdpa;
2237
2238     TRACE("(%d %p)\n", nGrow, hHeap);
2239
2240     if (hHeap)
2241         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
2242     else
2243         hdpa = Alloc (sizeof(*hdpa));
2244
2245     if (hdpa) {
2246         hdpa->nGrow = max(8, nGrow);
2247         hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
2248         hdpa->nMaxCount = hdpa->nGrow * 2;
2249         hdpa->ptrs = HeapAlloc (hdpa->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  * DPA_Create [COMCTL32.328]
2261  *
2262  * Creates a dynamic pointer array.
2263  *
2264  * PARAMS
2265  *     nGrow [I] number of items by which the array grows when it is filled
2266  *
2267  * RETURNS
2268  *     Success: handle (pointer) to the pointer array.
2269  *     Failure: NULL
2270  *
2271  * NOTES
2272  *     The DPA_ functions can be used to create and manipulate arrays of
2273  *     pointers.
2274  */
2275
2276 HDPA WINAPI
2277 DPA_Create (INT nGrow)
2278 {
2279     return DPA_CreateEx( nGrow, 0 );
2280 }
2281
2282
2283 /**************************************************************************
2284  * Notification functions
2285  */
2286
2287 typedef struct tagNOTIFYDATA
2288 {
2289     HWND hwndFrom;
2290     HWND hwndTo;
2291     DWORD  dwParam3;
2292     DWORD  dwParam4;
2293     DWORD  dwParam5;
2294     DWORD  dwParam6;
2295 } NOTIFYDATA, *LPNOTIFYDATA;
2296
2297
2298 /**************************************************************************
2299  * DoNotify [Internal]
2300  */
2301
2302 static LRESULT
2303 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2304 {
2305     NMHDR nmhdr;
2306     LPNMHDR lpNmh = NULL;
2307     UINT idFrom = 0;
2308
2309     TRACE("(%p %p %d %p 0x%08lx)\n",
2310            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2311            lpNotify->dwParam5);
2312
2313     if (!lpNotify->hwndTo)
2314         return 0;
2315
2316     if (lpNotify->hwndFrom == (HWND)-1) {
2317         lpNmh = lpHdr;
2318         idFrom = lpHdr->idFrom;
2319     }
2320     else {
2321         if (lpNotify->hwndFrom)
2322             idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2323
2324         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2325
2326         lpNmh->hwndFrom = lpNotify->hwndFrom;
2327         lpNmh->idFrom = idFrom;
2328         lpNmh->code = uCode;
2329     }
2330
2331     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2332 }
2333
2334
2335 /**************************************************************************
2336  * SendNotify [COMCTL32.341]
2337  *
2338  * Sends a WM_NOTIFY message to the specified window.
2339  *
2340  * PARAMS
2341  *     hwndTo   [I] Window to receive the message
2342  *     hwndFrom [I] Window that the message is from (see notes)
2343  *     uCode    [I] Notification code
2344  *     lpHdr    [I] The NMHDR and any additional information to send or NULL
2345  *
2346  * RETURNS
2347  *     Success: return value from notification
2348  *     Failure: 0
2349  *
2350  * NOTES
2351  *     If hwndFrom is -1 then the identifier of the control sending the
2352  *     message is taken from the NMHDR structure.
2353  *     If hwndFrom is not -1 then lpHdr can be NULL.
2354  */
2355
2356 LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
2357 {
2358     NOTIFYDATA notify;
2359
2360     TRACE("(%p %p %d %p)\n",
2361            hwndTo, hwndFrom, uCode, lpHdr);
2362
2363     notify.hwndFrom = hwndFrom;
2364     notify.hwndTo   = hwndTo;
2365     notify.dwParam5 = 0;
2366     notify.dwParam6 = 0;
2367
2368     return DoNotify (&notify, uCode, lpHdr);
2369 }
2370
2371
2372 /**************************************************************************
2373  * SendNotifyEx [COMCTL32.342]
2374  *
2375  * Sends a WM_NOTIFY message to the specified window.
2376  *
2377  * PARAMS
2378  *     hwndFrom [I] Window to receive the message
2379  *     hwndTo   [I] Window that the message is from
2380  *     uCode    [I] Notification code
2381  *     lpHdr    [I] The NMHDR and any additional information to send or NULL
2382  *     dwParam5 [I] Unknown
2383  *
2384  * RETURNS
2385  *     Success: return value from notification
2386  *     Failure: 0
2387  *
2388  * NOTES
2389  *     If hwndFrom is -1 then the identifier of the control sending the
2390  *     message is taken from the NMHDR structure.
2391  *     If hwndFrom is not -1 then lpHdr can be NULL.
2392  */
2393
2394 LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2395                              LPNMHDR lpHdr, DWORD dwParam5)
2396 {
2397     NOTIFYDATA notify;
2398     HWND hwndNotify;
2399
2400     TRACE("(%p %p %d %p 0x%08lx)\n",
2401            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2402
2403     hwndNotify = hwndTo;
2404     if (!hwndTo) {
2405         if (IsWindow (hwndFrom)) {
2406             hwndNotify = GetParent (hwndFrom);
2407             if (!hwndNotify)
2408                 return 0;
2409         }
2410     }
2411
2412     notify.hwndFrom = hwndFrom;
2413     notify.hwndTo   = hwndNotify;
2414     notify.dwParam5 = dwParam5;
2415     notify.dwParam6 = 0;
2416
2417     return DoNotify (&notify, uCode, lpHdr);
2418 }
2419
2420
2421
2422
2423 /**************************************************************************
2424  * DPA_EnumCallback [COMCTL32.385]
2425  *
2426  * Enumerates all items in a dynamic pointer array.
2427  *
2428  * PARAMS
2429  *     hdpa     [I] handle to the dynamic pointer array
2430  *     enumProc [I]
2431  *     lParam   [I]
2432  *
2433  * RETURNS
2434  *     none
2435  */
2436
2437 VOID WINAPI
2438 DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, LPVOID lParam)
2439 {
2440     INT i;
2441
2442     TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
2443
2444     if (!hdpa)
2445         return;
2446     if (hdpa->nItemCount <= 0)
2447         return;
2448
2449     for (i = 0; i < hdpa->nItemCount; i++) {
2450         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2451             return;
2452     }
2453
2454     return;
2455 }
2456
2457
2458 /**************************************************************************
2459  * DPA_DestroyCallback [COMCTL32.386]
2460  *
2461  * Enumerates all items in a dynamic pointer array and destroys it.
2462  *
2463  * PARAMS
2464  *     hdpa     [I] handle to the dynamic pointer array
2465  *     enumProc [I]
2466  *     lParam   [I]
2467  *
2468  * RETURNS
2469  *     none
2470  */
2471
2472 void WINAPI
2473 DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, LPVOID lParam)
2474 {
2475     TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
2476
2477     DPA_EnumCallback (hdpa, enumProc, lParam);
2478     DPA_Destroy (hdpa);
2479 }
2480
2481
2482 /**************************************************************************
2483  * DSA_EnumCallback [COMCTL32.387]
2484  *
2485  * Enumerates all items in a dynamic storage array.
2486  *
2487  * PARAMS
2488  *     hdsa     [I] handle to the dynamic storage array
2489  *     enumProc [I]
2490  *     lParam   [I]
2491  *
2492  * RETURNS
2493  *     none
2494  */
2495
2496 VOID WINAPI
2497 DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, LPVOID lParam)
2498 {
2499     INT i;
2500
2501     TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
2502
2503     if (!hdsa)
2504         return;
2505     if (hdsa->nItemCount <= 0)
2506         return;
2507
2508     for (i = 0; i < hdsa->nItemCount; i++) {
2509         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2510         if ((enumProc)(lpItem, lParam) == 0)
2511             return;
2512     }
2513
2514     return;
2515 }
2516
2517
2518 /**************************************************************************
2519  * DSA_DestroyCallback [COMCTL32.388]
2520  *
2521  * Enumerates all items in a dynamic storage array and destroys it.
2522  *
2523  * PARAMS
2524  *     hdsa     [I] handle to the dynamic storage array
2525  *     enumProc [I]
2526  *     lParam   [I]
2527  *
2528  * RETURNS
2529  *     none
2530  */
2531
2532 void WINAPI
2533 DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, LPVOID lParam)
2534 {
2535     TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
2536
2537     DSA_EnumCallback (hdsa, enumProc, lParam);
2538     DSA_Destroy (hdsa);
2539 }