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