Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[wine] / dlls / comctl32 / comctl32undoc.c
1 /*
2  * Undocumented functions from COMCTL32.DLL
3  *
4  * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
5  *           1998 Juergen Schmied <j.schmied@metronet.de>
6  * NOTES
7  *     All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
8  *     Do NOT rely on names or contents of undocumented structures and types!!!
9  *     These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
10  *     COMCTL32.DLL (internally).
11  *
12  * TODO
13  *     - Add more functions.
14  *     - Write some documentation.
15  */
16
17 #include <string.h>
18 #include <stdlib.h> /* atoi */
19 #include <ctype.h>
20
21 #include "winbase.h"
22 #include "winerror.h"
23 #include "objbase.h"
24 #include "commctrl.h"
25 #include "crtdll.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(commctrl)
29
30
31 extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
32
33 /*
34  * We put some function prototypes here that don't seem to belong in
35  * any header file. When they find their place, we can remove them.
36  */
37 extern LPSTR WINAPI lstrrchr(LPCSTR, LPCSTR, WORD);
38 extern LPWSTR WINAPI lstrrchrw(LPCWSTR, LPCWSTR, WORD);
39
40
41 typedef struct _STREAMDATA
42 {
43     DWORD dwSize;
44     DWORD dwData2;
45     DWORD dwItems;
46 } STREAMDATA, *PSTREAMDATA;
47
48 typedef struct _LOADDATA
49 {
50     INT   nCount;
51     PVOID ptr;
52 } LOADDATA, *LPLOADDATA;
53
54 typedef HRESULT(CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
55
56
57 /**************************************************************************
58  * DPA_LoadStream [COMCTL32.9]
59  *
60  * Loads a dynamic pointer array from a stream
61  *
62  * PARAMS
63  *     phDpa    [O] pointer to a handle to a dynamic pointer array
64  *     loadProc [I] pointer to a callback function
65  *     pStream  [I] pointer to a stream
66  *     lParam   [I] application specific value
67  *
68  * NOTES
69  *     No more information available yet!
70  */
71
72 HRESULT WINAPI
73 DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
74 {
75     HRESULT errCode;
76     LARGE_INTEGER position;
77     ULARGE_INTEGER newPosition;
78     STREAMDATA  streamData;
79     LOADDATA loadData;
80     ULONG ulRead;
81     HDPA hDpa;
82     PVOID *ptr;
83
84     FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
85            phDpa, loadProc, pStream, lParam);
86
87     if (!phDpa || !loadProc || !pStream)
88         return E_INVALIDARG;
89
90     *phDpa = (HDPA)NULL;
91
92     position.s.LowPart = 0;
93     position.s.HighPart = 0;
94
95     errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
96     if (errCode != S_OK)
97         return errCode;
98
99     errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
100     if (errCode != S_OK)
101         return errCode;
102
103     FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
104            streamData.dwSize, streamData.dwData2, streamData.dwItems);
105
106     if (lParam < sizeof(STREAMDATA) ||
107         streamData.dwSize < sizeof(STREAMDATA) ||
108         streamData.dwData2 < 1) {
109         errCode = E_FAIL;
110     }
111
112     /* create the dpa */
113     hDpa = DPA_Create (streamData.dwItems);
114     if (!hDpa)
115         return E_OUTOFMEMORY;
116
117     if (!DPA_Grow (hDpa, streamData.dwItems))
118         return E_OUTOFMEMORY;
119
120     /* load data from the stream into the dpa */
121     ptr = hDpa->ptrs;
122     for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
123         errCode = (loadProc)(&loadData, pStream, lParam);
124         if (errCode != S_OK) {
125             errCode = S_FALSE;
126             break;
127         }
128
129         *ptr = loadData.ptr;
130         ptr++;
131     }
132
133     /* set the number of items */
134     hDpa->nItemCount = loadData.nCount;
135
136     /* store the handle to the dpa */
137     *phDpa = hDpa;
138     FIXME ("new hDpa=%p\n", hDpa);
139
140     return errCode;
141 }
142
143
144 /**************************************************************************
145  * DPA_SaveStream [COMCTL32.10]
146  *
147  * Saves a dynamic pointer array to a stream
148  *
149  * PARAMS
150  *     hDpa     [I] handle to a dynamic pointer array
151  *     loadProc [I] pointer to a callback function
152  *     pStream  [I] pointer to a stream
153  *     lParam   [I] application specific value
154  *
155  * NOTES
156  *     No more information available yet!
157  */
158
159 HRESULT WINAPI
160 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
161 {
162
163     FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
164            hDpa, loadProc, pStream, lParam);
165
166     return E_FAIL;
167 }
168
169
170 /**************************************************************************
171  * DPA_Merge [COMCTL32.11]
172  *
173  * PARAMS
174  *     hdpa1    [I] handle to a dynamic pointer array
175  *     hdpa2    [I] handle to a dynamic pointer array
176  *     dwFlags  [I] flags
177  *     pfnSort  [I] pointer to sort function
178  *     pfnMerge [I] pointer to merge function
179  *     lParam   [I] application specific value
180  *
181  * NOTES
182  *     No more information available yet!
183  */
184
185 BOOL WINAPI
186 DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
187            PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
188 {
189     INT nCount;
190
191 #if 0    /* these go with the "incomplete implementation" below */
192     LPVOID pWork1, pWork2;
193     INT nResult;
194     INT nIndex;
195     INT nNewItems;
196 #endif
197
198     TRACE("(%p %p %08lx %p %p %08lx): semi stub!\n",
199            hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
200
201     if (IsBadWritePtr (hdpa1, sizeof(DPA)))
202         return FALSE;
203
204     if (IsBadWritePtr (hdpa2, sizeof(DPA)))
205         return FALSE;
206
207     if (IsBadCodePtr ((FARPROC)pfnCompare))
208         return FALSE;
209
210     if (IsBadCodePtr ((FARPROC)pfnMerge))
211         return FALSE;
212
213     if (dwFlags & DPAM_SORT) {
214         TRACE("sorting dpa's!\n");
215         if (hdpa1->nItemCount > 0)
216         DPA_Sort (hdpa1, pfnCompare, lParam);
217         TRACE ("dpa 1 sorted!\n");
218         if (hdpa2->nItemCount > 0)
219         DPA_Sort (hdpa2, pfnCompare, lParam);
220         TRACE ("dpa 2 sorted!\n");
221     }
222
223     if (hdpa2->nItemCount < 1)
224         return TRUE;
225
226     TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
227            hdpa1->nItemCount, hdpa2->nItemCount);
228
229
230     /* preliminary hack - simply append the pointer list hdpa2 to hdpa1*/
231     for (nCount = 0; nCount < hdpa2->nItemCount; nCount++)
232         DPA_InsertPtr (hdpa1, hdpa1->nItemCount + 1, hdpa2->ptrs[nCount]);
233
234 #if 0
235     /* incomplete implementation */
236
237     pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
238     pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
239
240     nIndex = hdpa1->nItemCount - 1;
241     nCount = hdpa2->nItemCount - 1;
242
243     do
244     {
245         nResult = (pfnCompare)(pWork1, pWork2, lParam);
246
247         if (nResult == 0)
248         {
249             PVOID ptr;
250
251             ptr = (pfnMerge)(1, pWork1, pWork2, lParam);
252             if (!ptr)
253                 return FALSE;
254
255             nCount--;
256             pWork2--;
257             pWork1 = ptr;
258         }
259         else if (nResult < 0)
260         {
261             if (!dwFlags & 8)
262             {
263                 PVOID ptr;
264
265                 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
266
267                 (pfnMerge)(2, ptr, NULL, lParam);
268             }
269         }
270         else
271         {
272             if (!dwFlags & 4)
273             {
274                 PVOID ptr;
275
276                 ptr = (pfnMerge)(3, pWork2, NULL, lParam);
277                 if (!ptr)
278                     return FALSE;
279                 DPA_InsertPtr (hdpa1, nIndex, ptr);
280     }
281             nCount--;
282             pWork2--;
283         }
284
285         nIndex--;
286         pWork1--;
287
288     }
289     while (nCount >= 0);
290 #endif
291
292     return TRUE;
293 }
294
295
296 /**************************************************************************
297  * Alloc [COMCTL32.71]
298  *
299  * Allocates memory block from the dll's private heap
300  *
301  * PARAMS
302  *     dwSize [I] size of the allocated memory block
303  *
304  * RETURNS
305  *     Success: pointer to allocated memory block
306  *     Failure: NULL
307  */
308
309 LPVOID WINAPI
310 COMCTL32_Alloc (DWORD dwSize)
311 {
312     LPVOID lpPtr;
313
314     TRACE("(0x%lx)\n", dwSize);
315
316     lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
317
318     TRACE("-- ret=%p\n", lpPtr);
319
320     return lpPtr;
321 }
322
323
324 /**************************************************************************
325  * ReAlloc [COMCTL32.72]
326  *
327  * Changes the size of an allocated memory block or allocates a memory
328  * block using the dll's private heap.
329  *
330  * PARAMS
331  *     lpSrc  [I] pointer to memory block which will be resized
332  *     dwSize [I] new size of the memory block.
333  *
334  * RETURNS
335  *     Success: pointer to the resized memory block
336  *     Failure: NULL
337  *
338  * NOTES
339  *     If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
340  *     block like COMCTL32_Alloc.
341  */
342
343 LPVOID WINAPI
344 COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
345 {
346     LPVOID lpDest;
347
348     TRACE("(%p 0x%08lx)\n", lpSrc, dwSize);
349
350     if (lpSrc)
351         lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
352     else
353         lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
354
355     TRACE("-- ret=%p\n", lpDest);
356
357     return lpDest;
358 }
359
360
361 /**************************************************************************
362  * Free [COMCTL32.73]
363  *
364  * Frees an allocated memory block from the dll's private heap.
365  *
366  * PARAMS
367  *     lpMem [I] pointer to memory block which will be freed
368  *
369  * RETURNS
370  *     Success: TRUE
371  *     Failure: FALSE
372  */
373
374 BOOL WINAPI
375 COMCTL32_Free (LPVOID lpMem)
376 {
377     TRACE("(%p)\n", lpMem);
378
379     return HeapFree (COMCTL32_hHeap, 0, lpMem);
380 }
381
382
383 /**************************************************************************
384  * GetSize [COMCTL32.74]
385  *
386  * Retrieves the size of the specified memory block from the dll's
387  * private heap.
388  *
389  * PARAMS
390  *     lpMem [I] pointer to an allocated memory block
391  *
392  * RETURNS
393  *     Success: size of the specified memory block
394  *     Failure: 0
395  */
396
397 DWORD WINAPI
398 COMCTL32_GetSize (LPVOID lpMem)
399 {
400     TRACE("(%p)\n", lpMem);
401
402     return HeapSize (COMCTL32_hHeap, 0, lpMem);
403 }
404
405
406 /**************************************************************************
407  * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
408  * lists.
409  *
410  * Stored in the reg. as a set of values under a single key.  Each item in the
411  * list has a value name that is a single char. 'a' - 'z', '{', '|' or '}'.
412  * The order of the list is stored with value name 'MRUList' which is a string
413  * containing the value names (i.e. 'a', 'b', etc.) in the relevant order.
414  */
415
416 typedef struct tagCREATEMRULIST
417 {
418     DWORD  cbSize;        /* size of struct */
419     DWORD  nMaxItems;     /* max no. of items in list */
420     DWORD  dwFlags;       /* see below */
421     HKEY   hKey;          /* root reg. key under which list is saved */
422     LPCSTR lpszSubKey;    /* reg. subkey */
423     PROC   lpfnCompare;   /* item compare proc */
424 } CREATEMRULIST, *LPCREATEMRULIST;
425
426 /* dwFlags */
427 #define MRUF_STRING_LIST  0 /* list will contain strings */
428 #define MRUF_BINARY_LIST  1 /* list will contain binary data */
429 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
430
431 /* If list is a string list lpfnCompare has the following prototype
432  * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
433  * for binary lists the prototype is
434  * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
435  * where cbData is the no. of bytes to compare.
436  * Need to check what return value means identical - 0?
437  */
438
439 typedef struct tagMRU
440 {
441     DWORD  dwParam1;  /* some kind of flag */
442     DWORD  dwParam2;
443     DWORD  dwParam3;
444     HKEY   hkeyMRU;
445     LPCSTR lpszSubKey;
446     DWORD  dwParam6;
447 } MRU, *HMRU;
448
449 HANDLE WINAPI
450 CreateMRUListLazyA (LPCREATEMRULIST lpcml, DWORD dwParam2,
451                     DWORD dwParam3, DWORD dwParam4);
452
453
454 /**************************************************************************
455  *              CreateMRUListA [COMCTL32.151]
456  *
457  * PARAMS
458  *     lpcml [I] ptr to CREATEMRULIST structure.
459  *
460  * RETURNS
461  *     Handle to MRU list.
462  */
463 HANDLE WINAPI
464 CreateMRUListA (LPCREATEMRULIST lpcml)
465 {
466      return CreateMRUListLazyA (lpcml, 0, 0, 0);
467 }
468
469 /**************************************************************************
470  *              FreeMRUListA [COMCTL32.152]
471  *
472  * PARAMS
473  *     hMRUList [I] Handle to list.
474  *
475  */
476 DWORD WINAPI
477 FreeMRUListA (HANDLE hMRUList)
478 {
479     FIXME("(%08x) empty stub!\n", hMRUList);
480
481 #if 0
482     if (!(hmru->dwParam1 & 1001)) {
483         RegSetValueExA (hmru->hKeyMRU, "MRUList", 0, REG_SZ,
484                           hmru->lpszMRUString,
485                           lstrlenA (hmru->lpszMRUString));
486     }
487
488
489     RegClosKey (hmru->hkeyMRU
490     COMCTL32_Free32 (hmru->lpszMRUString);
491 #endif
492
493     return COMCTL32_Free ((LPVOID)hMRUList);
494 }
495
496
497 /**************************************************************************
498  *              AddMRUData [COMCTL32.167]
499  * 
500  * Add item to MRU binary list.  If item already exists in list them it is
501  * simply moved up to the top of the list and not added again.  If list is
502  * full then the least recently used item is removed to make room.
503  *
504  * PARAMS
505  *     hList [I] Handle to list.
506  *     lpData [I] ptr to data to add.
507  *     cbData [I] no. of bytes of data.
508  *
509  * RETURNS
510  *     No. corresponding to registry name where value is stored 'a' -> 0 etc.
511  *     -1 on error.
512  */
513 INT WINAPI
514 AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
515 {
516     FIXME("(%08x, %p, %ld) empty stub!\n", hList, lpData, cbData);
517
518     return 0;
519 }
520
521 /**************************************************************************
522  *              AddMRUStringA [COMCTL32.153]
523  * 
524  * Add item to MRU string list.  If item already exists in list them it is
525  * simply moved up to the top of the list and not added again.  If list is
526  * full then the least recently used item is removed to make room.
527  *
528  * PARAMS
529  *     hList [I] Handle to list.
530  *     lpszString [I] ptr to string to add.
531  *
532  * RETURNS
533  *     No. corresponding to registry name where value is stored 'a' -> 0 etc.
534  *     -1 on error.
535  */
536 INT WINAPI
537 AddMRUStringA(HANDLE hList, LPCSTR lpszString)
538 {
539     FIXME("(%08x, %s) empty stub!\n", hList, debugstr_a(lpszString));
540
541     return 0;
542 }
543
544 /**************************************************************************
545  *              DelMRUString [COMCTL32.156]
546  *
547  * Removes item from either string or binary list (despite its name)
548  *
549  * PARAMS
550  *    hList [I] list handle
551  *    nItemPos [I] item position to remove 0 -> MRU
552  *
553  * RETURNS
554  *    TRUE is successful, FALSE if nItemPos is out of range.
555  */
556 BOOL WINAPI
557 DelMRUString(HANDLE hList, INT nItemPos)
558 {
559     FIXME("(%08x, %d): stub\n", hList, nItemPos);
560     return TRUE;
561 }
562
563 /**************************************************************************
564  *                  FindMRUData [COMCTL32.169]
565  * 
566  * Searches binary list for item that matches lpData of length cbData.
567  * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
568  * corresponding to item's reg. name will be stored in it ('a' -> 0).
569  *
570  * PARAMS
571  *    hList [I] list handle
572  *    lpData [I] data to find
573  *    cbData [I] length of data
574  *    lpRegNum [O] position in registry (maybe NULL)
575  *
576  * RETURNS
577  *    Position in list 0 -> MRU.  -1 if item not found.
578  */
579 INT WINAPI
580 FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum)
581 {
582     FIXME("(%08x, %p, %ld, %p) empty stub!\n",
583            hList, lpData, cbData, lpRegNum);
584
585     return 0;
586 }
587
588 /**************************************************************************
589  *                  FindMRUStringA [COMCTL32.155]
590  * 
591  * Searches string list for item that matches lpszString.
592  * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
593  * corresponding to item's reg. name will be stored in it ('a' -> 0).
594  *
595  * PARAMS
596  *    hList [I] list handle
597  *    lpszString [I] string to find
598  *    lpRegNum [O] position in registry (maybe NULL)
599  *
600  * RETURNS
601  *    Position in list 0 -> MRU.  -1 if item not found.
602  */
603 INT WINAPI
604 FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
605 {
606     FIXME("(%08x, %s, %p) empty stub!\n", hList, debugstr_a(lpszString),
607           lpRegNum);
608
609     return 0;
610 }
611
612 /**************************************************************************
613  *                  CreateMRUListLazyA [COMCTL32.157]
614  */
615 HANDLE WINAPI
616 CreateMRUListLazyA (LPCREATEMRULIST lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
617 {
618     /* DWORD  dwLocal1;   *
619      * HKEY   hkeyResult; *
620      * DWORD  dwLocal3;   *
621      * LPVOID lMRU;       *
622      * DWORD  dwLocal5;   *
623      * DWORD  dwLocal6;   *
624      * DWORD  dwLocal7;   *
625      * DWORD  dwDisposition; */
626
627     /* internal variables */
628     LPVOID ptr;
629
630     FIXME("(%p) empty stub!\n", lpcml);
631
632     if (lpcml == NULL)
633         return 0;
634
635     if (lpcml->cbSize < sizeof(CREATEMRULIST))
636         return 0;
637
638     FIXME("(%lu %lu %lx %lx \"%s\" %p)\n",
639           lpcml->cbSize, lpcml->nMaxItems, lpcml->dwFlags,
640           (DWORD)lpcml->hKey, lpcml->lpszSubKey, lpcml->lpfnCompare);
641
642     /* dummy pointer creation */
643     ptr = COMCTL32_Alloc (32);
644
645     FIXME("-- ret = %p\n", ptr);
646
647     return (HANDLE)ptr;
648 }
649
650 /**************************************************************************
651  *                EnumMRUListA [COMCTL32.154]
652  * 
653  * Enumerate item in a list
654  *
655  * PARAMS
656  *    hList [I] list handle
657  *    nItemPos [I] item position to enumerate
658  *    lpBuffer [O] buffer to receive item
659  *    nBufferSize [I] size of buffer
660  *
661  * RETURNS
662  *    For binary lists specifies how many bytes were copied to buffer, for
663  *    string lists specifies full length of string.  Enumerating past the end
664  *    of list returns -1.
665  *    If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
666  *    the list. 
667  */
668 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
669 DWORD nBufferSize)
670 {
671     FIXME("(%08x, %d, %p, %ld): stub\n", hList, nItemPos, lpBuffer,
672           nBufferSize);
673     return 0;
674 }
675
676 /**************************************************************************
677  * Str_GetPtrA [COMCTL32.233]
678  *
679  * PARAMS
680  *     lpSrc   [I]
681  *     lpDest  [O]
682  *     nMaxLen [I]
683  *
684  * RETURNS
685  */
686
687 INT WINAPI
688 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
689 {
690     INT len;
691
692     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
693
694     if (!lpDest && lpSrc)
695         return lstrlenA (lpSrc);
696
697     if (nMaxLen == 0)
698         return 0;
699
700     if (lpSrc == NULL) {
701         lpDest[0] = '\0';
702         return 0;
703     }
704
705     len = lstrlenA (lpSrc);
706     if (len >= nMaxLen)
707         len = nMaxLen - 1;
708
709     RtlMoveMemory (lpDest, lpSrc, len);
710     lpDest[len] = '\0';
711
712     return len;
713 }
714
715
716 /**************************************************************************
717  * Str_SetPtrA [COMCTL32.234]
718  *
719  * PARAMS
720  *     lppDest [O]
721  *     lpSrc   [I]
722  *
723  * RETURNS
724  */
725
726 BOOL WINAPI
727 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
728 {
729     TRACE("(%p %p)\n", lppDest, lpSrc);
730  
731     if (lpSrc) {
732         LPSTR ptr = COMCTL32_ReAlloc (*lppDest, lstrlenA (lpSrc) + 1);
733         if (!ptr)
734             return FALSE;
735         lstrcpyA (ptr, lpSrc);
736         *lppDest = ptr;
737     }
738     else {
739         if (*lppDest) {
740             COMCTL32_Free (*lppDest);
741             *lppDest = NULL;
742         }
743     }
744
745     return TRUE;
746 }
747
748
749 /**************************************************************************
750  * Str_GetPtrW [COMCTL32.235]
751  *
752  * PARAMS
753  *     lpSrc   [I]
754  *     lpDest  [O]
755  *     nMaxLen [I]
756  *
757  * RETURNS
758  */
759
760 INT WINAPI
761 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
762 {
763     INT len;
764
765     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
766
767     if (!lpDest && lpSrc)
768         return lstrlenW (lpSrc);
769
770     if (nMaxLen == 0)
771         return 0;
772
773     if (lpSrc == NULL) {
774         lpDest[0] = L'\0';
775         return 0;
776     }
777
778     len = lstrlenW (lpSrc);
779     if (len >= nMaxLen)
780         len = nMaxLen - 1;
781
782     RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
783     lpDest[len] = L'\0';
784
785     return len;
786 }
787
788
789 /**************************************************************************
790  * Str_SetPtrW [COMCTL32.236]
791  *
792  * PARAMS
793  *     lpDest [O]
794  *     lpSrc  [I]
795  *
796  * RETURNS
797  */
798
799 BOOL WINAPI
800 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
801 {
802     TRACE("(%p %p)\n", lppDest, lpSrc);
803  
804     if (lpSrc) {
805         INT len = lstrlenW (lpSrc) + 1;
806         LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
807         if (!ptr)
808             return FALSE;
809         lstrcpyW (ptr, lpSrc);
810         *lppDest = ptr;
811     }
812     else {
813         if (*lppDest) {
814             COMCTL32_Free (*lppDest);
815             *lppDest = NULL;
816         }
817     }
818
819     return TRUE;
820 }
821
822
823 /**************************************************************************
824  * The DSA-API is a set of functions to create and manipulate arrays of
825  * fix sized memory blocks. These arrays can store any kind of data
826  * (strings, icons...).
827  */
828
829 /**************************************************************************
830  * DSA_Create [COMCTL32.320] Creates a dynamic storage array
831  *
832  * PARAMS
833  *     nSize [I] size of the array elements
834  *     nGrow [I] number of elements by which the array grows when it is filled
835  *
836  * RETURNS
837  *     Success: pointer to a array control structure. use this like a handle.
838  *     Failure: NULL
839  */
840
841 HDSA WINAPI
842 DSA_Create (INT nSize, INT nGrow)
843 {
844     HDSA hdsa;
845
846     TRACE("(size=%d grow=%d)\n", nSize, nGrow);
847
848     hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
849     if (hdsa)
850     {
851         hdsa->nItemCount = 0;
852         hdsa->pData = NULL;
853         hdsa->nMaxCount = 0;
854         hdsa->nItemSize = nSize;
855         hdsa->nGrow = max(1, nGrow);
856     }
857
858     return hdsa;
859 }
860
861
862 /**************************************************************************
863  * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
864  *
865  * PARAMS
866  *     hdsa [I] pointer to the array control structure
867  *
868  * RETURNS
869  *     Success: TRUE
870  *     Failure: FALSE
871  */
872
873 BOOL WINAPI
874 DSA_Destroy (const HDSA hdsa)
875 {
876     TRACE("(%p)\n", hdsa);
877
878     if (!hdsa)
879         return FALSE;
880
881     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
882         return FALSE;
883
884     return COMCTL32_Free (hdsa);
885 }
886
887
888 /**************************************************************************
889  * DSA_GetItem [COMCTL32.322] 
890  *
891  * PARAMS
892  *     hdsa   [I] pointer to the array control structure
893  *     nIndex [I] number of the Item to get
894  *     pDest  [O] destination buffer. Has to be >= dwElementSize.
895  *
896  * RETURNS
897  *     Success: TRUE
898  *     Failure: FALSE
899  */
900
901 BOOL WINAPI
902 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
903 {
904     LPVOID pSrc;
905
906     TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
907     
908     if (!hdsa)
909         return FALSE;
910     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
911         return FALSE;
912
913     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
914     memmove (pDest, pSrc, hdsa->nItemSize);
915
916     return TRUE;
917 }
918
919
920 /**************************************************************************
921  * DSA_GetItemPtr [COMCTL32.323] 
922  *
923  * Retrieves a pointer to the specified item.
924  *
925  * PARAMS
926  *     hdsa   [I] pointer to the array control structure
927  *     nIndex [I] index of the desired item
928  *
929  * RETURNS
930  *     Success: pointer to an item
931  *     Failure: NULL
932  */
933
934 LPVOID WINAPI
935 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
936 {
937     LPVOID pSrc;
938
939     TRACE("(%p %d)\n", hdsa, nIndex);
940
941     if (!hdsa)
942         return NULL;
943     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
944         return NULL;
945
946     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
947     
948     TRACE("-- ret=%p\n", pSrc);
949
950     return  pSrc;
951 }
952
953
954 /**************************************************************************
955  * DSA_SetItem [COMCTL32.325] 
956  *
957  * Sets the contents of an item in the array.
958  *
959  * PARAMS
960  *     hdsa   [I] pointer to the array control structure
961  *     nIndex [I] index for the item
962  *     pSrc   [I] pointer to the new item data
963  *
964  * RETURNS
965  *     Success: TRUE
966  *     Failure: FALSE
967  */
968
969 BOOL WINAPI
970 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
971 {
972     INT  nSize, nNewItems;
973     LPVOID pDest, lpTemp;
974     
975     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
976
977     if ((!hdsa) || nIndex < 0)
978         return FALSE;
979       
980     if (hdsa->nItemCount <= nIndex) {
981         /* within the old array */
982         if (hdsa->nMaxCount > nIndex) {
983             /* within the allocated space, set a new boundary */
984             hdsa->nItemCount = nIndex + 1;
985         }
986         else {
987             /* resize the block of memory */
988             nNewItems =
989                 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
990             nSize = hdsa->nItemSize * nNewItems;
991
992             lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
993             if (!lpTemp)
994                 return FALSE;
995
996             hdsa->nMaxCount = nNewItems;
997             hdsa->nItemCount = nIndex + 1;
998             hdsa->pData = lpTemp;
999         }    
1000     }
1001
1002     /* put the new entry in */
1003     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1004     TRACE("-- move dest=%p src=%p size=%d\n",
1005            pDest, pSrc, hdsa->nItemSize);
1006     memmove (pDest, pSrc, hdsa->nItemSize);
1007
1008     return TRUE;
1009 }
1010
1011
1012 /**************************************************************************
1013  * DSA_InsertItem [COMCTL32.325] 
1014  *
1015  * PARAMS
1016  *     hdsa   [I] pointer to the array control structure
1017  *     nIndex [I] index for the new item
1018  *     pSrc   [I] pointer to the element
1019  *
1020  * RETURNS
1021  *     Success: position of the new item
1022  *     Failure: -1
1023  */
1024
1025 INT WINAPI
1026 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1027 {
1028     INT   nNewItems, nSize, i;
1029     LPVOID  lpTemp, lpDest;
1030     LPDWORD p;
1031     
1032     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1033
1034     if ((!hdsa) || nIndex < 0)
1035         return -1;
1036
1037     for (i = 0; i < hdsa->nItemSize; i += 4) {
1038         p = *(DWORD**)((char *) pSrc + i);
1039         if (IsBadStringPtrA ((char*)p, 256))
1040             TRACE("-- %d=%p\n", i, (DWORD*)p);
1041         else
1042             TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
1043     }
1044    
1045     /* when nIndex > nItemCount then append */
1046     if (nIndex >= hdsa->nItemCount)
1047         nIndex = hdsa->nItemCount;
1048
1049     /* do we need to resize ? */
1050     if (hdsa->nItemCount >= hdsa->nMaxCount) {
1051         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1052         nSize = hdsa->nItemSize * nNewItems;
1053
1054         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1055         if (!lpTemp)
1056             return -1;
1057
1058         hdsa->nMaxCount = nNewItems;
1059         hdsa->pData = lpTemp;         
1060     }
1061
1062     /* do we need to move elements ? */
1063     if (nIndex < hdsa->nItemCount) {
1064         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1065         lpDest = (char *) lpTemp + hdsa->nItemSize;
1066         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1067         TRACE("-- move dest=%p src=%p size=%d\n",
1068                lpDest, lpTemp, nSize);
1069         memmove (lpDest, lpTemp, nSize);
1070     }
1071
1072     /* ok, we can put the new Item in */
1073     hdsa->nItemCount++;
1074     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1075     TRACE("-- move dest=%p src=%p size=%d\n",
1076            lpDest, pSrc, hdsa->nItemSize);
1077     memmove (lpDest, pSrc, hdsa->nItemSize);
1078
1079     return hdsa->nItemCount;
1080 }
1081
1082
1083 /**************************************************************************
1084  * DSA_DeleteItem [COMCTL32.326] 
1085  *
1086  * PARAMS
1087  *     hdsa   [I] pointer to the array control structure
1088  *     nIndex [I] index for the element to delete
1089  *
1090  * RETURNS
1091  *     Success: number of the deleted element
1092  *     Failure: -1
1093  */
1094
1095 INT WINAPI
1096 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1097 {
1098     LPVOID lpDest,lpSrc;
1099     INT  nSize;
1100     
1101     TRACE("(%p %d)\n", hdsa, nIndex);
1102
1103     if (!hdsa)
1104         return -1;
1105     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1106         return -1;
1107
1108     /* do we need to move ? */
1109     if (nIndex < hdsa->nItemCount - 1) {
1110         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1111         lpSrc = (char *) lpDest + hdsa->nItemSize;
1112         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1113         TRACE("-- move dest=%p src=%p size=%d\n",
1114                lpDest, lpSrc, nSize);
1115         memmove (lpDest, lpSrc, nSize);
1116     }
1117     
1118     hdsa->nItemCount--;
1119     
1120     /* free memory ? */
1121     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1122         nSize = hdsa->nItemSize * hdsa->nItemCount;
1123
1124         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1125         if (!lpDest)
1126             return -1;
1127
1128         hdsa->nMaxCount = hdsa->nItemCount;
1129         hdsa->pData = lpDest;
1130     }
1131
1132     return nIndex;
1133 }
1134
1135
1136 /**************************************************************************
1137  * DSA_DeleteAllItems [COMCTL32.326]
1138  *
1139  * Removes all items and reinitializes the array.
1140  *
1141  * PARAMS
1142  *     hdsa [I] pointer to the array control structure
1143  *
1144  * RETURNS
1145  *     Success: TRUE
1146  *     Failure: FALSE
1147  */
1148
1149 BOOL WINAPI
1150 DSA_DeleteAllItems (const HDSA hdsa)
1151 {
1152     TRACE("(%p)\n", hdsa);
1153
1154     if (!hdsa) 
1155         return FALSE;
1156     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1157         return FALSE;
1158
1159     hdsa->nItemCount = 0;
1160     hdsa->pData = NULL;
1161     hdsa->nMaxCount = 0;
1162
1163     return TRUE;
1164 }
1165
1166
1167 /**************************************************************************
1168  * The DPA-API is a set of functions to create and manipulate arrays of
1169  * pointers.
1170  */
1171
1172 /**************************************************************************
1173  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1174  *
1175  * PARAMS
1176  *     nGrow [I] number of items by which the array grows when it is filled
1177  *
1178  * RETURNS
1179  *     Success: handle (pointer) to the pointer array.
1180  *     Failure: NULL
1181  */
1182
1183 HDPA WINAPI
1184 DPA_Create (INT nGrow)
1185 {
1186     HDPA hdpa;
1187
1188     TRACE("(%d)\n", nGrow);
1189
1190     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1191     if (hdpa) {
1192         hdpa->nGrow = max(8, nGrow);
1193         hdpa->hHeap = COMCTL32_hHeap;
1194         hdpa->nMaxCount = hdpa->nGrow * 2;
1195         hdpa->ptrs =
1196             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1197     }
1198
1199     TRACE("-- %p\n", hdpa);
1200
1201     return hdpa;
1202 }
1203
1204
1205 /**************************************************************************
1206  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1207  *
1208  * PARAMS
1209  *     hdpa [I] handle (pointer) to the pointer array
1210  *
1211  * RETURNS
1212  *     Success: TRUE
1213  *     Failure: FALSE
1214  */
1215
1216 BOOL WINAPI
1217 DPA_Destroy (const HDPA hdpa)
1218 {
1219     TRACE("(%p)\n", hdpa);
1220
1221     if (!hdpa)
1222         return FALSE;
1223
1224     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1225         return FALSE;
1226
1227     return HeapFree (hdpa->hHeap, 0, hdpa);
1228 }
1229
1230
1231 /**************************************************************************
1232  * DPA_Grow [COMCTL32.330]
1233  *
1234  * Sets the growth amount.
1235  *
1236  * PARAMS
1237  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1238  *     nGrow [I] number of items, the array grows, when it's too small
1239  *
1240  * RETURNS
1241  *     Success: TRUE
1242  *     Failure: FALSE
1243  */
1244
1245 BOOL WINAPI
1246 DPA_Grow (const HDPA hdpa, INT nGrow)
1247 {
1248     TRACE("(%p %d)\n", hdpa, nGrow);
1249
1250     if (!hdpa)
1251         return FALSE;
1252
1253     hdpa->nGrow = max(8, nGrow);
1254
1255     return TRUE;
1256 }
1257
1258
1259 /**************************************************************************
1260  * DPA_Clone [COMCTL32.331]
1261  *
1262  * Copies a pointer array to an other one or creates a copy
1263  *
1264  * PARAMS
1265  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1266  *     hdpaNew [O] handle (pointer) to the destination pointer array
1267  *
1268  * RETURNS
1269  *     Success: pointer to the destination pointer array.
1270  *     Failure: NULL
1271  *
1272  * NOTES
1273  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1274  *       array will be created and it's handle (pointer) is returned.
1275  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1276  *       this implementation just returns NULL.
1277  */
1278
1279 HDPA WINAPI
1280 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1281 {
1282     INT nNewItems, nSize;
1283     HDPA hdpaTemp;
1284
1285     if (!hdpa)
1286         return NULL;
1287
1288     TRACE("(%p %p)\n", hdpa, hdpaNew);
1289
1290     if (!hdpaNew) {
1291         /* create a new DPA */
1292         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1293                                     sizeof(DPA));
1294         hdpaTemp->hHeap = hdpa->hHeap;
1295         hdpaTemp->nGrow = hdpa->nGrow;
1296     }
1297     else
1298         hdpaTemp = hdpaNew;
1299
1300     if (hdpaTemp->ptrs) {
1301         /* remove old pointer array */
1302         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1303         hdpaTemp->ptrs = NULL;
1304         hdpaTemp->nItemCount = 0;
1305         hdpaTemp->nMaxCount = 0;
1306     }
1307
1308     /* create a new pointer array */
1309     nNewItems = hdpaTemp->nGrow *
1310                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1311     nSize = nNewItems * sizeof(LPVOID);
1312     hdpaTemp->ptrs =
1313         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1314     hdpaTemp->nMaxCount = nNewItems;
1315
1316     /* clone the pointer array */
1317     hdpaTemp->nItemCount = hdpa->nItemCount;
1318     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1319              hdpaTemp->nItemCount * sizeof(LPVOID));
1320
1321     return hdpaTemp;
1322 }
1323
1324
1325 /**************************************************************************
1326  * DPA_GetPtr [COMCTL32.332]
1327  *
1328  * Retrieves a pointer from a dynamic pointer array
1329  *
1330  * PARAMS
1331  *     hdpa   [I] handle (pointer) to the pointer array
1332  *     nIndex [I] array index of the desired pointer
1333  *
1334  * RETURNS
1335  *     Success: pointer
1336  *     Failure: NULL
1337  */
1338
1339 LPVOID WINAPI
1340 DPA_GetPtr (const HDPA hdpa, INT i)
1341 {
1342     TRACE("(%p %d)\n", hdpa, i);
1343
1344     if (!hdpa)
1345         return NULL;
1346     if (!hdpa->ptrs)
1347         return NULL;
1348     if ((i < 0) || (i >= hdpa->nItemCount))
1349         return NULL;
1350
1351     TRACE("-- %p\n", hdpa->ptrs[i]);
1352
1353     return hdpa->ptrs[i];
1354 }
1355
1356
1357 /**************************************************************************
1358  * DPA_GetPtrIndex [COMCTL32.333]
1359  *
1360  * Retrieves the index of the specified pointer
1361  *
1362  * PARAMS
1363  *     hdpa   [I] handle (pointer) to the pointer array
1364  *     p      [I] pointer
1365  *
1366  * RETURNS
1367  *     Success: index of the specified pointer
1368  *     Failure: -1
1369  */
1370
1371 INT WINAPI
1372 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1373 {
1374     INT i;
1375
1376     if (!hdpa->ptrs)
1377         return -1;
1378
1379     for (i = 0; i < hdpa->nItemCount; i++) {
1380         if (hdpa->ptrs[i] == p)
1381             return i;
1382     }
1383
1384     return -1;
1385 }
1386
1387
1388 /**************************************************************************
1389  * DPA_InsertPtr [COMCTL32.334]
1390  *
1391  * Inserts a pointer into a dynamic pointer array
1392  *
1393  * PARAMS
1394  *     hdpa [I] handle (pointer) to the array
1395  *     i    [I] array index
1396  *     p    [I] pointer to insert
1397  *
1398  * RETURNS
1399  *     Success: index of the inserted pointer
1400  *     Failure: -1
1401  */
1402
1403 INT WINAPI
1404 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1405 {
1406     INT   nNewItems, nSize, nIndex = 0;
1407     LPVOID  *lpTemp, *lpDest;
1408
1409     TRACE("(%p %d %p)\n", hdpa, i, p);
1410
1411     if ((!hdpa) || (i < 0))
1412         return -1;
1413
1414     if (!hdpa->ptrs) {
1415         hdpa->ptrs =
1416             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1417                                 2 * hdpa->nGrow * sizeof(LPVOID));
1418         if (!hdpa->ptrs)
1419             return -1;
1420         hdpa->nMaxCount = hdpa->nGrow * 2;
1421         nIndex = 0;
1422     }
1423     else {
1424         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1425             TRACE("-- resizing\n");
1426             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1427             nSize = nNewItems * sizeof(LPVOID);
1428
1429             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1430                                            hdpa->ptrs, nSize);
1431             if (!lpTemp)
1432                 return -1;
1433             hdpa->nMaxCount = nNewItems;
1434             hdpa->ptrs = lpTemp;
1435         }
1436
1437         if (i >= hdpa->nItemCount) {
1438             nIndex = hdpa->nItemCount;
1439             TRACE("-- appending at %d\n", nIndex);
1440         }
1441         else {
1442             TRACE("-- inserting at %d\n", i);
1443             lpTemp = hdpa->ptrs + i;
1444             lpDest = lpTemp + 1;
1445             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1446             TRACE("-- move dest=%p src=%p size=%x\n",
1447                    lpDest, lpTemp, nSize);
1448             memmove (lpDest, lpTemp, nSize);
1449             nIndex = i;
1450         }
1451     }
1452
1453     /* insert item */
1454     hdpa->nItemCount++;
1455     hdpa->ptrs[nIndex] = p;
1456
1457     return nIndex;
1458 }
1459
1460
1461 /**************************************************************************
1462  * DPA_SetPtr [COMCTL32.335]
1463  *
1464  * Sets a pointer in the pointer array
1465  *
1466  * PARAMS
1467  *     hdpa [I] handle (pointer) to the pointer array
1468  *     i    [I] index of the pointer that will be set
1469  *     p    [I] pointer to be set
1470  *
1471  * RETURNS
1472  *     Success: TRUE
1473  *     Failure: FALSE
1474  */
1475
1476 BOOL WINAPI
1477 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1478 {
1479     LPVOID *lpTemp;
1480     
1481     TRACE("(%p %d %p)\n", hdpa, i, p);
1482
1483     if ((!hdpa) || i < 0)
1484         return FALSE;
1485       
1486     if (hdpa->nItemCount <= i) {
1487         /* within the old array */
1488         if (hdpa->nMaxCount > i) {
1489             /* within the allocated space, set a new boundary */
1490             hdpa->nItemCount = i;
1491         }
1492         else {
1493             /* resize the block of memory */
1494             INT nNewItems =
1495                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1496             INT nSize = nNewItems * sizeof(LPVOID);
1497
1498             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1499                                            hdpa->ptrs, nSize);
1500             if (!lpTemp)
1501                 return FALSE;
1502
1503             hdpa->nItemCount = nNewItems;
1504             hdpa->ptrs = lpTemp;        
1505         }    
1506     }
1507
1508     /* put the new entry in */
1509     hdpa->ptrs[i] = p;
1510
1511     return TRUE;
1512 }
1513
1514
1515 /**************************************************************************
1516  * DPA_DeletePtr [COMCTL32.336]
1517  *
1518  * Removes a pointer from the pointer array.
1519  *
1520  * PARAMS
1521  *     hdpa [I] handle (pointer) to the pointer array
1522  *     i    [I] index of the pointer that will be deleted
1523  *
1524  * RETURNS
1525  *     Success: deleted pointer
1526  *     Failure: NULL
1527  */
1528
1529 LPVOID WINAPI
1530 DPA_DeletePtr (const HDPA hdpa, INT i)
1531 {
1532     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1533     INT  nSize;
1534     
1535     TRACE("(%p %d)\n", hdpa, i);
1536
1537     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1538         return NULL;
1539
1540     lpTemp = hdpa->ptrs[i];
1541
1542     /* do we need to move ?*/
1543     if (i < hdpa->nItemCount - 1) {
1544         lpDest = hdpa->ptrs + i;
1545         lpSrc = lpDest + 1;
1546         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1547         TRACE("-- move dest=%p src=%p size=%x\n",
1548                lpDest, lpSrc, nSize);
1549         memmove (lpDest, lpSrc, nSize);
1550     }
1551     
1552     hdpa->nItemCount --;
1553     
1554     /* free memory ?*/
1555     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1556         INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
1557         nSize = nNewItems * sizeof(LPVOID);
1558         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1559                                       hdpa->ptrs, nSize);
1560         if (!lpDest)
1561             return NULL;
1562
1563         hdpa->nMaxCount = nNewItems;
1564         hdpa->ptrs = (LPVOID*)lpDest;         
1565     }
1566
1567     return lpTemp;
1568 }
1569
1570
1571 /**************************************************************************
1572  * DPA_DeleteAllPtrs [COMCTL32.337]
1573  *
1574  * Removes all pointers and reinitializes the array.
1575  *
1576  * PARAMS
1577  *     hdpa [I] handle (pointer) to the pointer array
1578  *
1579  * RETURNS
1580  *     Success: TRUE
1581  *     Failure: FALSE
1582  */
1583
1584 BOOL WINAPI
1585 DPA_DeleteAllPtrs (const HDPA hdpa)
1586 {
1587     TRACE("(%p)\n", hdpa);
1588
1589     if (!hdpa) 
1590         return FALSE;
1591
1592     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1593         return FALSE;
1594
1595     hdpa->nItemCount = 0;
1596     hdpa->nMaxCount = hdpa->nGrow * 2;
1597     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1598                                      hdpa->nMaxCount * sizeof(LPVOID));
1599
1600     return TRUE;
1601 }
1602
1603
1604 /**************************************************************************
1605  * DPA_QuickSort [Internal]
1606  *
1607  * Ordinary quicksort (used by DPA_Sort).
1608  *
1609  * PARAMS
1610  *     lpPtrs     [I] pointer to the pointer array
1611  *     l          [I] index of the "left border" of the partition
1612  *     r          [I] index of the "right border" of the partition
1613  *     pfnCompare [I] pointer to the compare function
1614  *     lParam     [I] user defined value (3rd parameter in compare function)
1615  *
1616  * RETURNS
1617  *     NONE
1618  */
1619
1620 static VOID
1621 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1622                PFNDPACOMPARE pfnCompare, LPARAM lParam)
1623 {
1624     LPVOID t, v;
1625     INT  i, j;
1626
1627     TRACE("l=%i r=%i\n", l, r);
1628  
1629     i = l;
1630     j = r;
1631     v = lpPtrs[(int)(l+r)/2];
1632     do {
1633         while ((pfnCompare)(lpPtrs[i], v, lParam) < 0) i++;
1634         while ((pfnCompare)(lpPtrs[j], v, lParam) > 0) j--;
1635         if (i <= j) 
1636         {
1637             t = lpPtrs[i];
1638             lpPtrs[i++] = lpPtrs[j];
1639             lpPtrs[j--] = t;
1640         }
1641     } while (i <= j);
1642     if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
1643     if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
1644 }
1645
1646
1647 /**************************************************************************
1648  * DPA_Sort [COMCTL32.338]
1649  *
1650  * Sorts a pointer array using a user defined compare function
1651  *
1652  * PARAMS
1653  *     hdpa       [I] handle (pointer) to the pointer array
1654  *     pfnCompare [I] pointer to the compare function
1655  *     lParam     [I] user defined value (3rd parameter of compare function)
1656  *
1657  * RETURNS
1658  *     Success: TRUE
1659  *     Failure: FALSE
1660  */
1661
1662 BOOL WINAPI
1663 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1664 {
1665     if (!hdpa || !pfnCompare)
1666         return FALSE;
1667
1668     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1669
1670     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1671         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1672                        pfnCompare, lParam);
1673
1674     return TRUE;
1675 }
1676
1677
1678 /**************************************************************************
1679  * DPA_Search [COMCTL32.339]
1680  *
1681  * Searches a pointer array for a specified pointer
1682  *
1683  * PARAMS
1684  *     hdpa       [I] handle (pointer) to the pointer array
1685  *     pFind      [I] pointer to search for
1686  *     nStart     [I] start index
1687  *     pfnCompare [I] pointer to the compare function
1688  *     lParam     [I] user defined value (3rd parameter of compare function)
1689  *     uOptions   [I] search options
1690  *
1691  * RETURNS
1692  *     Success: index of the pointer in the array.
1693  *     Failure: -1
1694  *
1695  * NOTES
1696  *     Binary search taken from R.Sedgewick "Algorithms in C"!
1697  *     Function is NOT tested!
1698  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
1699  */
1700
1701 INT WINAPI
1702 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1703             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1704 {
1705     if (!hdpa || !pfnCompare || !pFind)
1706         return -1;
1707
1708     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1709            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1710
1711     if (uOptions & DPAS_SORTED) {
1712         /* array is sorted --> use binary search */
1713         INT l, r, x, n;
1714         LPVOID *lpPtr;
1715
1716         TRACE("binary search\n");
1717
1718         l = (nStart == -1) ? 0 : nStart;
1719         r = hdpa->nItemCount - 1;
1720         lpPtr = hdpa->ptrs;
1721         while (r >= l) {
1722             x = (l + r) / 2;
1723             n = (pfnCompare)(pFind, lpPtr[x], lParam);
1724             if (n < 0)
1725                 r = x - 1;
1726             else
1727                 l = x + 1;
1728             if (n == 0) {
1729                 TRACE("-- ret=%d\n", n);
1730                 return n;
1731             }
1732         }
1733
1734         if (uOptions & DPAS_INSERTBEFORE) {
1735             TRACE("-- ret=%d\n", r);
1736             return r;
1737         }
1738
1739         if (uOptions & DPAS_INSERTAFTER) {
1740             TRACE("-- ret=%d\n", l);
1741             return l;
1742         }
1743     }
1744     else {
1745         /* array is not sorted --> use linear search */
1746         LPVOID *lpPtr;
1747         INT  nIndex;
1748
1749         TRACE("linear search\n");
1750         
1751         nIndex = (nStart == -1)? 0 : nStart;
1752         lpPtr = hdpa->ptrs;
1753         for (; nIndex < hdpa->nItemCount; nIndex++) {
1754             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1755                 TRACE("-- ret=%d\n", nIndex);
1756                 return nIndex;
1757             }
1758         }
1759     }
1760
1761     TRACE("-- not found: ret=-1\n");
1762     return -1;
1763 }
1764
1765
1766 /**************************************************************************
1767  * DPA_CreateEx [COMCTL32.340]
1768  *
1769  * Creates a dynamic pointer array using the specified size and heap.
1770  *
1771  * PARAMS
1772  *     nGrow [I] number of items by which the array grows when it is filled
1773  *     hHeap [I] handle to the heap where the array is stored
1774  *
1775  * RETURNS
1776  *     Success: handle (pointer) to the pointer array.
1777  *     Failure: NULL
1778  */
1779
1780 HDPA WINAPI
1781 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1782 {
1783     HDPA hdpa;
1784
1785     TRACE("(%d 0x%x)\n", nGrow, hHeap);
1786
1787     if (hHeap)
1788         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1789     else
1790         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1791
1792     if (hdpa) {
1793         hdpa->nGrow = min(8, nGrow);
1794         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1795         hdpa->nMaxCount = hdpa->nGrow * 2;
1796         hdpa->ptrs =
1797             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1798                                 hdpa->nMaxCount * sizeof(LPVOID));
1799     }
1800
1801     TRACE("-- %p\n", hdpa);
1802
1803     return hdpa;
1804 }
1805
1806
1807 /**************************************************************************
1808  * Notification functions
1809  */
1810
1811 typedef struct tagNOTIFYDATA
1812 {
1813     HWND hwndFrom;
1814     HWND hwndTo;
1815     DWORD  dwParam3;
1816     DWORD  dwParam4;
1817     DWORD  dwParam5;
1818     DWORD  dwParam6;
1819 } NOTIFYDATA, *LPNOTIFYDATA;
1820
1821
1822 /**************************************************************************
1823  * DoNotify [Internal]
1824  */
1825
1826 static LRESULT
1827 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1828 {
1829     NMHDR nmhdr;
1830     LPNMHDR lpNmh = NULL;
1831     UINT idFrom = 0;
1832
1833     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1834            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1835            lpNotify->dwParam5);
1836
1837     if (!lpNotify->hwndTo)
1838         return 0;
1839
1840     if (lpNotify->hwndFrom == -1) {
1841         lpNmh = lpHdr;
1842         idFrom = lpHdr->idFrom;
1843     }
1844     else {
1845         if (lpNotify->hwndFrom) {
1846             HWND hwndParent = GetParent (lpNotify->hwndFrom);
1847             if (hwndParent) {
1848                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1849                 if (hwndParent)
1850                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1851             }
1852         }
1853
1854         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1855
1856         lpNmh->hwndFrom = lpNotify->hwndFrom;
1857         lpNmh->idFrom = idFrom;
1858         lpNmh->code = uCode;
1859     }
1860
1861     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1862 }
1863
1864
1865 /**************************************************************************
1866  * SendNotify [COMCTL32.341]
1867  *
1868  * PARAMS
1869  *     hwndFrom [I]
1870  *     hwndTo   [I]
1871  *     uCode    [I]
1872  *     lpHdr    [I]
1873  *
1874  * RETURNS
1875  *     Success: return value from notification
1876  *     Failure: 0
1877  */
1878
1879 LRESULT WINAPI
1880 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1881                      UINT uCode, LPNMHDR lpHdr)
1882 {
1883     NOTIFYDATA notify;
1884
1885     TRACE("(0x%04x 0x%04x %d %p)\n",
1886            hwndFrom, hwndTo, uCode, lpHdr);
1887
1888     notify.hwndFrom = hwndFrom;
1889     notify.hwndTo   = hwndTo;
1890     notify.dwParam5 = 0;
1891     notify.dwParam6 = 0;
1892
1893     return DoNotify (&notify, uCode, lpHdr);
1894 }
1895
1896
1897 /**************************************************************************
1898  * SendNotifyEx [COMCTL32.342]
1899  *
1900  * PARAMS
1901  *     hwndFrom [I]
1902  *     hwndTo   [I]
1903  *     uCode    [I]
1904  *     lpHdr    [I]
1905  *     dwParam5 [I]
1906  *
1907  * RETURNS
1908  *     Success: return value from notification
1909  *     Failure: 0
1910  */
1911
1912 LRESULT WINAPI
1913 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1914                        LPNMHDR lpHdr, DWORD dwParam5)
1915 {
1916     NOTIFYDATA notify;
1917     HWND hwndNotify;
1918
1919     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1920            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1921
1922     hwndNotify = hwndTo;
1923     if (!hwndTo) {
1924         if (IsWindow (hwndFrom)) {
1925             hwndNotify = GetParent (hwndFrom);
1926             if (!hwndNotify)
1927                 return 0;
1928         }
1929     }
1930
1931     notify.hwndFrom = hwndFrom;
1932     notify.hwndTo   = hwndNotify;
1933     notify.dwParam5 = dwParam5;
1934     notify.dwParam6 = 0;
1935
1936     return DoNotify (&notify, uCode, lpHdr);
1937 }
1938
1939
1940 /**************************************************************************
1941  * StrChrA [COMCTL32.350]
1942  *
1943  */
1944
1945 LPSTR WINAPI
1946 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
1947 {
1948     return strchr (lpString, cChar);
1949 }
1950
1951
1952 /**************************************************************************
1953  * StrStrIA [COMCTL32.355]
1954  */
1955
1956 LPSTR WINAPI
1957 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
1958 {
1959     INT len1, len2, i;
1960     CHAR  first;
1961
1962     if (*lpStr2 == 0)
1963         return ((LPSTR)lpStr1);
1964     len1 = 0;
1965     while (lpStr1[len1] != 0) ++len1;
1966     len2 = 0;
1967     while (lpStr2[len2] != 0) ++len2;
1968     if (len2 == 0)
1969         return ((LPSTR)(lpStr1 + len1));
1970     first = tolower (*lpStr2);
1971     while (len1 >= len2) {
1972         if (tolower(*lpStr1) == first) {
1973             for (i = 1; i < len2; ++i)
1974                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
1975                     break;
1976             if (i >= len2)
1977                 return ((LPSTR)lpStr1);
1978         }
1979         ++lpStr1; --len1;
1980     }
1981     return (NULL);
1982 }
1983
1984
1985 /**************************************************************************
1986  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
1987  */
1988
1989 INT WINAPI
1990 COMCTL32_StrToIntA (LPSTR lpString)
1991 {
1992     return atoi(lpString);
1993 }
1994
1995
1996 /**************************************************************************
1997  * DPA_EnumCallback [COMCTL32.385]
1998  *
1999  * Enumerates all items in a dynamic pointer array.
2000  *
2001  * PARAMS
2002  *     hdpa     [I] handle to the dynamic pointer array
2003  *     enumProc [I]
2004  *     lParam   [I] 
2005  *
2006  * RETURNS
2007  *     none
2008  */
2009
2010 VOID WINAPI
2011 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2012 {
2013     INT i;
2014
2015     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2016
2017     if (!hdpa)
2018         return;
2019     if (hdpa->nItemCount <= 0)
2020         return;
2021
2022     for (i = 0; i < hdpa->nItemCount; i++) {
2023         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2024             return;
2025     }
2026
2027     return;
2028 }
2029
2030
2031 /**************************************************************************
2032  * DPA_DestroyCallback [COMCTL32.386]
2033  *
2034  * Enumerates all items in a dynamic pointer array and destroys it.
2035  *
2036  * PARAMS
2037  *     hdpa     [I] handle to the dynamic pointer array
2038  *     enumProc [I]
2039  *     lParam   [I]
2040  *
2041  * RETURNS
2042  *     Success: TRUE
2043  *     Failure: FALSE
2044  */
2045
2046 BOOL WINAPI
2047 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2048 {
2049     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2050
2051     DPA_EnumCallback (hdpa, enumProc, lParam);
2052
2053     return DPA_Destroy (hdpa);
2054 }
2055
2056
2057 /**************************************************************************
2058  * DSA_EnumCallback [COMCTL32.387]
2059  *
2060  * Enumerates all items in a dynamic storage array.
2061  *
2062  * PARAMS
2063  *     hdsa     [I] handle to the dynamic storage array
2064  *     enumProc [I]
2065  *     lParam   [I]
2066  *
2067  * RETURNS
2068  *     none
2069  */
2070
2071 VOID WINAPI
2072 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2073 {
2074     INT i;
2075
2076     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2077
2078     if (!hdsa)
2079         return;
2080     if (hdsa->nItemCount <= 0)
2081         return;
2082
2083     for (i = 0; i < hdsa->nItemCount; i++) {
2084         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2085         if ((enumProc)(lpItem, lParam) == 0)
2086             return;
2087     }
2088
2089     return;
2090 }
2091
2092
2093 /**************************************************************************
2094  * DSA_DestroyCallback [COMCTL32.388]
2095  *
2096  * Enumerates all items in a dynamic storage array and destroys it.
2097  *
2098  * PARAMS
2099  *     hdsa     [I] handle to the dynamic storage array
2100  *     enumProc [I]
2101  *     lParam   [I]
2102  *
2103  * RETURNS
2104  *     Success: TRUE
2105  *     Failure: FALSE
2106  */
2107
2108 BOOL WINAPI
2109 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2110 {
2111     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2112
2113     DSA_EnumCallback (hdsa, enumProc, lParam);
2114
2115     return DSA_Destroy (hdsa);
2116 }
2117
2118 /**************************************************************************
2119  * StrCSpnA [COMCTL32.356]
2120  *
2121  */
2122 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2123   return strcspn(lpStr, lpSet);
2124 }
2125
2126 /**************************************************************************
2127  * StrChrW [COMCTL32.358]
2128  *
2129  */
2130 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2131   return CRTDLL_wcschr(lpStart, wMatch);
2132 }
2133
2134 /**************************************************************************
2135  * StrCmpNA [COMCTL32.352]
2136  *
2137  */
2138 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2139   return strncmp(lpStr1, lpStr2, nChar);
2140 }
2141
2142 /**************************************************************************
2143  * StrCmpNIA [COMCTL32.353]
2144  *
2145  */
2146 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2147   return strncasecmp(lpStr1, lpStr2, nChar);
2148 }
2149
2150 /**************************************************************************
2151  * StrCmpNW [COMCTL32.360]
2152  *
2153  */
2154 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2155   return CRTDLL_wcsncmp(lpStr1, lpStr2, nChar);
2156 }
2157
2158 /**************************************************************************
2159  * StrCmpNIW [COMCTL32.361]
2160  *
2161  */
2162 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2163   FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2164   return 0;
2165 }
2166
2167 /**************************************************************************
2168  * StrRChrA [COMCTL32.351]
2169  *
2170  */
2171 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch) {
2172   return lstrrchr(lpStart, lpEnd, wMatch); 
2173 }
2174
2175 /**************************************************************************
2176  * StrRChrW [COMCTL32.359]
2177  *
2178  */
2179 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch) {
2180   return lstrrchrw(lpStart, lpEnd, wMatch); 
2181 }
2182
2183 /**************************************************************************
2184  * StrStrA [COMCTL32.354]
2185  *
2186  */
2187 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2188   return strstr(lpFirst, lpSrch);
2189 }
2190
2191 /**************************************************************************
2192  * StrStrW [COMCTL32.362]
2193  *
2194  */
2195 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2196   return CRTDLL_wcsstr(lpFirst, lpSrch);
2197 }
2198
2199 /**************************************************************************
2200  * StrSpnW [COMCTL32.364]
2201  *
2202  */
2203 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2204   LPWSTR lpLoop = lpStr;
2205
2206   /* validate ptr */
2207   if ((lpStr == 0) || (lpSet == 0)) return 0;
2208
2209 /* while(*lpLoop) { if lpLoop++; } */
2210
2211   for(; (*lpLoop != 0); lpLoop++)
2212     if( CRTDLL_wcschr(lpSet, *(WORD*)lpLoop))
2213       return (INT)(lpLoop-lpStr);
2214   
2215   return (INT)(lpLoop-lpStr);
2216 }
2217
2218 /**************************************************************************
2219  * COMCTL32_410 [COMCTL32.410]
2220  *
2221  * FIXME: What's this supposed to do?
2222  *        Parameter 1 is an HWND, you're on your own for the rest.
2223  */
2224
2225 BOOL WINAPI COMCTL32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2226
2227    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2228
2229    return TRUE;
2230 }
2231
2232 /**************************************************************************
2233  * COMCTL32_411 [COMCTL32.411]
2234  *
2235  * FIXME: What's this supposed to do?
2236  *        Parameter 1 is an HWND, you're on your own for the rest.
2237  */
2238
2239 BOOL WINAPI COMCTL32_411( HWND hw, DWORD b, DWORD c) {
2240
2241    FIXME("(%x, %lx, %lx): stub!\n", hw, b, c);
2242
2243    return TRUE;
2244 }
2245
2246 /**************************************************************************
2247  * COMCTL32_412 [COMCTL32.412]
2248  *
2249  * FIXME: What's this supposed to do?
2250  *        Parameter 1 is an HWND, you're on your own for the rest.
2251  */
2252
2253 BOOL WINAPI COMCTL32_412( HWND hwnd, DWORD b, DWORD c)
2254 {
2255     FIXME("(%x, %lx, %lx): stub!\n", hwnd, b, c);
2256
2257     if (IsWindow (hwnd) == FALSE)
2258         return FALSE;
2259
2260     if (b == 0)
2261         return FALSE;
2262
2263
2264     return TRUE;
2265 }
2266
2267 /**************************************************************************
2268  * COMCTL32_413 [COMCTL32.413]
2269  *
2270  * FIXME: What's this supposed to do?
2271  *        Parameter 1 is an HWND, you're on your own for the rest.
2272  */
2273
2274 BOOL WINAPI COMCTL32_413( HWND hw, DWORD b, DWORD c, DWORD d) {
2275
2276    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2277
2278    return TRUE;
2279 }
2280
2281 /*************************************************************************
2282  * InitMUILanguage [COMCTL32.70]
2283  *
2284  * FIXME: What's this supposed to do?  Apparently some i18n thing.
2285  *
2286  */
2287
2288 BOOL WINAPI InitMUILanguage( LANGID uiLang) {
2289
2290    FIXME("(%04x): stub!\n", uiLang);
2291
2292    return TRUE;
2293 }
2294