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