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