Added DebugBreak.
[wine] / dlls / comctl32 / comctl32undoc.c
1 /*
2  * Undocumented functions from COMCTL32.DLL
3  *
4  * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
5  *           1998 Juergen Schmied <j.schmied@metronet.de>
6  * NOTES
7  *     All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
8  *     Do NOT rely on names or contents of undocumented structures and types!!!
9  *     These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
10  *     COMCTL32.DLL (internally).
11  *
12  * TODO
13  *     - Add more functions.
14  *     - Write some documentation.
15  */
16
17 #include <string.h>
18 #include <stdlib.h> /* atoi */
19 #include <ctype.h>
20
21 #include "winbase.h"
22 #include "commctrl.h"
23 #include "debugtools.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("(%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("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("nCount1=%d nCount2=%d\n", nCount1, nCount2);
91     FIXME("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("(0x%lx)\n", dwSize);
136
137     lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
138
139     TRACE("-- 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("(%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("-- 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("(%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("(%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("(%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("(%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("(%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("(%p) empty stub!\n", lpmi);
336
337     if (lpmi) {
338         FIXME("(%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("-- 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("(%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("(%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("(%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("(%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("(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("(%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("(%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("(%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("-- 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("(%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 + 1;
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->nItemCount = nIndex + 1;
676             hdsa->pData = lpTemp;
677         }    
678     }
679
680     /* put the new entry in */
681     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
682     TRACE("-- move dest=%p src=%p size=%d\n",
683            pDest, pSrc, hdsa->nItemSize);
684     memmove (pDest, pSrc, hdsa->nItemSize);
685
686     return TRUE;
687 }
688
689
690 /**************************************************************************
691  * DSA_InsertItem [COMCTL32.325] 
692  *
693  * PARAMS
694  *     hdsa   [I] pointer to the array control structure
695  *     nIndex [I] index for the new item
696  *     pSrc   [I] pointer to the element
697  *
698  * RETURNS
699  *     Success: position of the new item
700  *     Failure: -1
701  */
702
703 INT WINAPI
704 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
705 {
706     INT   nNewItems, nSize, i;
707     LPVOID  lpTemp, lpDest;
708     LPDWORD p;
709     
710     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
711
712     if ((!hdsa) || nIndex < 0)
713         return -1;
714
715     for (i = 0; i < hdsa->nItemSize; i += 4) {
716         p = *(DWORD**)((char *) pSrc + i);
717         if (IsBadStringPtrA ((char*)p, 256))
718             TRACE("-- %d=%p\n", i, (DWORD*)p);
719         else
720             TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
721     }
722    
723     /* when nIndex > nItemCount then append */
724     if (nIndex >= hdsa->nItemCount)
725         nIndex = hdsa->nItemCount;
726
727     /* do we need to resize ? */
728     if (hdsa->nItemCount >= hdsa->nMaxCount) {
729         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
730         nSize = hdsa->nItemSize * nNewItems;
731
732         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
733         if (!lpTemp)
734             return -1;
735
736         hdsa->nMaxCount = nNewItems;
737         hdsa->pData = lpTemp;         
738     }
739
740     /* do we need to move elements ? */
741     if (nIndex < hdsa->nItemCount) {
742         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
743         lpDest = (char *) lpTemp + hdsa->nItemSize;
744         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
745         TRACE("-- move dest=%p src=%p size=%d\n",
746                lpDest, lpTemp, nSize);
747         memmove (lpDest, lpTemp, nSize);
748     }
749
750     /* ok, we can put the new Item in */
751     hdsa->nItemCount++;
752     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
753     TRACE("-- move dest=%p src=%p size=%d\n",
754            lpDest, pSrc, hdsa->nItemSize);
755     memmove (lpDest, pSrc, hdsa->nItemSize);
756
757     return hdsa->nItemCount;
758 }
759
760
761 /**************************************************************************
762  * DSA_DeleteItem [COMCTL32.326] 
763  *
764  * PARAMS
765  *     hdsa   [I] pointer to the array control structure
766  *     nIndex [I] index for the element to delete
767  *
768  * RETURNS
769  *     Success: number of the deleted element
770  *     Failure: -1
771  */
772
773 INT WINAPI
774 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
775 {
776     LPVOID lpDest,lpSrc;
777     INT  nSize;
778     
779     TRACE("(%p %d)\n", hdsa, nIndex);
780
781     if (!hdsa)
782         return -1;
783     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
784         return -1;
785
786     /* do we need to move ? */
787     if (nIndex < hdsa->nItemCount - 1) {
788         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
789         lpSrc = (char *) lpDest + hdsa->nItemSize;
790         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
791         TRACE("-- move dest=%p src=%p size=%d\n",
792                lpDest, lpSrc, nSize);
793         memmove (lpDest, lpSrc, nSize);
794     }
795     
796     hdsa->nItemCount--;
797     
798     /* free memory ? */
799     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
800         nSize = hdsa->nItemSize * hdsa->nItemCount;
801
802         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
803         if (!lpDest)
804             return -1;
805
806         hdsa->nMaxCount = hdsa->nItemCount;
807         hdsa->pData = lpDest;
808     }
809
810     return nIndex;
811 }
812
813
814 /**************************************************************************
815  * DSA_DeleteAllItems [COMCTL32.326]
816  *
817  * Removes all items and reinitializes the array.
818  *
819  * PARAMS
820  *     hdsa [I] pointer to the array control structure
821  *
822  * RETURNS
823  *     Success: TRUE
824  *     Failure: FALSE
825  */
826
827 BOOL WINAPI
828 DSA_DeleteAllItems (const HDSA hdsa)
829 {
830     TRACE("(%p)\n", hdsa);
831
832     if (!hdsa) 
833         return FALSE;
834     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
835         return FALSE;
836
837     hdsa->nItemCount = 0;
838     hdsa->pData = NULL;
839     hdsa->nMaxCount = 0;
840
841     return TRUE;
842 }
843
844
845 /**************************************************************************
846  * The DPA-API is a set of functions to create and manipulate arrays of
847  * pointers.
848  */
849
850 /**************************************************************************
851  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
852  *
853  * PARAMS
854  *     nGrow [I] number of items by which the array grows when it is filled
855  *
856  * RETURNS
857  *     Success: handle (pointer) to the pointer array.
858  *     Failure: NULL
859  */
860
861 HDPA WINAPI
862 DPA_Create (INT nGrow)
863 {
864     HDPA hdpa;
865
866     TRACE("(%d)\n", nGrow);
867
868     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
869     if (hdpa) {
870         hdpa->nGrow = MAX(8, nGrow);
871         hdpa->hHeap = COMCTL32_hHeap;
872         hdpa->nMaxCount = hdpa->nGrow * 2;
873         hdpa->ptrs =
874             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
875     }
876
877     TRACE("-- %p\n", hdpa);
878
879     return hdpa;
880 }
881
882
883 /**************************************************************************
884  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
885  *
886  * PARAMS
887  *     hdpa [I] handle (pointer) to the pointer array
888  *
889  * RETURNS
890  *     Success: TRUE
891  *     Failure: FALSE
892  */
893
894 BOOL WINAPI
895 DPA_Destroy (const HDPA hdpa)
896 {
897     TRACE("(%p)\n", hdpa);
898
899     if (!hdpa)
900         return FALSE;
901
902     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
903         return FALSE;
904
905     return HeapFree (hdpa->hHeap, 0, hdpa);
906 }
907
908
909 /**************************************************************************
910  * DPA_Grow [COMCTL32.330]
911  *
912  * Sets the growth amount.
913  *
914  * PARAMS
915  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
916  *     nGrow [I] number of items, the array grows, when it's too small
917  *
918  * RETURNS
919  *     Success: TRUE
920  *     Failure: FALSE
921  */
922
923 BOOL WINAPI
924 DPA_Grow (const HDPA hdpa, INT nGrow)
925 {
926     TRACE("(%p %d)\n", hdpa, nGrow);
927
928     if (!hdpa)
929         return FALSE;
930
931     hdpa->nGrow = MAX(8, nGrow);
932
933     return TRUE;
934 }
935
936
937 /**************************************************************************
938  * DPA_Clone [COMCTL32.331]
939  *
940  * Copies a pointer array to an other one or creates a copy
941  *
942  * PARAMS
943  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
944  *     hdpaNew [O] handle (pointer) to the destination pointer array
945  *
946  * RETURNS
947  *     Success: pointer to the destination pointer array.
948  *     Failure: NULL
949  *
950  * NOTES
951  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
952  *       array will be created and it's handle (pointer) is returned.
953  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
954  *       this implementation just returns NULL.
955  */
956
957 HDPA WINAPI
958 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
959 {
960     INT nNewItems, nSize;
961     HDPA hdpaTemp;
962
963     if (!hdpa)
964         return NULL;
965
966     TRACE("(%p %p)\n", hdpa, hdpaNew);
967
968     if (!hdpaNew) {
969         /* create a new DPA */
970         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
971                                     sizeof(DPA));
972         hdpaTemp->hHeap = hdpa->hHeap;
973         hdpaTemp->nGrow = hdpa->nGrow;
974     }
975     else
976         hdpaTemp = hdpaNew;
977
978     if (hdpaTemp->ptrs) {
979         /* remove old pointer array */
980         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
981         hdpaTemp->ptrs = NULL;
982         hdpaTemp->nItemCount = 0;
983         hdpaTemp->nMaxCount = 0;
984     }
985
986     /* create a new pointer array */
987     nNewItems = hdpaTemp->nGrow *
988                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
989     nSize = nNewItems * sizeof(LPVOID);
990     hdpaTemp->ptrs =
991         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
992     hdpaTemp->nMaxCount = nNewItems;
993
994     /* clone the pointer array */
995     hdpaTemp->nItemCount = hdpa->nItemCount;
996     memmove (hdpaTemp->ptrs, hdpa->ptrs,
997              hdpaTemp->nItemCount * sizeof(LPVOID));
998
999     return hdpaTemp;
1000 }
1001
1002
1003 /**************************************************************************
1004  * DPA_GetPtr [COMCTL32.332]
1005  *
1006  * Retrieves a pointer from a dynamic pointer array
1007  *
1008  * PARAMS
1009  *     hdpa   [I] handle (pointer) to the pointer array
1010  *     nIndex [I] array index of the desired pointer
1011  *
1012  * RETURNS
1013  *     Success: pointer
1014  *     Failure: NULL
1015  */
1016
1017 LPVOID WINAPI
1018 DPA_GetPtr (const HDPA hdpa, INT i)
1019 {
1020     TRACE("(%p %d)\n", hdpa, i);
1021
1022     if (!hdpa)
1023         return NULL;
1024     if (!hdpa->ptrs)
1025         return NULL;
1026     if ((i < 0) || (i >= hdpa->nItemCount))
1027         return NULL;
1028
1029     TRACE("-- %p\n", hdpa->ptrs[i]);
1030
1031     return hdpa->ptrs[i];
1032 }
1033
1034
1035 /**************************************************************************
1036  * DPA_GetPtrIndex [COMCTL32.333]
1037  *
1038  * Retrieves the index of the specified pointer
1039  *
1040  * PARAMS
1041  *     hdpa   [I] handle (pointer) to the pointer array
1042  *     p      [I] pointer
1043  *
1044  * RETURNS
1045  *     Success: index of the specified pointer
1046  *     Failure: -1
1047  */
1048
1049 INT WINAPI
1050 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1051 {
1052     INT i;
1053
1054     if (!hdpa->ptrs)
1055         return -1;
1056
1057     for (i = 0; i < hdpa->nItemCount; i++) {
1058         if (hdpa->ptrs[i] == p)
1059             return i;
1060     }
1061
1062     return -1;
1063 }
1064
1065
1066 /**************************************************************************
1067  * DPA_InsertPtr [COMCTL32.334]
1068  *
1069  * Inserts a pointer into a dynamic pointer array
1070  *
1071  * PARAMS
1072  *     hdpa [I] handle (pointer) to the array
1073  *     i    [I] array index
1074  *     p    [I] pointer to insert
1075  *
1076  * RETURNS
1077  *     Success: index of the inserted pointer
1078  *     Failure: -1
1079  */
1080
1081 INT WINAPI
1082 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1083 {
1084     INT   nNewItems, nSize, nIndex = 0;
1085     LPVOID  *lpTemp, *lpDest;
1086
1087     TRACE("(%p %d %p)\n", hdpa, i, p);
1088
1089     if ((!hdpa) || (i < 0))
1090         return -1;
1091
1092     if (!hdpa->ptrs) {
1093         hdpa->ptrs =
1094             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1095                                 2 * hdpa->nGrow * sizeof(LPVOID));
1096         if (!hdpa->ptrs)
1097             return -1;
1098         hdpa->nMaxCount = hdpa->nGrow * 2;
1099         nIndex = 0;
1100     }
1101     else {
1102         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1103             TRACE("-- resizing\n");
1104             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1105             nSize = nNewItems * sizeof(LPVOID);
1106
1107             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1108                                            hdpa->ptrs, nSize);
1109             if (!lpTemp)
1110                 return -1;
1111             hdpa->nMaxCount = nNewItems;
1112             hdpa->ptrs = lpTemp;
1113         }
1114
1115         if (i >= hdpa->nItemCount) {
1116             nIndex = hdpa->nItemCount;
1117             TRACE("-- appending at %d\n", nIndex);
1118         }
1119         else {
1120             TRACE("-- inserting at %d\n", i);
1121             lpTemp = hdpa->ptrs + i;
1122             lpDest = lpTemp + 1;
1123             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1124             TRACE("-- move dest=%p src=%p size=%x\n",
1125                    lpDest, lpTemp, nSize);
1126             memmove (lpDest, lpTemp, nSize);
1127             nIndex = i;
1128         }
1129     }
1130
1131     /* insert item */
1132     hdpa->nItemCount++;
1133     hdpa->ptrs[nIndex] = p;
1134
1135     return nIndex;
1136 }
1137
1138
1139 /**************************************************************************
1140  * DPA_SetPtr [COMCTL32.335]
1141  *
1142  * Sets a pointer in the pointer array
1143  *
1144  * PARAMS
1145  *     hdpa [I] handle (pointer) to the pointer array
1146  *     i    [I] index of the pointer that will be set
1147  *     p    [I] pointer to be set
1148  *
1149  * RETURNS
1150  *     Success: TRUE
1151  *     Failure: FALSE
1152  */
1153
1154 BOOL WINAPI
1155 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1156 {
1157     LPVOID *lpTemp;
1158     
1159     TRACE("(%p %d %p)\n", hdpa, i, p);
1160
1161     if ((!hdpa) || i < 0)
1162         return FALSE;
1163       
1164     if (hdpa->nItemCount <= i) {
1165         /* within the old array */
1166         if (hdpa->nMaxCount > i) {
1167             /* within the allocated space, set a new boundary */
1168             hdpa->nItemCount = i;
1169         }
1170         else {
1171             /* resize the block of memory */
1172             INT nNewItems =
1173                 hdpa->nGrow * ((INT)((i - 1) / hdpa->nGrow) + 1);
1174             INT nSize = nNewItems * sizeof(LPVOID);
1175
1176             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1177                                            hdpa->ptrs, nSize);
1178             if (!lpTemp)
1179                 return FALSE;
1180
1181             hdpa->nItemCount = nNewItems;
1182             hdpa->ptrs = lpTemp;        
1183         }    
1184     }
1185
1186     /* put the new entry in */
1187     hdpa->ptrs[i] = p;
1188
1189     return TRUE;
1190 }
1191
1192
1193 /**************************************************************************
1194  * DPA_DeletePtr [COMCTL32.336]
1195  *
1196  * Removes a pointer from the pointer array.
1197  *
1198  * PARAMS
1199  *     hdpa [I] handle (pointer) to the pointer array
1200  *     i    [I] index of the pointer that will be deleted
1201  *
1202  * RETURNS
1203  *     Success: deleted pointer
1204  *     Failure: NULL
1205  */
1206
1207 LPVOID WINAPI
1208 DPA_DeletePtr (const HDPA hdpa, INT i)
1209 {
1210     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1211     INT  nSize;
1212     
1213     TRACE("(%p %d)\n", hdpa, i);
1214
1215     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1216         return NULL;
1217
1218     lpTemp = hdpa->ptrs[i];
1219
1220     /* do we need to move ?*/
1221     if (i < hdpa->nItemCount - 1) {
1222         lpDest = hdpa->ptrs + i;
1223         lpSrc = lpDest + 1;
1224         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1225         TRACE("-- move dest=%p src=%p size=%x\n",
1226                lpDest, lpSrc, nSize);
1227         memmove (lpDest, lpSrc, nSize);
1228     }
1229     
1230     hdpa->nItemCount --;
1231     
1232     /* free memory ?*/
1233     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1234         INT nNewItems = MIN(hdpa->nGrow * 2, hdpa->nItemCount);
1235         nSize = nNewItems * sizeof(LPVOID);
1236         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1237                                       hdpa->ptrs, nSize);
1238         if (!lpDest)
1239             return NULL;
1240
1241         hdpa->nMaxCount = nNewItems;
1242         hdpa->ptrs = (LPVOID*)lpDest;         
1243     }
1244
1245     return lpTemp;
1246 }
1247
1248
1249 /**************************************************************************
1250  * DPA_DeleteAllPtrs [COMCTL32.337]
1251  *
1252  * Removes all pointers and reinitializes the array.
1253  *
1254  * PARAMS
1255  *     hdpa [I] handle (pointer) to the pointer array
1256  *
1257  * RETURNS
1258  *     Success: TRUE
1259  *     Failure: FALSE
1260  */
1261
1262 BOOL WINAPI
1263 DPA_DeleteAllPtrs (const HDPA hdpa)
1264 {
1265     TRACE("(%p)\n", hdpa);
1266
1267     if (!hdpa) 
1268         return FALSE;
1269
1270     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1271         return FALSE;
1272
1273     hdpa->nItemCount = 0;
1274     hdpa->nMaxCount = hdpa->nGrow * 2;
1275     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1276                                      hdpa->nMaxCount * sizeof(LPVOID));
1277
1278     return TRUE;
1279 }
1280
1281
1282 /**************************************************************************
1283  * DPA_QuickSort [Internal]
1284  *
1285  * Ordinary quicksort (used by DPA_Sort).
1286  *
1287  * PARAMS
1288  *     lpPtrs     [I] pointer to the pointer array
1289  *     l          [I] index of the "left border" of the partition
1290  *     r          [I] index of the "right border" of the partition
1291  *     pfnCompare [I] pointer to the compare function
1292  *     lParam     [I] user defined value (3rd parameter in compare function)
1293  *
1294  * RETURNS
1295  *     NONE
1296  */
1297
1298 static VOID
1299 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1300                PFNDPACOMPARE pfnCompare, LPARAM lParam)
1301 {
1302     LPVOID t, v;
1303     INT  i, j;
1304
1305     TRACE("l=%i r=%i\n", l, r);
1306  
1307     i = l;
1308     j = r;
1309     v = lpPtrs[(int)(l+r)/2];
1310     do {
1311         while ((pfnCompare)(lpPtrs[i], v, lParam) > 0) i++;
1312         while ((pfnCompare)(lpPtrs[j], v, lParam) < 0) j--;
1313         if (i <= j) 
1314         {
1315             t = lpPtrs[i];
1316             lpPtrs[i++] = lpPtrs[j];
1317             lpPtrs[j--] = t;
1318         }
1319     } while (i <= j);
1320     if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
1321     if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
1322 }
1323
1324
1325 /**************************************************************************
1326  * DPA_Sort [COMCTL32.338]
1327  *
1328  * Sorts a pointer array using a user defined compare function
1329  *
1330  * PARAMS
1331  *     hdpa       [I] handle (pointer) to the pointer array
1332  *     pfnCompare [I] pointer to the compare function
1333  *     lParam     [I] user defined value (3rd parameter of compare function)
1334  *
1335  * RETURNS
1336  *     Success: TRUE
1337  *     Failure: FALSE
1338  */
1339
1340 BOOL WINAPI
1341 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1342 {
1343     if (!hdpa || !pfnCompare)
1344         return FALSE;
1345
1346     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1347
1348     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1349         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1350                        pfnCompare, lParam);
1351
1352     return TRUE;
1353 }
1354
1355
1356 /**************************************************************************
1357  * DPA_Search [COMCTL32.339]
1358  *
1359  * Searches a pointer array for a specified pointer
1360  *
1361  * PARAMS
1362  *     hdpa       [I] handle (pointer) to the pointer array
1363  *     pFind      [I] pointer to search for
1364  *     nStart     [I] start index
1365  *     pfnCompare [I] pointer to the compare function
1366  *     lParam     [I] user defined value (3rd parameter of compare function)
1367  *     uOptions   [I] search options
1368  *
1369  * RETURNS
1370  *     Success: index of the pointer in the array.
1371  *     Failure: -1
1372  *
1373  * NOTES
1374  *     Binary search taken from R.Sedgewick "Algorithms in C"!
1375  *     Function is NOT tested!
1376  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
1377  */
1378
1379 INT WINAPI
1380 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1381             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1382 {
1383     if (!hdpa || !pfnCompare || !pFind)
1384         return -1;
1385
1386     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1387            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1388
1389     if (uOptions & DPAS_SORTED) {
1390         /* array is sorted --> use binary search */
1391         INT l, r, x, n;
1392         LPVOID *lpPtr;
1393
1394         TRACE("binary search\n");
1395
1396         l = (nStart == -1) ? 0 : nStart;
1397         r = hdpa->nItemCount - 1;
1398         lpPtr = hdpa->ptrs;
1399         while (r >= l) {
1400             x = (l + r) / 2;
1401             n = (pfnCompare)(pFind, lpPtr[x], lParam);
1402             if (n < 0)
1403                 r = x - 1;
1404             else
1405                 l = x + 1;
1406             if (n == 0) {
1407                 TRACE("-- ret=%d\n", n);
1408                 return n;
1409             }
1410         }
1411
1412         if (uOptions & DPAS_INSERTBEFORE) {
1413             TRACE("-- ret=%d\n", r);
1414             return r;
1415         }
1416
1417         if (uOptions & DPAS_INSERTAFTER) {
1418             TRACE("-- ret=%d\n", l);
1419             return l;
1420         }
1421     }
1422     else {
1423         /* array is not sorted --> use linear search */
1424         LPVOID *lpPtr;
1425         INT  nIndex;
1426
1427         TRACE("linear search\n");
1428         
1429         nIndex = (nStart == -1)? 0 : nStart;
1430         lpPtr = hdpa->ptrs;
1431         for (; nIndex < hdpa->nItemCount; nIndex++) {
1432             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1433                 TRACE("-- ret=%d\n", nIndex);
1434                 return nIndex;
1435             }
1436         }
1437     }
1438
1439     TRACE("-- not found: ret=-1\n");
1440     return -1;
1441 }
1442
1443
1444 /**************************************************************************
1445  * DPA_CreateEx [COMCTL32.340]
1446  *
1447  * Creates a dynamic pointer array using the specified size and heap.
1448  *
1449  * PARAMS
1450  *     nGrow [I] number of items by which the array grows when it is filled
1451  *     hHeap [I] handle to the heap where the array is stored
1452  *
1453  * RETURNS
1454  *     Success: handle (pointer) to the pointer array.
1455  *     Failure: NULL
1456  */
1457
1458 HDPA WINAPI
1459 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1460 {
1461     HDPA hdpa;
1462
1463     TRACE("(%d 0x%x)\n", nGrow, hHeap);
1464
1465     if (hHeap)
1466         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1467     else
1468         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1469
1470     if (hdpa) {
1471         hdpa->nGrow = MIN(8, nGrow);
1472         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1473         hdpa->nMaxCount = hdpa->nGrow * 2;
1474         hdpa->ptrs =
1475             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1476                                 hdpa->nMaxCount * sizeof(LPVOID));
1477     }
1478
1479     TRACE("-- %p\n", hdpa);
1480
1481     return hdpa;
1482 }
1483
1484
1485 /**************************************************************************
1486  * Notification functions
1487  */
1488
1489 typedef struct tagNOTIFYDATA
1490 {
1491     HWND hwndFrom;
1492     HWND hwndTo;
1493     DWORD  dwParam3;
1494     DWORD  dwParam4;
1495     DWORD  dwParam5;
1496     DWORD  dwParam6;
1497 } NOTIFYDATA, *LPNOTIFYDATA;
1498
1499
1500 /**************************************************************************
1501  * DoNotify [Internal]
1502  */
1503
1504 static LRESULT
1505 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1506 {
1507     NMHDR nmhdr;
1508     LPNMHDR lpNmh = NULL;
1509     UINT idFrom = 0;
1510
1511     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1512            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1513            lpNotify->dwParam5);
1514
1515     if (!lpNotify->hwndTo)
1516         return 0;
1517
1518     if (lpNotify->hwndFrom == -1) {
1519         lpNmh = lpHdr;
1520         idFrom = lpHdr->idFrom;
1521     }
1522     else {
1523         if (lpNotify->hwndFrom) {
1524             HWND hwndParent = GetParent (lpNotify->hwndFrom);
1525             if (hwndParent) {
1526                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1527                 if (hwndParent)
1528                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1529             }
1530         }
1531
1532         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1533
1534         lpNmh->hwndFrom = lpNotify->hwndFrom;
1535         lpNmh->idFrom = idFrom;
1536         lpNmh->code = uCode;
1537     }
1538
1539     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1540 }
1541
1542
1543 /**************************************************************************
1544  * SendNotify [COMCTL32.341]
1545  *
1546  * PARAMS
1547  *     hwndFrom [I]
1548  *     hwndTo   [I]
1549  *     uCode    [I]
1550  *     lpHdr    [I]
1551  *
1552  * RETURNS
1553  *     Success: return value from notification
1554  *     Failure: 0
1555  */
1556
1557 LRESULT WINAPI
1558 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1559                      UINT uCode, LPNMHDR lpHdr)
1560 {
1561     NOTIFYDATA notify;
1562
1563     TRACE("(0x%04x 0x%04x %d %p)\n",
1564            hwndFrom, hwndTo, uCode, lpHdr);
1565
1566     notify.hwndFrom = hwndFrom;
1567     notify.hwndTo   = hwndTo;
1568     notify.dwParam5 = 0;
1569     notify.dwParam6 = 0;
1570
1571     return DoNotify (&notify, uCode, lpHdr);
1572 }
1573
1574
1575 /**************************************************************************
1576  * SendNotifyEx [COMCTL32.342]
1577  *
1578  * PARAMS
1579  *     hwndFrom [I]
1580  *     hwndTo   [I]
1581  *     uCode    [I]
1582  *     lpHdr    [I]
1583  *     dwParam5 [I]
1584  *
1585  * RETURNS
1586  *     Success: return value from notification
1587  *     Failure: 0
1588  */
1589
1590 LRESULT WINAPI
1591 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1592                        LPNMHDR lpHdr, DWORD dwParam5)
1593 {
1594     NOTIFYDATA notify;
1595     HWND hwndNotify;
1596
1597     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1598            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1599
1600     hwndNotify = hwndTo;
1601     if (!hwndTo) {
1602         if (IsWindow (hwndFrom)) {
1603             hwndNotify = GetParent (hwndFrom);
1604             if (!hwndNotify)
1605                 return 0;
1606         }
1607     }
1608
1609     notify.hwndFrom = hwndFrom;
1610     notify.hwndTo   = hwndNotify;
1611     notify.dwParam5 = dwParam5;
1612     notify.dwParam6 = 0;
1613
1614     return DoNotify (&notify, uCode, lpHdr);
1615 }
1616
1617
1618 /**************************************************************************
1619  * StrChrA [COMCTL32.350]
1620  *
1621  */
1622
1623 LPSTR WINAPI
1624 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
1625 {
1626     return strchr (lpString, cChar);
1627 }
1628
1629
1630 /**************************************************************************
1631  * StrStrIA [COMCTL32.355]
1632  */
1633
1634 LPSTR WINAPI
1635 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
1636 {
1637     INT len1, len2, i;
1638     CHAR  first;
1639
1640     if (*lpStr2 == 0)
1641         return ((LPSTR)lpStr1);
1642     len1 = 0;
1643     while (lpStr1[len1] != 0) ++len1;
1644     len2 = 0;
1645     while (lpStr2[len2] != 0) ++len2;
1646     if (len2 == 0)
1647         return ((LPSTR)(lpStr1 + len1));
1648     first = tolower (*lpStr2);
1649     while (len1 >= len2) {
1650         if (tolower(*lpStr1) == first) {
1651             for (i = 1; i < len2; ++i)
1652                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
1653                     break;
1654             if (i >= len2)
1655                 return ((LPSTR)lpStr1);
1656         }
1657         ++lpStr1; --len1;
1658     }
1659     return (NULL);
1660 }
1661
1662
1663 /**************************************************************************
1664  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
1665  */
1666
1667 INT WINAPI
1668 COMCTL32_StrToIntA (LPSTR lpString)
1669 {
1670     return atoi(lpString);
1671 }
1672
1673
1674 /**************************************************************************
1675  * DPA_EnumCallback [COMCTL32.385]
1676  *
1677  * Enumerates all items in a dynamic pointer array.
1678  *
1679  * PARAMS
1680  *     hdpa     [I] handle to the dynamic pointer array
1681  *     enumProc [I]
1682  *     lParam   [I] 
1683  *
1684  * RETURNS
1685  *     none
1686  */
1687
1688 VOID WINAPI
1689 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1690 {
1691     INT i;
1692
1693     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1694
1695     if (!hdpa)
1696         return;
1697     if (hdpa->nItemCount <= 0)
1698         return;
1699
1700     for (i = 0; i < hdpa->nItemCount; i++) {
1701         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
1702             return;
1703     }
1704
1705     return;
1706 }
1707
1708
1709 /**************************************************************************
1710  * DPA_DestroyCallback [COMCTL32.386]
1711  *
1712  * Enumerates all items in a dynamic pointer array and destroys it.
1713  *
1714  * PARAMS
1715  *     hdpa     [I] handle to the dynamic pointer array
1716  *     enumProc [I]
1717  *     lParam   [I]
1718  *
1719  * RETURNS
1720  *     Success: TRUE
1721  *     Failure: FALSE
1722  */
1723
1724 BOOL WINAPI
1725 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1726 {
1727     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1728
1729     DPA_EnumCallback (hdpa, enumProc, lParam);
1730
1731     return DPA_Destroy (hdpa);
1732 }
1733
1734
1735 /**************************************************************************
1736  * DSA_EnumCallback [COMCTL32.387]
1737  *
1738  * Enumerates all items in a dynamic storage array.
1739  *
1740  * PARAMS
1741  *     hdsa     [I] handle to the dynamic storage array
1742  *     enumProc [I]
1743  *     lParam   [I]
1744  *
1745  * RETURNS
1746  *     none
1747  */
1748
1749 VOID WINAPI
1750 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1751 {
1752     INT i;
1753
1754     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1755
1756     if (!hdsa)
1757         return;
1758     if (hdsa->nItemCount <= 0)
1759         return;
1760
1761     for (i = 0; i < hdsa->nItemCount; i++) {
1762         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
1763         if ((enumProc)(lpItem, lParam) == 0)
1764             return;
1765     }
1766
1767     return;
1768 }
1769
1770
1771 /**************************************************************************
1772  * DSA_DestroyCallback [COMCTL32.388]
1773  *
1774  * Enumerates all items in a dynamic storage array and destroys it.
1775  *
1776  * PARAMS
1777  *     hdsa     [I] handle to the dynamic storage array
1778  *     enumProc [I]
1779  *     lParam   [I]
1780  *
1781  * RETURNS
1782  *     Success: TRUE
1783  *     Failure: FALSE
1784  */
1785
1786 BOOL WINAPI
1787 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1788 {
1789     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1790
1791     DSA_EnumCallback (hdsa, enumProc, lParam);
1792
1793     return DSA_Destroy (hdsa);
1794 }
1795
1796 /**************************************************************************
1797  * StrCSpnA [COMCTL32.356]
1798  *
1799  */
1800 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
1801   return strcspn(lpStr, lpSet);
1802 }
1803
1804 /**************************************************************************
1805  * StrChrW [COMCTL32.358]
1806  *
1807  */
1808 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
1809   return CRTDLL_wcschr(lpStart, wMatch);
1810 }
1811
1812 /**************************************************************************
1813  * StrCmpNA [COMCTL32.352]
1814  *
1815  */
1816 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
1817   return lstrncmpA(lpStr1, lpStr2, nChar);
1818 }
1819
1820 /**************************************************************************
1821  * StrCmpNW [COMCTL32.360]
1822  *
1823  */
1824 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
1825   return lstrncmpW(lpStr1, lpStr2, nChar);
1826 }
1827
1828 /**************************************************************************
1829  * StrRChrA [COMCTL32.351]
1830  *
1831  */
1832 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch) {
1833   return lstrrchr(lpStart, lpEnd, wMatch); 
1834 }
1835
1836 /**************************************************************************
1837  * StrRChrW [COMCTL32.359]
1838  *
1839  */
1840 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch) {
1841   return lstrrchrw(lpStart, lpEnd, wMatch); 
1842 }
1843
1844 /**************************************************************************
1845  * StrStrA [COMCTL32.354]
1846  *
1847  */
1848 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
1849   return strstr(lpFirst, lpSrch);
1850 }
1851
1852 /**************************************************************************
1853  * StrStrW [COMCTL32.362]
1854  *
1855  */
1856 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
1857   return strstrw(lpFirst, lpSrch);
1858 }
1859
1860 /**************************************************************************
1861  * StrSpnW [COMCTL32.364]
1862  *
1863  */
1864 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
1865   LPWSTR lpLoop = lpStr;
1866
1867   /* validate ptr */
1868   if ((lpStr == 0) || (lpSet == 0)) return 0;
1869
1870 /* while(*lpLoop) { if lpLoop++; } */
1871
1872   for(; (*lpLoop != 0); lpLoop++)
1873     if( CRTDLL_wcschr(lpSet, *(WORD*)lpLoop))
1874       return (INT)(lpLoop-lpStr);
1875   
1876   return (INT)(lpLoop-lpStr);
1877 }
1878
1879 /*************************************************************************
1880  * DPA_LoadStream [COMCTL32.9]
1881  *
1882  * NOTE: Ordinal is only accurate for Win98 / IE 4 and later
1883  */
1884
1885 DWORD WINAPI DPA_LoadStream(HDPA *hDpa, DWORD pfnDpaLoadCallback, DWORD param3, DWORD param4)
1886 {
1887   FIXME("(%p %lx %lx %lx): partial stub!\n", hDpa, pfnDpaLoadCallback, param3, param4);
1888
1889  *hDpa = DPA_Create(8);
1890
1891   return(0);
1892 }
1893
1894 /************************************************************************
1895  * DPA_SaveStream [COMCTL32.10]
1896  *
1897  * NOTE: Ordinal is only accurate for Win98 / IE 4 and later
1898  */
1899
1900 DWORD WINAPI DPA_SaveStream(DWORD param1, DWORD param2, DWORD param3, DWORD param4)
1901 {
1902   FIXME("(%lx %lx %lx %lx): stub!\n", param1, param2, param3, param4);
1903
1904   return(0);
1905 }