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