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