Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine] / dlls / comctl32 / comctl32undoc.c
1 /*
2  * Undocumented functions from COMCTL32.DLL
3  *
4  * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
5  *           1998 Juergen Schmied <j.schmied@metronet.de>
6  * NOTES
7  *     All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
8  *     Do NOT rely on names or contents of undocumented structures and types!!!
9  *     These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
10  *     COMCTL32.DLL (internally).
11  *
12  * TODO
13  *     - Add more functions.
14  *     - Write some documentation.
15  */
16
17 #include <string.h>
18 #include <stdlib.h> /* atoi */
19 #include <ctype.h>
20
21 #include "winbase.h"
22 #include "winerror.h"
23 #include "objbase.h"
24 #include "commctrl.h"
25 #include "crtdll.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(commctrl)
29
30
31 extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
32
33 /*
34  * We put some function prototypes here that don't seem to belong in
35  * any header file. When they find their place, we can remove them.
36  */
37 extern LPSTR WINAPI lstrrchr(LPCSTR, LPCSTR, WORD);
38 extern LPWSTR WINAPI lstrrchrw(LPCWSTR, LPCWSTR, WORD);
39
40
41 typedef struct _STREAMDATA
42 {
43     DWORD dwSize;
44     DWORD dwData2;
45     DWORD dwItems;
46 } STREAMDATA, *PSTREAMDATA;
47
48 typedef struct _LOADDATA
49 {
50     INT   nCount;
51     PVOID ptr;
52 } LOADDATA, *LPLOADDATA;
53
54 typedef HRESULT(CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
55
56
57 /**************************************************************************
58  * DPA_LoadStream [COMCTL32.9]
59  *
60  * Loads a dynamic pointer array from a stream
61  *
62  * PARAMS
63  *     phDpa    [O] pointer to a handle to a dynamic pointer array
64  *     loadProc [I] pointer to a callback function
65  *     pStream  [I] pointer to a stream
66  *     lParam   [I] application specific value
67  *
68  * NOTES
69  *     No more information available yet!
70  */
71
72 HRESULT WINAPI
73 DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
74 {
75     HRESULT errCode;
76     LARGE_INTEGER position;
77     ULARGE_INTEGER newPosition;
78     STREAMDATA  streamData;
79     LOADDATA loadData;
80     ULONG ulRead;
81     HDPA hDpa;
82     PVOID *ptr;
83
84     FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
85            phDpa, loadProc, pStream, lParam);
86
87     if (!phDpa || !loadProc || !pStream)
88         return E_INVALIDARG;
89
90     *phDpa = (HDPA)NULL;
91
92     position.s.LowPart = 0;
93     position.s.HighPart = 0;
94
95     errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
96     if (errCode != S_OK)
97         return errCode;
98
99     errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
100     if (errCode != S_OK)
101         return errCode;
102
103     FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
104            streamData.dwSize, streamData.dwData2, streamData.dwItems);
105
106     if (lParam < sizeof(STREAMDATA) ||
107         streamData.dwSize < sizeof(STREAMDATA) ||
108         streamData.dwData2 < 1) {
109         errCode = E_FAIL;
110     }
111
112     /* create the dpa */
113     hDpa = DPA_Create (streamData.dwItems);
114     if (!hDpa)
115         return E_OUTOFMEMORY;
116
117     if (!DPA_Grow (hDpa, streamData.dwItems))
118         return E_OUTOFMEMORY;
119
120     /* load data from the stream into the dpa */
121     ptr = hDpa->ptrs;
122     for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
123         errCode = (loadProc)(&loadData, pStream, lParam);
124         if (errCode != S_OK) {
125             errCode = S_FALSE;
126             break;
127         }
128
129         *ptr = loadData.ptr;
130         ptr++;
131     }
132
133     /* set the number of items */
134     hDpa->nItemCount = loadData.nCount;
135
136     /* store the handle to the dpa */
137     *phDpa = hDpa;
138     FIXME ("new hDpa=%p\n", hDpa);
139
140     return errCode;
141 }
142
143
144 /**************************************************************************
145  * DPA_SaveStream [COMCTL32.10]
146  *
147  * Saves a dynamic pointer array to a stream
148  *
149  * PARAMS
150  *     hDpa     [I] handle to a dynamic pointer array
151  *     loadProc [I] pointer to a callback function
152  *     pStream  [I] pointer to a stream
153  *     lParam   [I] application specific value
154  *
155  * NOTES
156  *     No more information available yet!
157  */
158
159 HRESULT WINAPI
160 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
161 {
162
163     FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
164            hDpa, loadProc, pStream, lParam);
165
166     return E_FAIL;
167 }
168
169
170 /**************************************************************************
171  * DPA_Merge [COMCTL32.11]
172  *
173  * PARAMS
174  *     hdpa1    [I] handle to a dynamic pointer array
175  *     hdpa2    [I] handle to a dynamic pointer array
176  *     dwFlags  [I] flags
177  *     pfnSort  [I] pointer to sort function
178  *     pfnMerge [I] pointer to merge function
179  *     lParam   [I] application specific value
180  *
181  * NOTES
182  *     No more information available yet!
183  */
184
185 BOOL WINAPI
186 DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
187            PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
188 {
189     INT nCount;
190
191 #if 0    /* these go with the "incomplete implementation" below */
192     LPVOID pWork1, pWork2;
193     INT nResult;
194     INT nIndex;
195     INT nNewItems;
196 #endif
197
198     TRACE("(%p %p %08lx %p %p %08lx): semi stub!\n",
199            hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
200
201     if (IsBadWritePtr (hdpa1, sizeof(DPA)))
202         return FALSE;
203
204     if (IsBadWritePtr (hdpa2, sizeof(DPA)))
205         return FALSE;
206
207     if (IsBadCodePtr ((FARPROC)pfnCompare))
208         return FALSE;
209
210     if (IsBadCodePtr ((FARPROC)pfnMerge))
211         return FALSE;
212
213     if (dwFlags & DPAM_SORT) {
214         TRACE("sorting dpa's!\n");
215         if (hdpa1->nItemCount > 0)
216         DPA_Sort (hdpa1, pfnCompare, lParam);
217         TRACE ("dpa 1 sorted!\n");
218         if (hdpa2->nItemCount > 0)
219         DPA_Sort (hdpa2, pfnCompare, lParam);
220         TRACE ("dpa 2 sorted!\n");
221     }
222
223     if (hdpa2->nItemCount < 1)
224         return TRUE;
225
226     TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
227            hdpa1->nItemCount, hdpa2->nItemCount);
228
229
230     /* preliminary hack - simply append the pointer list hdpa2 to hdpa1*/
231     for (nCount = 0; nCount < hdpa2->nItemCount; nCount++)
232         DPA_InsertPtr (hdpa1, hdpa1->nItemCount + 1, hdpa2->ptrs[nCount]);
233
234 #if 0
235     /* incomplete implementation */
236
237     pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
238     pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
239
240     nIndex = hdpa1->nItemCount - 1;
241     nCount = hdpa2->nItemCount - 1;
242
243     do
244     {
245         nResult = (pfnCompare)(pWork1, pWork2, lParam);
246
247         if (nResult == 0)
248         {
249             PVOID ptr;
250
251             ptr = (pfnMerge)(1, pWork1, pWork2, lParam);
252             if (!ptr)
253                 return FALSE;
254
255             nCount--;
256             pWork2--;
257             pWork1 = ptr;
258         }
259         else if (nResult < 0)
260         {
261             if (!dwFlags & 8)
262             {
263                 PVOID ptr;
264
265                 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
266
267                 (pfnMerge)(2, ptr, NULL, lParam);
268             }
269         }
270         else
271         {
272             if (!dwFlags & 4)
273             {
274                 PVOID ptr;
275
276                 ptr = (pfnMerge)(3, pWork2, NULL, lParam);
277                 if (!ptr)
278                     return FALSE;
279                 DPA_InsertPtr (hdpa1, nIndex, ptr);
280     }
281             nCount--;
282             pWork2--;
283         }
284
285         nIndex--;
286         pWork1--;
287
288     }
289     while (nCount >= 0);
290 #endif
291
292     return TRUE;
293 }
294
295
296 /**************************************************************************
297  * Alloc [COMCTL32.71]
298  *
299  * Allocates memory block from the dll's private heap
300  *
301  * PARAMS
302  *     dwSize [I] size of the allocated memory block
303  *
304  * RETURNS
305  *     Success: pointer to allocated memory block
306  *     Failure: NULL
307  */
308
309 LPVOID WINAPI
310 COMCTL32_Alloc (DWORD dwSize)
311 {
312     LPVOID lpPtr;
313
314     TRACE("(0x%lx)\n", dwSize);
315
316     lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
317
318     TRACE("-- ret=%p\n", lpPtr);
319
320     return lpPtr;
321 }
322
323
324 /**************************************************************************
325  * ReAlloc [COMCTL32.72]
326  *
327  * Changes the size of an allocated memory block or allocates a memory
328  * block using the dll's private heap.
329  *
330  * PARAMS
331  *     lpSrc  [I] pointer to memory block which will be resized
332  *     dwSize [I] new size of the memory block.
333  *
334  * RETURNS
335  *     Success: pointer to the resized memory block
336  *     Failure: NULL
337  *
338  * NOTES
339  *     If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
340  *     block like COMCTL32_Alloc.
341  */
342
343 LPVOID WINAPI
344 COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
345 {
346     LPVOID lpDest;
347
348     TRACE("(%p 0x%08lx)\n", lpSrc, dwSize);
349
350     if (lpSrc)
351         lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
352     else
353         lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
354
355     TRACE("-- ret=%p\n", lpDest);
356
357     return lpDest;
358 }
359
360
361 /**************************************************************************
362  * Free [COMCTL32.73]
363  *
364  * Frees an allocated memory block from the dll's private heap.
365  *
366  * PARAMS
367  *     lpMem [I] pointer to memory block which will be freed
368  *
369  * RETURNS
370  *     Success: TRUE
371  *     Failure: FALSE
372  */
373
374 BOOL WINAPI
375 COMCTL32_Free (LPVOID lpMem)
376 {
377     TRACE("(%p)\n", lpMem);
378
379     return HeapFree (COMCTL32_hHeap, 0, lpMem);
380 }
381
382
383 /**************************************************************************
384  * GetSize [COMCTL32.74]
385  *
386  * Retrieves the size of the specified memory block from the dll's
387  * private heap.
388  *
389  * PARAMS
390  *     lpMem [I] pointer to an allocated memory block
391  *
392  * RETURNS
393  *     Success: size of the specified memory block
394  *     Failure: 0
395  */
396
397 DWORD WINAPI
398 COMCTL32_GetSize (LPVOID lpMem)
399 {
400     TRACE("(%p)\n", lpMem);
401
402     return HeapSize (COMCTL32_hHeap, 0, lpMem);
403 }
404
405
406 /**************************************************************************
407  * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
408  * lists.
409  *
410  *
411  */
412
413 typedef struct tagMRUINFO
414 {
415     DWORD  dwParam1;
416     DWORD  dwParam2;
417     DWORD  dwParam3;
418     HKEY   hkeyMain;
419     LPCSTR lpszSubKey;
420     DWORD  dwParam6;
421 } MRUINFO, *LPMRUINFO;
422
423  
424 typedef struct tagMRU
425 {
426     DWORD  dwParam1;  /* some kind of flag */
427     DWORD  dwParam2;
428     DWORD  dwParam3;
429     HKEY   hkeyMRU;
430     LPCSTR lpszSubKey;
431     DWORD  dwParam6;
432 } MRU, *HMRU;
433
434 LPVOID WINAPI
435 CreateMRUListLazyA (LPMRUINFO lpmi, DWORD dwParam2,
436                     DWORD dwParam3, DWORD dwParam4);
437
438
439 /**************************************************************************
440  * CreateMRUListA [COMCTL32.151]
441  *
442  * PARAMS
443  *     dwParam
444  *
445  * RETURNS
446  */
447
448 LPVOID WINAPI
449 CreateMRUListA (LPMRUINFO lpmi)
450 {
451      return CreateMRUListLazyA (lpmi, 0, 0, 0);
452 }
453
454
455 DWORD WINAPI
456 FreeMRUListA (HMRU hmru)
457 {
458     FIXME("(%p) empty stub!\n", hmru);
459
460 #if 0
461     if (!(hmru->dwParam1 & 1001)) {
462         RegSetValueExA (hmru->hKeyMRU, "MRUList", 0, REG_SZ,
463                           hmru->lpszMRUString,
464                           lstrlenA (hmru->lpszMRUString));
465     }
466
467
468     RegClosKey (hmru->hkeyMRU
469     COMCTL32_Free32 (hmru->lpszMRUString);
470 #endif
471
472     return COMCTL32_Free (hmru);
473 }
474
475
476
477 DWORD WINAPI
478 AddMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
479 {
480
481     FIXME("(%lx %lx %lx) empty stub!\n",
482            dwParam1, dwParam2, dwParam3);
483
484     return 0;
485 }
486
487
488 DWORD WINAPI
489 FindMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
490 {
491
492     FIXME("(%lx %lx %lx %lx) empty stub!\n",
493            dwParam1, dwParam2, dwParam3, dwParam4);
494
495     return TRUE;
496 }
497
498
499 LPVOID WINAPI
500 CreateMRUListLazyA (LPMRUINFO lpmi, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
501 {
502     /* DWORD  dwLocal1;   *
503      * HKEY   hkeyResult; *
504      * DWORD  dwLocal3;   *
505      * LPVOID lMRU;       *
506      * DWORD  dwLocal5;   *
507      * DWORD  dwLocal6;   *
508      * DWORD  dwLocal7;   *
509      * DWORD  dwDisposition; */
510
511     /* internal variables */
512     LPVOID ptr;
513
514     FIXME("(%p) empty stub!\n", lpmi);
515
516     if (lpmi) {
517         FIXME("(%lx %lx %lx %lx \"%s\" %lx)\n",
518                lpmi->dwParam1, lpmi->dwParam2, lpmi->dwParam3,
519                (DWORD)lpmi->hkeyMain, lpmi->lpszSubKey, lpmi->dwParam6);
520     }
521
522     /* dummy pointer creation */
523     ptr = COMCTL32_Alloc (32);
524
525     FIXME("-- ret = %p\n", ptr);
526
527     return ptr;
528 }
529
530
531
532
533 /**************************************************************************
534  * Str_GetPtrA [COMCTL32.233]
535  *
536  * PARAMS
537  *     lpSrc   [I]
538  *     lpDest  [O]
539  *     nMaxLen [I]
540  *
541  * RETURNS
542  */
543
544 INT WINAPI
545 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
546 {
547     INT len;
548
549     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
550
551     if (!lpDest && lpSrc)
552         return lstrlenA (lpSrc);
553
554     if (nMaxLen == 0)
555         return 0;
556
557     if (lpSrc == NULL) {
558         lpDest[0] = '\0';
559         return 0;
560     }
561
562     len = lstrlenA (lpSrc);
563     if (len >= nMaxLen)
564         len = nMaxLen - 1;
565
566     RtlMoveMemory (lpDest, lpSrc, len);
567     lpDest[len] = '\0';
568
569     return len;
570 }
571
572
573 /**************************************************************************
574  * Str_SetPtrA [COMCTL32.234]
575  *
576  * PARAMS
577  *     lppDest [O]
578  *     lpSrc   [I]
579  *
580  * RETURNS
581  */
582
583 BOOL WINAPI
584 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
585 {
586     TRACE("(%p %p)\n", lppDest, lpSrc);
587  
588     if (lpSrc) {
589         LPSTR ptr = COMCTL32_ReAlloc (*lppDest, lstrlenA (lpSrc) + 1);
590         if (!ptr)
591             return FALSE;
592         lstrcpyA (ptr, lpSrc);
593         *lppDest = ptr;
594     }
595     else {
596         if (*lppDest) {
597             COMCTL32_Free (*lppDest);
598             *lppDest = NULL;
599         }
600     }
601
602     return TRUE;
603 }
604
605
606 /**************************************************************************
607  * Str_GetPtrW [COMCTL32.235]
608  *
609  * PARAMS
610  *     lpSrc   [I]
611  *     lpDest  [O]
612  *     nMaxLen [I]
613  *
614  * RETURNS
615  */
616
617 INT WINAPI
618 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
619 {
620     INT len;
621
622     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
623
624     if (!lpDest && lpSrc)
625         return lstrlenW (lpSrc);
626
627     if (nMaxLen == 0)
628         return 0;
629
630     if (lpSrc == NULL) {
631         lpDest[0] = L'\0';
632         return 0;
633     }
634
635     len = lstrlenW (lpSrc);
636     if (len >= nMaxLen)
637         len = nMaxLen - 1;
638
639     RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
640     lpDest[len] = L'\0';
641
642     return len;
643 }
644
645
646 /**************************************************************************
647  * Str_SetPtrW [COMCTL32.236]
648  *
649  * PARAMS
650  *     lpDest [O]
651  *     lpSrc  [I]
652  *
653  * RETURNS
654  */
655
656 BOOL WINAPI
657 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
658 {
659     TRACE("(%p %p)\n", lppDest, lpSrc);
660  
661     if (lpSrc) {
662         INT len = lstrlenW (lpSrc) + 1;
663         LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
664         if (!ptr)
665             return FALSE;
666         lstrcpyW (ptr, lpSrc);
667         *lppDest = ptr;
668     }
669     else {
670         if (*lppDest) {
671             COMCTL32_Free (*lppDest);
672             *lppDest = NULL;
673         }
674     }
675
676     return TRUE;
677 }
678
679
680 /**************************************************************************
681  * The DSA-API is a set of functions to create and manipulate arrays of
682  * fix sized memory blocks. These arrays can store any kind of data
683  * (strings, icons...).
684  */
685
686 /**************************************************************************
687  * DSA_Create [COMCTL32.320] Creates a dynamic storage array
688  *
689  * PARAMS
690  *     nSize [I] size of the array elements
691  *     nGrow [I] number of elements by which the array grows when it is filled
692  *
693  * RETURNS
694  *     Success: pointer to a array control structure. use this like a handle.
695  *     Failure: NULL
696  */
697
698 HDSA WINAPI
699 DSA_Create (INT nSize, INT nGrow)
700 {
701     HDSA hdsa;
702
703     TRACE("(size=%d grow=%d)\n", nSize, nGrow);
704
705     hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
706     if (hdsa)
707     {
708         hdsa->nItemCount = 0;
709         hdsa->pData = NULL;
710         hdsa->nMaxCount = 0;
711         hdsa->nItemSize = nSize;
712         hdsa->nGrow = MAX(1, nGrow);
713     }
714
715     return hdsa;
716 }
717
718
719 /**************************************************************************
720  * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
721  *
722  * PARAMS
723  *     hdsa [I] pointer to the array control structure
724  *
725  * RETURNS
726  *     Success: TRUE
727  *     Failure: FALSE
728  */
729
730 BOOL WINAPI
731 DSA_Destroy (const HDSA hdsa)
732 {
733     TRACE("(%p)\n", hdsa);
734
735     if (!hdsa)
736         return FALSE;
737
738     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
739         return FALSE;
740
741     return COMCTL32_Free (hdsa);
742 }
743
744
745 /**************************************************************************
746  * DSA_GetItem [COMCTL32.322] 
747  *
748  * PARAMS
749  *     hdsa   [I] pointer to the array control structure
750  *     nIndex [I] number of the Item to get
751  *     pDest  [O] destination buffer. Has to be >= dwElementSize.
752  *
753  * RETURNS
754  *     Success: TRUE
755  *     Failure: FALSE
756  */
757
758 BOOL WINAPI
759 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
760 {
761     LPVOID pSrc;
762
763     TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
764     
765     if (!hdsa)
766         return FALSE;
767     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
768         return FALSE;
769
770     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
771     memmove (pDest, pSrc, hdsa->nItemSize);
772
773     return TRUE;
774 }
775
776
777 /**************************************************************************
778  * DSA_GetItemPtr [COMCTL32.323] 
779  *
780  * Retrieves a pointer to the specified item.
781  *
782  * PARAMS
783  *     hdsa   [I] pointer to the array control structure
784  *     nIndex [I] index of the desired item
785  *
786  * RETURNS
787  *     Success: pointer to an item
788  *     Failure: NULL
789  */
790
791 LPVOID WINAPI
792 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
793 {
794     LPVOID pSrc;
795
796     TRACE("(%p %d)\n", hdsa, nIndex);
797
798     if (!hdsa)
799         return NULL;
800     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
801         return NULL;
802
803     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
804     
805     TRACE("-- ret=%p\n", pSrc);
806
807     return  pSrc;
808 }
809
810
811 /**************************************************************************
812  * DSA_SetItem [COMCTL32.325] 
813  *
814  * Sets the contents of an item in the array.
815  *
816  * PARAMS
817  *     hdsa   [I] pointer to the array control structure
818  *     nIndex [I] index for the item
819  *     pSrc   [I] pointer to the new item data
820  *
821  * RETURNS
822  *     Success: TRUE
823  *     Failure: FALSE
824  */
825
826 BOOL WINAPI
827 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
828 {
829     INT  nSize, nNewItems;
830     LPVOID pDest, lpTemp;
831     
832     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
833
834     if ((!hdsa) || nIndex < 0)
835         return FALSE;
836       
837     if (hdsa->nItemCount <= nIndex) {
838         /* within the old array */
839         if (hdsa->nMaxCount > nIndex) {
840             /* within the allocated space, set a new boundary */
841             hdsa->nItemCount = nIndex + 1;
842         }
843         else {
844             /* resize the block of memory */
845             nNewItems =
846                 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
847             nSize = hdsa->nItemSize * nNewItems;
848
849             lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
850             if (!lpTemp)
851                 return FALSE;
852
853             hdsa->nMaxCount = nNewItems;
854             hdsa->nItemCount = nIndex + 1;
855             hdsa->pData = lpTemp;
856         }    
857     }
858
859     /* put the new entry in */
860     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
861     TRACE("-- move dest=%p src=%p size=%d\n",
862            pDest, pSrc, hdsa->nItemSize);
863     memmove (pDest, pSrc, hdsa->nItemSize);
864
865     return TRUE;
866 }
867
868
869 /**************************************************************************
870  * DSA_InsertItem [COMCTL32.325] 
871  *
872  * PARAMS
873  *     hdsa   [I] pointer to the array control structure
874  *     nIndex [I] index for the new item
875  *     pSrc   [I] pointer to the element
876  *
877  * RETURNS
878  *     Success: position of the new item
879  *     Failure: -1
880  */
881
882 INT WINAPI
883 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
884 {
885     INT   nNewItems, nSize, i;
886     LPVOID  lpTemp, lpDest;
887     LPDWORD p;
888     
889     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
890
891     if ((!hdsa) || nIndex < 0)
892         return -1;
893
894     for (i = 0; i < hdsa->nItemSize; i += 4) {
895         p = *(DWORD**)((char *) pSrc + i);
896         if (IsBadStringPtrA ((char*)p, 256))
897             TRACE("-- %d=%p\n", i, (DWORD*)p);
898         else
899             TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
900     }
901    
902     /* when nIndex > nItemCount then append */
903     if (nIndex >= hdsa->nItemCount)
904         nIndex = hdsa->nItemCount;
905
906     /* do we need to resize ? */
907     if (hdsa->nItemCount >= hdsa->nMaxCount) {
908         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
909         nSize = hdsa->nItemSize * nNewItems;
910
911         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
912         if (!lpTemp)
913             return -1;
914
915         hdsa->nMaxCount = nNewItems;
916         hdsa->pData = lpTemp;         
917     }
918
919     /* do we need to move elements ? */
920     if (nIndex < hdsa->nItemCount) {
921         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
922         lpDest = (char *) lpTemp + hdsa->nItemSize;
923         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
924         TRACE("-- move dest=%p src=%p size=%d\n",
925                lpDest, lpTemp, nSize);
926         memmove (lpDest, lpTemp, nSize);
927     }
928
929     /* ok, we can put the new Item in */
930     hdsa->nItemCount++;
931     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
932     TRACE("-- move dest=%p src=%p size=%d\n",
933            lpDest, pSrc, hdsa->nItemSize);
934     memmove (lpDest, pSrc, hdsa->nItemSize);
935
936     return hdsa->nItemCount;
937 }
938
939
940 /**************************************************************************
941  * DSA_DeleteItem [COMCTL32.326] 
942  *
943  * PARAMS
944  *     hdsa   [I] pointer to the array control structure
945  *     nIndex [I] index for the element to delete
946  *
947  * RETURNS
948  *     Success: number of the deleted element
949  *     Failure: -1
950  */
951
952 INT WINAPI
953 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
954 {
955     LPVOID lpDest,lpSrc;
956     INT  nSize;
957     
958     TRACE("(%p %d)\n", hdsa, nIndex);
959
960     if (!hdsa)
961         return -1;
962     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
963         return -1;
964
965     /* do we need to move ? */
966     if (nIndex < hdsa->nItemCount - 1) {
967         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
968         lpSrc = (char *) lpDest + hdsa->nItemSize;
969         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
970         TRACE("-- move dest=%p src=%p size=%d\n",
971                lpDest, lpSrc, nSize);
972         memmove (lpDest, lpSrc, nSize);
973     }
974     
975     hdsa->nItemCount--;
976     
977     /* free memory ? */
978     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
979         nSize = hdsa->nItemSize * hdsa->nItemCount;
980
981         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
982         if (!lpDest)
983             return -1;
984
985         hdsa->nMaxCount = hdsa->nItemCount;
986         hdsa->pData = lpDest;
987     }
988
989     return nIndex;
990 }
991
992
993 /**************************************************************************
994  * DSA_DeleteAllItems [COMCTL32.326]
995  *
996  * Removes all items and reinitializes the array.
997  *
998  * PARAMS
999  *     hdsa [I] pointer to the array control structure
1000  *
1001  * RETURNS
1002  *     Success: TRUE
1003  *     Failure: FALSE
1004  */
1005
1006 BOOL WINAPI
1007 DSA_DeleteAllItems (const HDSA hdsa)
1008 {
1009     TRACE("(%p)\n", hdsa);
1010
1011     if (!hdsa) 
1012         return FALSE;
1013     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1014         return FALSE;
1015
1016     hdsa->nItemCount = 0;
1017     hdsa->pData = NULL;
1018     hdsa->nMaxCount = 0;
1019
1020     return TRUE;
1021 }
1022
1023
1024 /**************************************************************************
1025  * The DPA-API is a set of functions to create and manipulate arrays of
1026  * pointers.
1027  */
1028
1029 /**************************************************************************
1030  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1031  *
1032  * PARAMS
1033  *     nGrow [I] number of items by which the array grows when it is filled
1034  *
1035  * RETURNS
1036  *     Success: handle (pointer) to the pointer array.
1037  *     Failure: NULL
1038  */
1039
1040 HDPA WINAPI
1041 DPA_Create (INT nGrow)
1042 {
1043     HDPA hdpa;
1044
1045     TRACE("(%d)\n", nGrow);
1046
1047     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1048     if (hdpa) {
1049         hdpa->nGrow = MAX(8, nGrow);
1050         hdpa->hHeap = COMCTL32_hHeap;
1051         hdpa->nMaxCount = hdpa->nGrow * 2;
1052         hdpa->ptrs =
1053             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1054     }
1055
1056     TRACE("-- %p\n", hdpa);
1057
1058     return hdpa;
1059 }
1060
1061
1062 /**************************************************************************
1063  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1064  *
1065  * PARAMS
1066  *     hdpa [I] handle (pointer) to the pointer array
1067  *
1068  * RETURNS
1069  *     Success: TRUE
1070  *     Failure: FALSE
1071  */
1072
1073 BOOL WINAPI
1074 DPA_Destroy (const HDPA hdpa)
1075 {
1076     TRACE("(%p)\n", hdpa);
1077
1078     if (!hdpa)
1079         return FALSE;
1080
1081     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1082         return FALSE;
1083
1084     return HeapFree (hdpa->hHeap, 0, hdpa);
1085 }
1086
1087
1088 /**************************************************************************
1089  * DPA_Grow [COMCTL32.330]
1090  *
1091  * Sets the growth amount.
1092  *
1093  * PARAMS
1094  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1095  *     nGrow [I] number of items, the array grows, when it's too small
1096  *
1097  * RETURNS
1098  *     Success: TRUE
1099  *     Failure: FALSE
1100  */
1101
1102 BOOL WINAPI
1103 DPA_Grow (const HDPA hdpa, INT nGrow)
1104 {
1105     TRACE("(%p %d)\n", hdpa, nGrow);
1106
1107     if (!hdpa)
1108         return FALSE;
1109
1110     hdpa->nGrow = MAX(8, nGrow);
1111
1112     return TRUE;
1113 }
1114
1115
1116 /**************************************************************************
1117  * DPA_Clone [COMCTL32.331]
1118  *
1119  * Copies a pointer array to an other one or creates a copy
1120  *
1121  * PARAMS
1122  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1123  *     hdpaNew [O] handle (pointer) to the destination pointer array
1124  *
1125  * RETURNS
1126  *     Success: pointer to the destination pointer array.
1127  *     Failure: NULL
1128  *
1129  * NOTES
1130  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1131  *       array will be created and it's handle (pointer) is returned.
1132  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1133  *       this implementation just returns NULL.
1134  */
1135
1136 HDPA WINAPI
1137 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1138 {
1139     INT nNewItems, nSize;
1140     HDPA hdpaTemp;
1141
1142     if (!hdpa)
1143         return NULL;
1144
1145     TRACE("(%p %p)\n", hdpa, hdpaNew);
1146
1147     if (!hdpaNew) {
1148         /* create a new DPA */
1149         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1150                                     sizeof(DPA));
1151         hdpaTemp->hHeap = hdpa->hHeap;
1152         hdpaTemp->nGrow = hdpa->nGrow;
1153     }
1154     else
1155         hdpaTemp = hdpaNew;
1156
1157     if (hdpaTemp->ptrs) {
1158         /* remove old pointer array */
1159         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1160         hdpaTemp->ptrs = NULL;
1161         hdpaTemp->nItemCount = 0;
1162         hdpaTemp->nMaxCount = 0;
1163     }
1164
1165     /* create a new pointer array */
1166     nNewItems = hdpaTemp->nGrow *
1167                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1168     nSize = nNewItems * sizeof(LPVOID);
1169     hdpaTemp->ptrs =
1170         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1171     hdpaTemp->nMaxCount = nNewItems;
1172
1173     /* clone the pointer array */
1174     hdpaTemp->nItemCount = hdpa->nItemCount;
1175     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1176              hdpaTemp->nItemCount * sizeof(LPVOID));
1177
1178     return hdpaTemp;
1179 }
1180
1181
1182 /**************************************************************************
1183  * DPA_GetPtr [COMCTL32.332]
1184  *
1185  * Retrieves a pointer from a dynamic pointer array
1186  *
1187  * PARAMS
1188  *     hdpa   [I] handle (pointer) to the pointer array
1189  *     nIndex [I] array index of the desired pointer
1190  *
1191  * RETURNS
1192  *     Success: pointer
1193  *     Failure: NULL
1194  */
1195
1196 LPVOID WINAPI
1197 DPA_GetPtr (const HDPA hdpa, INT i)
1198 {
1199     TRACE("(%p %d)\n", hdpa, i);
1200
1201     if (!hdpa)
1202         return NULL;
1203     if (!hdpa->ptrs)
1204         return NULL;
1205     if ((i < 0) || (i >= hdpa->nItemCount))
1206         return NULL;
1207
1208     TRACE("-- %p\n", hdpa->ptrs[i]);
1209
1210     return hdpa->ptrs[i];
1211 }
1212
1213
1214 /**************************************************************************
1215  * DPA_GetPtrIndex [COMCTL32.333]
1216  *
1217  * Retrieves the index of the specified pointer
1218  *
1219  * PARAMS
1220  *     hdpa   [I] handle (pointer) to the pointer array
1221  *     p      [I] pointer
1222  *
1223  * RETURNS
1224  *     Success: index of the specified pointer
1225  *     Failure: -1
1226  */
1227
1228 INT WINAPI
1229 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1230 {
1231     INT i;
1232
1233     if (!hdpa->ptrs)
1234         return -1;
1235
1236     for (i = 0; i < hdpa->nItemCount; i++) {
1237         if (hdpa->ptrs[i] == p)
1238             return i;
1239     }
1240
1241     return -1;
1242 }
1243
1244
1245 /**************************************************************************
1246  * DPA_InsertPtr [COMCTL32.334]
1247  *
1248  * Inserts a pointer into a dynamic pointer array
1249  *
1250  * PARAMS
1251  *     hdpa [I] handle (pointer) to the array
1252  *     i    [I] array index
1253  *     p    [I] pointer to insert
1254  *
1255  * RETURNS
1256  *     Success: index of the inserted pointer
1257  *     Failure: -1
1258  */
1259
1260 INT WINAPI
1261 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1262 {
1263     INT   nNewItems, nSize, nIndex = 0;
1264     LPVOID  *lpTemp, *lpDest;
1265
1266     TRACE("(%p %d %p)\n", hdpa, i, p);
1267
1268     if ((!hdpa) || (i < 0))
1269         return -1;
1270
1271     if (!hdpa->ptrs) {
1272         hdpa->ptrs =
1273             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1274                                 2 * hdpa->nGrow * sizeof(LPVOID));
1275         if (!hdpa->ptrs)
1276             return -1;
1277         hdpa->nMaxCount = hdpa->nGrow * 2;
1278         nIndex = 0;
1279     }
1280     else {
1281         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1282             TRACE("-- resizing\n");
1283             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1284             nSize = nNewItems * sizeof(LPVOID);
1285
1286             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1287                                            hdpa->ptrs, nSize);
1288             if (!lpTemp)
1289                 return -1;
1290             hdpa->nMaxCount = nNewItems;
1291             hdpa->ptrs = lpTemp;
1292         }
1293
1294         if (i >= hdpa->nItemCount) {
1295             nIndex = hdpa->nItemCount;
1296             TRACE("-- appending at %d\n", nIndex);
1297         }
1298         else {
1299             TRACE("-- inserting at %d\n", i);
1300             lpTemp = hdpa->ptrs + i;
1301             lpDest = lpTemp + 1;
1302             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1303             TRACE("-- move dest=%p src=%p size=%x\n",
1304                    lpDest, lpTemp, nSize);
1305             memmove (lpDest, lpTemp, nSize);
1306             nIndex = i;
1307         }
1308     }
1309
1310     /* insert item */
1311     hdpa->nItemCount++;
1312     hdpa->ptrs[nIndex] = p;
1313
1314     return nIndex;
1315 }
1316
1317
1318 /**************************************************************************
1319  * DPA_SetPtr [COMCTL32.335]
1320  *
1321  * Sets a pointer in the pointer array
1322  *
1323  * PARAMS
1324  *     hdpa [I] handle (pointer) to the pointer array
1325  *     i    [I] index of the pointer that will be set
1326  *     p    [I] pointer to be set
1327  *
1328  * RETURNS
1329  *     Success: TRUE
1330  *     Failure: FALSE
1331  */
1332
1333 BOOL WINAPI
1334 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1335 {
1336     LPVOID *lpTemp;
1337     
1338     TRACE("(%p %d %p)\n", hdpa, i, p);
1339
1340     if ((!hdpa) || i < 0)
1341         return FALSE;
1342       
1343     if (hdpa->nItemCount <= i) {
1344         /* within the old array */
1345         if (hdpa->nMaxCount > i) {
1346             /* within the allocated space, set a new boundary */
1347             hdpa->nItemCount = i;
1348         }
1349         else {
1350             /* resize the block of memory */
1351             INT nNewItems =
1352                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1353             INT nSize = nNewItems * sizeof(LPVOID);
1354
1355             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1356                                            hdpa->ptrs, nSize);
1357             if (!lpTemp)
1358                 return FALSE;
1359
1360             hdpa->nItemCount = nNewItems;
1361             hdpa->ptrs = lpTemp;        
1362         }    
1363     }
1364
1365     /* put the new entry in */
1366     hdpa->ptrs[i] = p;
1367
1368     return TRUE;
1369 }
1370
1371
1372 /**************************************************************************
1373  * DPA_DeletePtr [COMCTL32.336]
1374  *
1375  * Removes a pointer from the pointer array.
1376  *
1377  * PARAMS
1378  *     hdpa [I] handle (pointer) to the pointer array
1379  *     i    [I] index of the pointer that will be deleted
1380  *
1381  * RETURNS
1382  *     Success: deleted pointer
1383  *     Failure: NULL
1384  */
1385
1386 LPVOID WINAPI
1387 DPA_DeletePtr (const HDPA hdpa, INT i)
1388 {
1389     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1390     INT  nSize;
1391     
1392     TRACE("(%p %d)\n", hdpa, i);
1393
1394     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1395         return NULL;
1396
1397     lpTemp = hdpa->ptrs[i];
1398
1399     /* do we need to move ?*/
1400     if (i < hdpa->nItemCount - 1) {
1401         lpDest = hdpa->ptrs + i;
1402         lpSrc = lpDest + 1;
1403         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1404         TRACE("-- move dest=%p src=%p size=%x\n",
1405                lpDest, lpSrc, nSize);
1406         memmove (lpDest, lpSrc, nSize);
1407     }
1408     
1409     hdpa->nItemCount --;
1410     
1411     /* free memory ?*/
1412     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1413         INT nNewItems = MIN(hdpa->nGrow * 2, hdpa->nItemCount);
1414         nSize = nNewItems * sizeof(LPVOID);
1415         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1416                                       hdpa->ptrs, nSize);
1417         if (!lpDest)
1418             return NULL;
1419
1420         hdpa->nMaxCount = nNewItems;
1421         hdpa->ptrs = (LPVOID*)lpDest;         
1422     }
1423
1424     return lpTemp;
1425 }
1426
1427
1428 /**************************************************************************
1429  * DPA_DeleteAllPtrs [COMCTL32.337]
1430  *
1431  * Removes all pointers and reinitializes the array.
1432  *
1433  * PARAMS
1434  *     hdpa [I] handle (pointer) to the pointer array
1435  *
1436  * RETURNS
1437  *     Success: TRUE
1438  *     Failure: FALSE
1439  */
1440
1441 BOOL WINAPI
1442 DPA_DeleteAllPtrs (const HDPA hdpa)
1443 {
1444     TRACE("(%p)\n", hdpa);
1445
1446     if (!hdpa) 
1447         return FALSE;
1448
1449     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1450         return FALSE;
1451
1452     hdpa->nItemCount = 0;
1453     hdpa->nMaxCount = hdpa->nGrow * 2;
1454     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1455                                      hdpa->nMaxCount * sizeof(LPVOID));
1456
1457     return TRUE;
1458 }
1459
1460
1461 /**************************************************************************
1462  * DPA_QuickSort [Internal]
1463  *
1464  * Ordinary quicksort (used by DPA_Sort).
1465  *
1466  * PARAMS
1467  *     lpPtrs     [I] pointer to the pointer array
1468  *     l          [I] index of the "left border" of the partition
1469  *     r          [I] index of the "right border" of the partition
1470  *     pfnCompare [I] pointer to the compare function
1471  *     lParam     [I] user defined value (3rd parameter in compare function)
1472  *
1473  * RETURNS
1474  *     NONE
1475  */
1476
1477 static VOID
1478 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1479                PFNDPACOMPARE pfnCompare, LPARAM lParam)
1480 {
1481     LPVOID t, v;
1482     INT  i, j;
1483
1484     TRACE("l=%i r=%i\n", l, r);
1485  
1486     i = l;
1487     j = r;
1488     v = lpPtrs[(int)(l+r)/2];
1489     do {
1490         while ((pfnCompare)(lpPtrs[i], v, lParam) < 0) i++;
1491         while ((pfnCompare)(lpPtrs[j], v, lParam) > 0) j--;
1492         if (i <= j) 
1493         {
1494             t = lpPtrs[i];
1495             lpPtrs[i++] = lpPtrs[j];
1496             lpPtrs[j--] = t;
1497         }
1498     } while (i <= j);
1499     if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
1500     if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
1501 }
1502
1503
1504 /**************************************************************************
1505  * DPA_Sort [COMCTL32.338]
1506  *
1507  * Sorts a pointer array using a user defined compare function
1508  *
1509  * PARAMS
1510  *     hdpa       [I] handle (pointer) to the pointer array
1511  *     pfnCompare [I] pointer to the compare function
1512  *     lParam     [I] user defined value (3rd parameter of compare function)
1513  *
1514  * RETURNS
1515  *     Success: TRUE
1516  *     Failure: FALSE
1517  */
1518
1519 BOOL WINAPI
1520 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1521 {
1522     if (!hdpa || !pfnCompare)
1523         return FALSE;
1524
1525     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1526
1527     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1528         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1529                        pfnCompare, lParam);
1530
1531     return TRUE;
1532 }
1533
1534
1535 /**************************************************************************
1536  * DPA_Search [COMCTL32.339]
1537  *
1538  * Searches a pointer array for a specified pointer
1539  *
1540  * PARAMS
1541  *     hdpa       [I] handle (pointer) to the pointer array
1542  *     pFind      [I] pointer to search for
1543  *     nStart     [I] start index
1544  *     pfnCompare [I] pointer to the compare function
1545  *     lParam     [I] user defined value (3rd parameter of compare function)
1546  *     uOptions   [I] search options
1547  *
1548  * RETURNS
1549  *     Success: index of the pointer in the array.
1550  *     Failure: -1
1551  *
1552  * NOTES
1553  *     Binary search taken from R.Sedgewick "Algorithms in C"!
1554  *     Function is NOT tested!
1555  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
1556  */
1557
1558 INT WINAPI
1559 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1560             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1561 {
1562     if (!hdpa || !pfnCompare || !pFind)
1563         return -1;
1564
1565     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1566            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1567
1568     if (uOptions & DPAS_SORTED) {
1569         /* array is sorted --> use binary search */
1570         INT l, r, x, n;
1571         LPVOID *lpPtr;
1572
1573         TRACE("binary search\n");
1574
1575         l = (nStart == -1) ? 0 : nStart;
1576         r = hdpa->nItemCount - 1;
1577         lpPtr = hdpa->ptrs;
1578         while (r >= l) {
1579             x = (l + r) / 2;
1580             n = (pfnCompare)(pFind, lpPtr[x], lParam);
1581             if (n < 0)
1582                 r = x - 1;
1583             else
1584                 l = x + 1;
1585             if (n == 0) {
1586                 TRACE("-- ret=%d\n", n);
1587                 return n;
1588             }
1589         }
1590
1591         if (uOptions & DPAS_INSERTBEFORE) {
1592             TRACE("-- ret=%d\n", r);
1593             return r;
1594         }
1595
1596         if (uOptions & DPAS_INSERTAFTER) {
1597             TRACE("-- ret=%d\n", l);
1598             return l;
1599         }
1600     }
1601     else {
1602         /* array is not sorted --> use linear search */
1603         LPVOID *lpPtr;
1604         INT  nIndex;
1605
1606         TRACE("linear search\n");
1607         
1608         nIndex = (nStart == -1)? 0 : nStart;
1609         lpPtr = hdpa->ptrs;
1610         for (; nIndex < hdpa->nItemCount; nIndex++) {
1611             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1612                 TRACE("-- ret=%d\n", nIndex);
1613                 return nIndex;
1614             }
1615         }
1616     }
1617
1618     TRACE("-- not found: ret=-1\n");
1619     return -1;
1620 }
1621
1622
1623 /**************************************************************************
1624  * DPA_CreateEx [COMCTL32.340]
1625  *
1626  * Creates a dynamic pointer array using the specified size and heap.
1627  *
1628  * PARAMS
1629  *     nGrow [I] number of items by which the array grows when it is filled
1630  *     hHeap [I] handle to the heap where the array is stored
1631  *
1632  * RETURNS
1633  *     Success: handle (pointer) to the pointer array.
1634  *     Failure: NULL
1635  */
1636
1637 HDPA WINAPI
1638 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1639 {
1640     HDPA hdpa;
1641
1642     TRACE("(%d 0x%x)\n", nGrow, hHeap);
1643
1644     if (hHeap)
1645         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1646     else
1647         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1648
1649     if (hdpa) {
1650         hdpa->nGrow = MIN(8, nGrow);
1651         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1652         hdpa->nMaxCount = hdpa->nGrow * 2;
1653         hdpa->ptrs =
1654             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1655                                 hdpa->nMaxCount * sizeof(LPVOID));
1656     }
1657
1658     TRACE("-- %p\n", hdpa);
1659
1660     return hdpa;
1661 }
1662
1663
1664 /**************************************************************************
1665  * Notification functions
1666  */
1667
1668 typedef struct tagNOTIFYDATA
1669 {
1670     HWND hwndFrom;
1671     HWND hwndTo;
1672     DWORD  dwParam3;
1673     DWORD  dwParam4;
1674     DWORD  dwParam5;
1675     DWORD  dwParam6;
1676 } NOTIFYDATA, *LPNOTIFYDATA;
1677
1678
1679 /**************************************************************************
1680  * DoNotify [Internal]
1681  */
1682
1683 static LRESULT
1684 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1685 {
1686     NMHDR nmhdr;
1687     LPNMHDR lpNmh = NULL;
1688     UINT idFrom = 0;
1689
1690     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1691            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1692            lpNotify->dwParam5);
1693
1694     if (!lpNotify->hwndTo)
1695         return 0;
1696
1697     if (lpNotify->hwndFrom == -1) {
1698         lpNmh = lpHdr;
1699         idFrom = lpHdr->idFrom;
1700     }
1701     else {
1702         if (lpNotify->hwndFrom) {
1703             HWND hwndParent = GetParent (lpNotify->hwndFrom);
1704             if (hwndParent) {
1705                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1706                 if (hwndParent)
1707                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1708             }
1709         }
1710
1711         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1712
1713         lpNmh->hwndFrom = lpNotify->hwndFrom;
1714         lpNmh->idFrom = idFrom;
1715         lpNmh->code = uCode;
1716     }
1717
1718     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1719 }
1720
1721
1722 /**************************************************************************
1723  * SendNotify [COMCTL32.341]
1724  *
1725  * PARAMS
1726  *     hwndFrom [I]
1727  *     hwndTo   [I]
1728  *     uCode    [I]
1729  *     lpHdr    [I]
1730  *
1731  * RETURNS
1732  *     Success: return value from notification
1733  *     Failure: 0
1734  */
1735
1736 LRESULT WINAPI
1737 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1738                      UINT uCode, LPNMHDR lpHdr)
1739 {
1740     NOTIFYDATA notify;
1741
1742     TRACE("(0x%04x 0x%04x %d %p)\n",
1743            hwndFrom, hwndTo, uCode, lpHdr);
1744
1745     notify.hwndFrom = hwndFrom;
1746     notify.hwndTo   = hwndTo;
1747     notify.dwParam5 = 0;
1748     notify.dwParam6 = 0;
1749
1750     return DoNotify (&notify, uCode, lpHdr);
1751 }
1752
1753
1754 /**************************************************************************
1755  * SendNotifyEx [COMCTL32.342]
1756  *
1757  * PARAMS
1758  *     hwndFrom [I]
1759  *     hwndTo   [I]
1760  *     uCode    [I]
1761  *     lpHdr    [I]
1762  *     dwParam5 [I]
1763  *
1764  * RETURNS
1765  *     Success: return value from notification
1766  *     Failure: 0
1767  */
1768
1769 LRESULT WINAPI
1770 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1771                        LPNMHDR lpHdr, DWORD dwParam5)
1772 {
1773     NOTIFYDATA notify;
1774     HWND hwndNotify;
1775
1776     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1777            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1778
1779     hwndNotify = hwndTo;
1780     if (!hwndTo) {
1781         if (IsWindow (hwndFrom)) {
1782             hwndNotify = GetParent (hwndFrom);
1783             if (!hwndNotify)
1784                 return 0;
1785         }
1786     }
1787
1788     notify.hwndFrom = hwndFrom;
1789     notify.hwndTo   = hwndNotify;
1790     notify.dwParam5 = dwParam5;
1791     notify.dwParam6 = 0;
1792
1793     return DoNotify (&notify, uCode, lpHdr);
1794 }
1795
1796
1797 /**************************************************************************
1798  * StrChrA [COMCTL32.350]
1799  *
1800  */
1801
1802 LPSTR WINAPI
1803 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
1804 {
1805     return strchr (lpString, cChar);
1806 }
1807
1808
1809 /**************************************************************************
1810  * StrStrIA [COMCTL32.355]
1811  */
1812
1813 LPSTR WINAPI
1814 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
1815 {
1816     INT len1, len2, i;
1817     CHAR  first;
1818
1819     if (*lpStr2 == 0)
1820         return ((LPSTR)lpStr1);
1821     len1 = 0;
1822     while (lpStr1[len1] != 0) ++len1;
1823     len2 = 0;
1824     while (lpStr2[len2] != 0) ++len2;
1825     if (len2 == 0)
1826         return ((LPSTR)(lpStr1 + len1));
1827     first = tolower (*lpStr2);
1828     while (len1 >= len2) {
1829         if (tolower(*lpStr1) == first) {
1830             for (i = 1; i < len2; ++i)
1831                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
1832                     break;
1833             if (i >= len2)
1834                 return ((LPSTR)lpStr1);
1835         }
1836         ++lpStr1; --len1;
1837     }
1838     return (NULL);
1839 }
1840
1841
1842 /**************************************************************************
1843  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
1844  */
1845
1846 INT WINAPI
1847 COMCTL32_StrToIntA (LPSTR lpString)
1848 {
1849     return atoi(lpString);
1850 }
1851
1852
1853 /**************************************************************************
1854  * DPA_EnumCallback [COMCTL32.385]
1855  *
1856  * Enumerates all items in a dynamic pointer array.
1857  *
1858  * PARAMS
1859  *     hdpa     [I] handle to the dynamic pointer array
1860  *     enumProc [I]
1861  *     lParam   [I] 
1862  *
1863  * RETURNS
1864  *     none
1865  */
1866
1867 VOID WINAPI
1868 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1869 {
1870     INT i;
1871
1872     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1873
1874     if (!hdpa)
1875         return;
1876     if (hdpa->nItemCount <= 0)
1877         return;
1878
1879     for (i = 0; i < hdpa->nItemCount; i++) {
1880         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
1881             return;
1882     }
1883
1884     return;
1885 }
1886
1887
1888 /**************************************************************************
1889  * DPA_DestroyCallback [COMCTL32.386]
1890  *
1891  * Enumerates all items in a dynamic pointer array and destroys it.
1892  *
1893  * PARAMS
1894  *     hdpa     [I] handle to the dynamic pointer array
1895  *     enumProc [I]
1896  *     lParam   [I]
1897  *
1898  * RETURNS
1899  *     Success: TRUE
1900  *     Failure: FALSE
1901  */
1902
1903 BOOL WINAPI
1904 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1905 {
1906     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1907
1908     DPA_EnumCallback (hdpa, enumProc, lParam);
1909
1910     return DPA_Destroy (hdpa);
1911 }
1912
1913
1914 /**************************************************************************
1915  * DSA_EnumCallback [COMCTL32.387]
1916  *
1917  * Enumerates all items in a dynamic storage array.
1918  *
1919  * PARAMS
1920  *     hdsa     [I] handle to the dynamic storage array
1921  *     enumProc [I]
1922  *     lParam   [I]
1923  *
1924  * RETURNS
1925  *     none
1926  */
1927
1928 VOID WINAPI
1929 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1930 {
1931     INT i;
1932
1933     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1934
1935     if (!hdsa)
1936         return;
1937     if (hdsa->nItemCount <= 0)
1938         return;
1939
1940     for (i = 0; i < hdsa->nItemCount; i++) {
1941         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
1942         if ((enumProc)(lpItem, lParam) == 0)
1943             return;
1944     }
1945
1946     return;
1947 }
1948
1949
1950 /**************************************************************************
1951  * DSA_DestroyCallback [COMCTL32.388]
1952  *
1953  * Enumerates all items in a dynamic storage array and destroys it.
1954  *
1955  * PARAMS
1956  *     hdsa     [I] handle to the dynamic storage array
1957  *     enumProc [I]
1958  *     lParam   [I]
1959  *
1960  * RETURNS
1961  *     Success: TRUE
1962  *     Failure: FALSE
1963  */
1964
1965 BOOL WINAPI
1966 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1967 {
1968     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1969
1970     DSA_EnumCallback (hdsa, enumProc, lParam);
1971
1972     return DSA_Destroy (hdsa);
1973 }
1974
1975 /**************************************************************************
1976  * StrCSpnA [COMCTL32.356]
1977  *
1978  */
1979 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
1980   return strcspn(lpStr, lpSet);
1981 }
1982
1983 /**************************************************************************
1984  * StrChrW [COMCTL32.358]
1985  *
1986  */
1987 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
1988   return CRTDLL_wcschr(lpStart, wMatch);
1989 }
1990
1991 /**************************************************************************
1992  * StrCmpNA [COMCTL32.352]
1993  *
1994  */
1995 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
1996   return strncmp(lpStr1, lpStr2, nChar);
1997 }
1998
1999 /**************************************************************************
2000  * StrCmpNIA [COMCTL32.353]
2001  *
2002  */
2003 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2004   return strncasecmp(lpStr1, lpStr2, nChar);
2005 }
2006
2007 /**************************************************************************
2008  * StrCmpNW [COMCTL32.360]
2009  *
2010  */
2011 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2012   return CRTDLL_wcsncmp(lpStr1, lpStr2, nChar);
2013 }
2014
2015 /**************************************************************************
2016  * StrCmpNIW [COMCTL32.361]
2017  *
2018  */
2019 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2020   FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2021   return 0;
2022 }
2023
2024 /**************************************************************************
2025  * StrRChrA [COMCTL32.351]
2026  *
2027  */
2028 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch) {
2029   return lstrrchr(lpStart, lpEnd, wMatch); 
2030 }
2031
2032 /**************************************************************************
2033  * StrRChrW [COMCTL32.359]
2034  *
2035  */
2036 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch) {
2037   return lstrrchrw(lpStart, lpEnd, wMatch); 
2038 }
2039
2040 /**************************************************************************
2041  * StrStrA [COMCTL32.354]
2042  *
2043  */
2044 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2045   return strstr(lpFirst, lpSrch);
2046 }
2047
2048 /**************************************************************************
2049  * StrStrW [COMCTL32.362]
2050  *
2051  */
2052 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2053   return CRTDLL_wcsstr(lpFirst, lpSrch);
2054 }
2055
2056 /**************************************************************************
2057  * StrSpnW [COMCTL32.364]
2058  *
2059  */
2060 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2061   LPWSTR lpLoop = lpStr;
2062
2063   /* validate ptr */
2064   if ((lpStr == 0) || (lpSet == 0)) return 0;
2065
2066 /* while(*lpLoop) { if lpLoop++; } */
2067
2068   for(; (*lpLoop != 0); lpLoop++)
2069     if( CRTDLL_wcschr(lpSet, *(WORD*)lpLoop))
2070       return (INT)(lpLoop-lpStr);
2071   
2072   return (INT)(lpLoop-lpStr);
2073 }
2074
2075 /**************************************************************************
2076  * comctl32_410 [COMCTL32.410]
2077  *
2078  * FIXME: What's this supposed to do?
2079  *        Parameter 1 is an HWND, you're on your own for the rest.
2080  */
2081
2082 BOOL WINAPI comctl32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2083
2084    FIXME_(commctrl)("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2085
2086    return TRUE;
2087 }
2088
2089 /*************************************************************************
2090  * InitMUILanguage [COMCTL32.70]
2091  *
2092  * FIXME: What's this supposed to do?  Apparently some i18n thing.
2093  *
2094  */
2095
2096 BOOL WINAPI InitMUILanguage( DWORD a ) {
2097
2098    FIXME_(commctrl)("(%lx): stub!\n", a);
2099
2100    return TRUE;
2101 }
2102