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