Height calculation was 1 off in ImageList_Read.
[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 HANDLE WINAPI
613 CreateMRUListLazyA (LPCREATEMRULIST lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
614 {
615     /* DWORD  dwLocal1;   *
616      * HKEY   hkeyResult; *
617      * DWORD  dwLocal3;   *
618      * LPVOID lMRU;       *
619      * DWORD  dwLocal5;   *
620      * DWORD  dwLocal6;   *
621      * DWORD  dwLocal7;   *
622      * DWORD  dwDisposition; */
623
624     /* internal variables */
625     LPVOID ptr;
626
627     FIXME("(%p) empty stub!\n", lpcml);
628
629     if (lpcml == NULL)
630         return 0;
631
632     if (lpcml->cbSize < sizeof(CREATEMRULIST))
633         return 0;
634
635     FIXME("(%lu %lu %lx %lx \"%s\" %p)\n",
636           lpcml->cbSize, lpcml->nMaxItems, lpcml->dwFlags,
637           (DWORD)lpcml->hKey, lpcml->lpszSubKey, lpcml->lpfnCompare);
638
639     /* dummy pointer creation */
640     ptr = COMCTL32_Alloc (32);
641
642     FIXME("-- ret = %p\n", ptr);
643
644     return (HANDLE)ptr;
645 }
646
647 /**************************************************************************
648  *                EnumMRUListA [COMCTL32.154]
649  * 
650  * Enumerate item in a list
651  *
652  * PARAMS
653  *    hList [I] list handle
654  *    nItemPos [I] item position to enumerate
655  *    lpBuffer [O] buffer to receive item
656  *    nBufferSize [I] size of buffer
657  *
658  * RETURNS
659  *    For binary lists specifies how many bytes were copied to buffer, for
660  *    string lists specifies full length of string.  Enumerating past the end
661  *    of list returns -1.
662  *    If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
663  *    the list. 
664  */
665 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
666 DWORD nBufferSize)
667 {
668     FIXME("(%08x, %d, %p, %ld): stub\n", hList, nItemPos, lpBuffer,
669           nBufferSize);
670     return 0;
671 }
672
673 /**************************************************************************
674  * Str_GetPtrA [COMCTL32.233]
675  *
676  * PARAMS
677  *     lpSrc   [I]
678  *     lpDest  [O]
679  *     nMaxLen [I]
680  *
681  * RETURNS
682  */
683
684 INT WINAPI
685 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
686 {
687     INT len;
688
689     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
690
691     if (!lpDest && lpSrc)
692         return lstrlenA (lpSrc);
693
694     if (nMaxLen == 0)
695         return 0;
696
697     if (lpSrc == NULL) {
698         lpDest[0] = '\0';
699         return 0;
700     }
701
702     len = lstrlenA (lpSrc);
703     if (len >= nMaxLen)
704         len = nMaxLen - 1;
705
706     RtlMoveMemory (lpDest, lpSrc, len);
707     lpDest[len] = '\0';
708
709     return len;
710 }
711
712
713 /**************************************************************************
714  * Str_SetPtrA [COMCTL32.234]
715  *
716  * PARAMS
717  *     lppDest [O]
718  *     lpSrc   [I]
719  *
720  * RETURNS
721  */
722
723 BOOL WINAPI
724 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
725 {
726     TRACE("(%p %p)\n", lppDest, lpSrc);
727  
728     if (lpSrc) {
729         LPSTR ptr = COMCTL32_ReAlloc (*lppDest, lstrlenA (lpSrc) + 1);
730         if (!ptr)
731             return FALSE;
732         lstrcpyA (ptr, lpSrc);
733         *lppDest = ptr;
734     }
735     else {
736         if (*lppDest) {
737             COMCTL32_Free (*lppDest);
738             *lppDest = NULL;
739         }
740     }
741
742     return TRUE;
743 }
744
745
746 /**************************************************************************
747  * Str_GetPtrW [COMCTL32.235]
748  *
749  * PARAMS
750  *     lpSrc   [I]
751  *     lpDest  [O]
752  *     nMaxLen [I]
753  *
754  * RETURNS
755  */
756
757 INT WINAPI
758 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
759 {
760     INT len;
761
762     TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
763
764     if (!lpDest && lpSrc)
765         return lstrlenW (lpSrc);
766
767     if (nMaxLen == 0)
768         return 0;
769
770     if (lpSrc == NULL) {
771         lpDest[0] = L'\0';
772         return 0;
773     }
774
775     len = lstrlenW (lpSrc);
776     if (len >= nMaxLen)
777         len = nMaxLen - 1;
778
779     RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
780     lpDest[len] = L'\0';
781
782     return len;
783 }
784
785
786 /**************************************************************************
787  * Str_SetPtrW [COMCTL32.236]
788  *
789  * PARAMS
790  *     lpDest [O]
791  *     lpSrc  [I]
792  *
793  * RETURNS
794  */
795
796 BOOL WINAPI
797 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
798 {
799     TRACE("(%p %p)\n", lppDest, lpSrc);
800  
801     if (lpSrc) {
802         INT len = lstrlenW (lpSrc) + 1;
803         LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
804         if (!ptr)
805             return FALSE;
806         lstrcpyW (ptr, lpSrc);
807         *lppDest = ptr;
808     }
809     else {
810         if (*lppDest) {
811             COMCTL32_Free (*lppDest);
812             *lppDest = NULL;
813         }
814     }
815
816     return TRUE;
817 }
818
819
820 /**************************************************************************
821  * The DSA-API is a set of functions to create and manipulate arrays of
822  * fix sized memory blocks. These arrays can store any kind of data
823  * (strings, icons...).
824  */
825
826 /**************************************************************************
827  * DSA_Create [COMCTL32.320] Creates a dynamic storage array
828  *
829  * PARAMS
830  *     nSize [I] size of the array elements
831  *     nGrow [I] number of elements by which the array grows when it is filled
832  *
833  * RETURNS
834  *     Success: pointer to a array control structure. use this like a handle.
835  *     Failure: NULL
836  */
837
838 HDSA WINAPI
839 DSA_Create (INT nSize, INT nGrow)
840 {
841     HDSA hdsa;
842
843     TRACE("(size=%d grow=%d)\n", nSize, nGrow);
844
845     hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
846     if (hdsa)
847     {
848         hdsa->nItemCount = 0;
849         hdsa->pData = NULL;
850         hdsa->nMaxCount = 0;
851         hdsa->nItemSize = nSize;
852         hdsa->nGrow = MAX(1, nGrow);
853     }
854
855     return hdsa;
856 }
857
858
859 /**************************************************************************
860  * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
861  *
862  * PARAMS
863  *     hdsa [I] pointer to the array control structure
864  *
865  * RETURNS
866  *     Success: TRUE
867  *     Failure: FALSE
868  */
869
870 BOOL WINAPI
871 DSA_Destroy (const HDSA hdsa)
872 {
873     TRACE("(%p)\n", hdsa);
874
875     if (!hdsa)
876         return FALSE;
877
878     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
879         return FALSE;
880
881     return COMCTL32_Free (hdsa);
882 }
883
884
885 /**************************************************************************
886  * DSA_GetItem [COMCTL32.322] 
887  *
888  * PARAMS
889  *     hdsa   [I] pointer to the array control structure
890  *     nIndex [I] number of the Item to get
891  *     pDest  [O] destination buffer. Has to be >= dwElementSize.
892  *
893  * RETURNS
894  *     Success: TRUE
895  *     Failure: FALSE
896  */
897
898 BOOL WINAPI
899 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
900 {
901     LPVOID pSrc;
902
903     TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
904     
905     if (!hdsa)
906         return FALSE;
907     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
908         return FALSE;
909
910     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
911     memmove (pDest, pSrc, hdsa->nItemSize);
912
913     return TRUE;
914 }
915
916
917 /**************************************************************************
918  * DSA_GetItemPtr [COMCTL32.323] 
919  *
920  * Retrieves a pointer to the specified item.
921  *
922  * PARAMS
923  *     hdsa   [I] pointer to the array control structure
924  *     nIndex [I] index of the desired item
925  *
926  * RETURNS
927  *     Success: pointer to an item
928  *     Failure: NULL
929  */
930
931 LPVOID WINAPI
932 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
933 {
934     LPVOID pSrc;
935
936     TRACE("(%p %d)\n", hdsa, nIndex);
937
938     if (!hdsa)
939         return NULL;
940     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
941         return NULL;
942
943     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
944     
945     TRACE("-- ret=%p\n", pSrc);
946
947     return  pSrc;
948 }
949
950
951 /**************************************************************************
952  * DSA_SetItem [COMCTL32.325] 
953  *
954  * Sets the contents of an item in the array.
955  *
956  * PARAMS
957  *     hdsa   [I] pointer to the array control structure
958  *     nIndex [I] index for the item
959  *     pSrc   [I] pointer to the new item data
960  *
961  * RETURNS
962  *     Success: TRUE
963  *     Failure: FALSE
964  */
965
966 BOOL WINAPI
967 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
968 {
969     INT  nSize, nNewItems;
970     LPVOID pDest, lpTemp;
971     
972     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
973
974     if ((!hdsa) || nIndex < 0)
975         return FALSE;
976       
977     if (hdsa->nItemCount <= nIndex) {
978         /* within the old array */
979         if (hdsa->nMaxCount > nIndex) {
980             /* within the allocated space, set a new boundary */
981             hdsa->nItemCount = nIndex + 1;
982         }
983         else {
984             /* resize the block of memory */
985             nNewItems =
986                 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
987             nSize = hdsa->nItemSize * nNewItems;
988
989             lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
990             if (!lpTemp)
991                 return FALSE;
992
993             hdsa->nMaxCount = nNewItems;
994             hdsa->nItemCount = nIndex + 1;
995             hdsa->pData = lpTemp;
996         }    
997     }
998
999     /* put the new entry in */
1000     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1001     TRACE("-- move dest=%p src=%p size=%d\n",
1002            pDest, pSrc, hdsa->nItemSize);
1003     memmove (pDest, pSrc, hdsa->nItemSize);
1004
1005     return TRUE;
1006 }
1007
1008
1009 /**************************************************************************
1010  * DSA_InsertItem [COMCTL32.325] 
1011  *
1012  * PARAMS
1013  *     hdsa   [I] pointer to the array control structure
1014  *     nIndex [I] index for the new item
1015  *     pSrc   [I] pointer to the element
1016  *
1017  * RETURNS
1018  *     Success: position of the new item
1019  *     Failure: -1
1020  */
1021
1022 INT WINAPI
1023 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1024 {
1025     INT   nNewItems, nSize, i;
1026     LPVOID  lpTemp, lpDest;
1027     LPDWORD p;
1028     
1029     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1030
1031     if ((!hdsa) || nIndex < 0)
1032         return -1;
1033
1034     for (i = 0; i < hdsa->nItemSize; i += 4) {
1035         p = *(DWORD**)((char *) pSrc + i);
1036         if (IsBadStringPtrA ((char*)p, 256))
1037             TRACE("-- %d=%p\n", i, (DWORD*)p);
1038         else
1039             TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
1040     }
1041    
1042     /* when nIndex > nItemCount then append */
1043     if (nIndex >= hdsa->nItemCount)
1044         nIndex = hdsa->nItemCount;
1045
1046     /* do we need to resize ? */
1047     if (hdsa->nItemCount >= hdsa->nMaxCount) {
1048         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1049         nSize = hdsa->nItemSize * nNewItems;
1050
1051         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1052         if (!lpTemp)
1053             return -1;
1054
1055         hdsa->nMaxCount = nNewItems;
1056         hdsa->pData = lpTemp;         
1057     }
1058
1059     /* do we need to move elements ? */
1060     if (nIndex < hdsa->nItemCount) {
1061         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1062         lpDest = (char *) lpTemp + hdsa->nItemSize;
1063         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1064         TRACE("-- move dest=%p src=%p size=%d\n",
1065                lpDest, lpTemp, nSize);
1066         memmove (lpDest, lpTemp, nSize);
1067     }
1068
1069     /* ok, we can put the new Item in */
1070     hdsa->nItemCount++;
1071     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1072     TRACE("-- move dest=%p src=%p size=%d\n",
1073            lpDest, pSrc, hdsa->nItemSize);
1074     memmove (lpDest, pSrc, hdsa->nItemSize);
1075
1076     return hdsa->nItemCount;
1077 }
1078
1079
1080 /**************************************************************************
1081  * DSA_DeleteItem [COMCTL32.326] 
1082  *
1083  * PARAMS
1084  *     hdsa   [I] pointer to the array control structure
1085  *     nIndex [I] index for the element to delete
1086  *
1087  * RETURNS
1088  *     Success: number of the deleted element
1089  *     Failure: -1
1090  */
1091
1092 INT WINAPI
1093 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1094 {
1095     LPVOID lpDest,lpSrc;
1096     INT  nSize;
1097     
1098     TRACE("(%p %d)\n", hdsa, nIndex);
1099
1100     if (!hdsa)
1101         return -1;
1102     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1103         return -1;
1104
1105     /* do we need to move ? */
1106     if (nIndex < hdsa->nItemCount - 1) {
1107         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1108         lpSrc = (char *) lpDest + hdsa->nItemSize;
1109         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1110         TRACE("-- move dest=%p src=%p size=%d\n",
1111                lpDest, lpSrc, nSize);
1112         memmove (lpDest, lpSrc, nSize);
1113     }
1114     
1115     hdsa->nItemCount--;
1116     
1117     /* free memory ? */
1118     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1119         nSize = hdsa->nItemSize * hdsa->nItemCount;
1120
1121         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1122         if (!lpDest)
1123             return -1;
1124
1125         hdsa->nMaxCount = hdsa->nItemCount;
1126         hdsa->pData = lpDest;
1127     }
1128
1129     return nIndex;
1130 }
1131
1132
1133 /**************************************************************************
1134  * DSA_DeleteAllItems [COMCTL32.326]
1135  *
1136  * Removes all items and reinitializes the array.
1137  *
1138  * PARAMS
1139  *     hdsa [I] pointer to the array control structure
1140  *
1141  * RETURNS
1142  *     Success: TRUE
1143  *     Failure: FALSE
1144  */
1145
1146 BOOL WINAPI
1147 DSA_DeleteAllItems (const HDSA hdsa)
1148 {
1149     TRACE("(%p)\n", hdsa);
1150
1151     if (!hdsa) 
1152         return FALSE;
1153     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1154         return FALSE;
1155
1156     hdsa->nItemCount = 0;
1157     hdsa->pData = NULL;
1158     hdsa->nMaxCount = 0;
1159
1160     return TRUE;
1161 }
1162
1163
1164 /**************************************************************************
1165  * The DPA-API is a set of functions to create and manipulate arrays of
1166  * pointers.
1167  */
1168
1169 /**************************************************************************
1170  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1171  *
1172  * PARAMS
1173  *     nGrow [I] number of items by which the array grows when it is filled
1174  *
1175  * RETURNS
1176  *     Success: handle (pointer) to the pointer array.
1177  *     Failure: NULL
1178  */
1179
1180 HDPA WINAPI
1181 DPA_Create (INT nGrow)
1182 {
1183     HDPA hdpa;
1184
1185     TRACE("(%d)\n", nGrow);
1186
1187     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1188     if (hdpa) {
1189         hdpa->nGrow = MAX(8, nGrow);
1190         hdpa->hHeap = COMCTL32_hHeap;
1191         hdpa->nMaxCount = hdpa->nGrow * 2;
1192         hdpa->ptrs =
1193             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1194     }
1195
1196     TRACE("-- %p\n", hdpa);
1197
1198     return hdpa;
1199 }
1200
1201
1202 /**************************************************************************
1203  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1204  *
1205  * PARAMS
1206  *     hdpa [I] handle (pointer) to the pointer array
1207  *
1208  * RETURNS
1209  *     Success: TRUE
1210  *     Failure: FALSE
1211  */
1212
1213 BOOL WINAPI
1214 DPA_Destroy (const HDPA hdpa)
1215 {
1216     TRACE("(%p)\n", hdpa);
1217
1218     if (!hdpa)
1219         return FALSE;
1220
1221     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1222         return FALSE;
1223
1224     return HeapFree (hdpa->hHeap, 0, hdpa);
1225 }
1226
1227
1228 /**************************************************************************
1229  * DPA_Grow [COMCTL32.330]
1230  *
1231  * Sets the growth amount.
1232  *
1233  * PARAMS
1234  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1235  *     nGrow [I] number of items, the array grows, when it's too small
1236  *
1237  * RETURNS
1238  *     Success: TRUE
1239  *     Failure: FALSE
1240  */
1241
1242 BOOL WINAPI
1243 DPA_Grow (const HDPA hdpa, INT nGrow)
1244 {
1245     TRACE("(%p %d)\n", hdpa, nGrow);
1246
1247     if (!hdpa)
1248         return FALSE;
1249
1250     hdpa->nGrow = MAX(8, nGrow);
1251
1252     return TRUE;
1253 }
1254
1255
1256 /**************************************************************************
1257  * DPA_Clone [COMCTL32.331]
1258  *
1259  * Copies a pointer array to an other one or creates a copy
1260  *
1261  * PARAMS
1262  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1263  *     hdpaNew [O] handle (pointer) to the destination pointer array
1264  *
1265  * RETURNS
1266  *     Success: pointer to the destination pointer array.
1267  *     Failure: NULL
1268  *
1269  * NOTES
1270  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1271  *       array will be created and it's handle (pointer) is returned.
1272  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1273  *       this implementation just returns NULL.
1274  */
1275
1276 HDPA WINAPI
1277 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1278 {
1279     INT nNewItems, nSize;
1280     HDPA hdpaTemp;
1281
1282     if (!hdpa)
1283         return NULL;
1284
1285     TRACE("(%p %p)\n", hdpa, hdpaNew);
1286
1287     if (!hdpaNew) {
1288         /* create a new DPA */
1289         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1290                                     sizeof(DPA));
1291         hdpaTemp->hHeap = hdpa->hHeap;
1292         hdpaTemp->nGrow = hdpa->nGrow;
1293     }
1294     else
1295         hdpaTemp = hdpaNew;
1296
1297     if (hdpaTemp->ptrs) {
1298         /* remove old pointer array */
1299         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1300         hdpaTemp->ptrs = NULL;
1301         hdpaTemp->nItemCount = 0;
1302         hdpaTemp->nMaxCount = 0;
1303     }
1304
1305     /* create a new pointer array */
1306     nNewItems = hdpaTemp->nGrow *
1307                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1308     nSize = nNewItems * sizeof(LPVOID);
1309     hdpaTemp->ptrs =
1310         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1311     hdpaTemp->nMaxCount = nNewItems;
1312
1313     /* clone the pointer array */
1314     hdpaTemp->nItemCount = hdpa->nItemCount;
1315     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1316              hdpaTemp->nItemCount * sizeof(LPVOID));
1317
1318     return hdpaTemp;
1319 }
1320
1321
1322 /**************************************************************************
1323  * DPA_GetPtr [COMCTL32.332]
1324  *
1325  * Retrieves a pointer from a dynamic pointer array
1326  *
1327  * PARAMS
1328  *     hdpa   [I] handle (pointer) to the pointer array
1329  *     nIndex [I] array index of the desired pointer
1330  *
1331  * RETURNS
1332  *     Success: pointer
1333  *     Failure: NULL
1334  */
1335
1336 LPVOID WINAPI
1337 DPA_GetPtr (const HDPA hdpa, INT i)
1338 {
1339     TRACE("(%p %d)\n", hdpa, i);
1340
1341     if (!hdpa)
1342         return NULL;
1343     if (!hdpa->ptrs)
1344         return NULL;
1345     if ((i < 0) || (i >= hdpa->nItemCount))
1346         return NULL;
1347
1348     TRACE("-- %p\n", hdpa->ptrs[i]);
1349
1350     return hdpa->ptrs[i];
1351 }
1352
1353
1354 /**************************************************************************
1355  * DPA_GetPtrIndex [COMCTL32.333]
1356  *
1357  * Retrieves the index of the specified pointer
1358  *
1359  * PARAMS
1360  *     hdpa   [I] handle (pointer) to the pointer array
1361  *     p      [I] pointer
1362  *
1363  * RETURNS
1364  *     Success: index of the specified pointer
1365  *     Failure: -1
1366  */
1367
1368 INT WINAPI
1369 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1370 {
1371     INT i;
1372
1373     if (!hdpa->ptrs)
1374         return -1;
1375
1376     for (i = 0; i < hdpa->nItemCount; i++) {
1377         if (hdpa->ptrs[i] == p)
1378             return i;
1379     }
1380
1381     return -1;
1382 }
1383
1384
1385 /**************************************************************************
1386  * DPA_InsertPtr [COMCTL32.334]
1387  *
1388  * Inserts a pointer into a dynamic pointer array
1389  *
1390  * PARAMS
1391  *     hdpa [I] handle (pointer) to the array
1392  *     i    [I] array index
1393  *     p    [I] pointer to insert
1394  *
1395  * RETURNS
1396  *     Success: index of the inserted pointer
1397  *     Failure: -1
1398  */
1399
1400 INT WINAPI
1401 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1402 {
1403     INT   nNewItems, nSize, nIndex = 0;
1404     LPVOID  *lpTemp, *lpDest;
1405
1406     TRACE("(%p %d %p)\n", hdpa, i, p);
1407
1408     if ((!hdpa) || (i < 0))
1409         return -1;
1410
1411     if (!hdpa->ptrs) {
1412         hdpa->ptrs =
1413             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1414                                 2 * hdpa->nGrow * sizeof(LPVOID));
1415         if (!hdpa->ptrs)
1416             return -1;
1417         hdpa->nMaxCount = hdpa->nGrow * 2;
1418         nIndex = 0;
1419     }
1420     else {
1421         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1422             TRACE("-- resizing\n");
1423             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1424             nSize = nNewItems * sizeof(LPVOID);
1425
1426             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1427                                            hdpa->ptrs, nSize);
1428             if (!lpTemp)
1429                 return -1;
1430             hdpa->nMaxCount = nNewItems;
1431             hdpa->ptrs = lpTemp;
1432         }
1433
1434         if (i >= hdpa->nItemCount) {
1435             nIndex = hdpa->nItemCount;
1436             TRACE("-- appending at %d\n", nIndex);
1437         }
1438         else {
1439             TRACE("-- inserting at %d\n", i);
1440             lpTemp = hdpa->ptrs + i;
1441             lpDest = lpTemp + 1;
1442             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1443             TRACE("-- move dest=%p src=%p size=%x\n",
1444                    lpDest, lpTemp, nSize);
1445             memmove (lpDest, lpTemp, nSize);
1446             nIndex = i;
1447         }
1448     }
1449
1450     /* insert item */
1451     hdpa->nItemCount++;
1452     hdpa->ptrs[nIndex] = p;
1453
1454     return nIndex;
1455 }
1456
1457
1458 /**************************************************************************
1459  * DPA_SetPtr [COMCTL32.335]
1460  *
1461  * Sets a pointer in the pointer array
1462  *
1463  * PARAMS
1464  *     hdpa [I] handle (pointer) to the pointer array
1465  *     i    [I] index of the pointer that will be set
1466  *     p    [I] pointer to be set
1467  *
1468  * RETURNS
1469  *     Success: TRUE
1470  *     Failure: FALSE
1471  */
1472
1473 BOOL WINAPI
1474 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1475 {
1476     LPVOID *lpTemp;
1477     
1478     TRACE("(%p %d %p)\n", hdpa, i, p);
1479
1480     if ((!hdpa) || i < 0)
1481         return FALSE;
1482       
1483     if (hdpa->nItemCount <= i) {
1484         /* within the old array */
1485         if (hdpa->nMaxCount > i) {
1486             /* within the allocated space, set a new boundary */
1487             hdpa->nItemCount = i;
1488         }
1489         else {
1490             /* resize the block of memory */
1491             INT nNewItems =
1492                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1493             INT nSize = nNewItems * sizeof(LPVOID);
1494
1495             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1496                                            hdpa->ptrs, nSize);
1497             if (!lpTemp)
1498                 return FALSE;
1499
1500             hdpa->nItemCount = nNewItems;
1501             hdpa->ptrs = lpTemp;        
1502         }    
1503     }
1504
1505     /* put the new entry in */
1506     hdpa->ptrs[i] = p;
1507
1508     return TRUE;
1509 }
1510
1511
1512 /**************************************************************************
1513  * DPA_DeletePtr [COMCTL32.336]
1514  *
1515  * Removes a pointer from the pointer array.
1516  *
1517  * PARAMS
1518  *     hdpa [I] handle (pointer) to the pointer array
1519  *     i    [I] index of the pointer that will be deleted
1520  *
1521  * RETURNS
1522  *     Success: deleted pointer
1523  *     Failure: NULL
1524  */
1525
1526 LPVOID WINAPI
1527 DPA_DeletePtr (const HDPA hdpa, INT i)
1528 {
1529     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1530     INT  nSize;
1531     
1532     TRACE("(%p %d)\n", hdpa, i);
1533
1534     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1535         return NULL;
1536
1537     lpTemp = hdpa->ptrs[i];
1538
1539     /* do we need to move ?*/
1540     if (i < hdpa->nItemCount - 1) {
1541         lpDest = hdpa->ptrs + i;
1542         lpSrc = lpDest + 1;
1543         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1544         TRACE("-- move dest=%p src=%p size=%x\n",
1545                lpDest, lpSrc, nSize);
1546         memmove (lpDest, lpSrc, nSize);
1547     }
1548     
1549     hdpa->nItemCount --;
1550     
1551     /* free memory ?*/
1552     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1553         INT nNewItems = MAX(hdpa->nGrow * 2, hdpa->nItemCount);
1554         nSize = nNewItems * sizeof(LPVOID);
1555         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1556                                       hdpa->ptrs, nSize);
1557         if (!lpDest)
1558             return NULL;
1559
1560         hdpa->nMaxCount = nNewItems;
1561         hdpa->ptrs = (LPVOID*)lpDest;         
1562     }
1563
1564     return lpTemp;
1565 }
1566
1567
1568 /**************************************************************************
1569  * DPA_DeleteAllPtrs [COMCTL32.337]
1570  *
1571  * Removes all pointers and reinitializes the array.
1572  *
1573  * PARAMS
1574  *     hdpa [I] handle (pointer) to the pointer array
1575  *
1576  * RETURNS
1577  *     Success: TRUE
1578  *     Failure: FALSE
1579  */
1580
1581 BOOL WINAPI
1582 DPA_DeleteAllPtrs (const HDPA hdpa)
1583 {
1584     TRACE("(%p)\n", hdpa);
1585
1586     if (!hdpa) 
1587         return FALSE;
1588
1589     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1590         return FALSE;
1591
1592     hdpa->nItemCount = 0;
1593     hdpa->nMaxCount = hdpa->nGrow * 2;
1594     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1595                                      hdpa->nMaxCount * sizeof(LPVOID));
1596
1597     return TRUE;
1598 }
1599
1600
1601 /**************************************************************************
1602  * DPA_QuickSort [Internal]
1603  *
1604  * Ordinary quicksort (used by DPA_Sort).
1605  *
1606  * PARAMS
1607  *     lpPtrs     [I] pointer to the pointer array
1608  *     l          [I] index of the "left border" of the partition
1609  *     r          [I] index of the "right border" of the partition
1610  *     pfnCompare [I] pointer to the compare function
1611  *     lParam     [I] user defined value (3rd parameter in compare function)
1612  *
1613  * RETURNS
1614  *     NONE
1615  */
1616
1617 static VOID
1618 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1619                PFNDPACOMPARE pfnCompare, LPARAM lParam)
1620 {
1621     LPVOID t, v;
1622     INT  i, j;
1623
1624     TRACE("l=%i r=%i\n", l, r);
1625  
1626     i = l;
1627     j = r;
1628     v = lpPtrs[(int)(l+r)/2];
1629     do {
1630         while ((pfnCompare)(lpPtrs[i], v, lParam) < 0) i++;
1631         while ((pfnCompare)(lpPtrs[j], v, lParam) > 0) j--;
1632         if (i <= j) 
1633         {
1634             t = lpPtrs[i];
1635             lpPtrs[i++] = lpPtrs[j];
1636             lpPtrs[j--] = t;
1637         }
1638     } while (i <= j);
1639     if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
1640     if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
1641 }
1642
1643
1644 /**************************************************************************
1645  * DPA_Sort [COMCTL32.338]
1646  *
1647  * Sorts a pointer array using a user defined compare function
1648  *
1649  * PARAMS
1650  *     hdpa       [I] handle (pointer) to the pointer array
1651  *     pfnCompare [I] pointer to the compare function
1652  *     lParam     [I] user defined value (3rd parameter of compare function)
1653  *
1654  * RETURNS
1655  *     Success: TRUE
1656  *     Failure: FALSE
1657  */
1658
1659 BOOL WINAPI
1660 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1661 {
1662     if (!hdpa || !pfnCompare)
1663         return FALSE;
1664
1665     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1666
1667     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1668         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1669                        pfnCompare, lParam);
1670
1671     return TRUE;
1672 }
1673
1674
1675 /**************************************************************************
1676  * DPA_Search [COMCTL32.339]
1677  *
1678  * Searches a pointer array for a specified pointer
1679  *
1680  * PARAMS
1681  *     hdpa       [I] handle (pointer) to the pointer array
1682  *     pFind      [I] pointer to search for
1683  *     nStart     [I] start index
1684  *     pfnCompare [I] pointer to the compare function
1685  *     lParam     [I] user defined value (3rd parameter of compare function)
1686  *     uOptions   [I] search options
1687  *
1688  * RETURNS
1689  *     Success: index of the pointer in the array.
1690  *     Failure: -1
1691  *
1692  * NOTES
1693  *     Binary search taken from R.Sedgewick "Algorithms in C"!
1694  *     Function is NOT tested!
1695  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
1696  */
1697
1698 INT WINAPI
1699 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1700             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1701 {
1702     if (!hdpa || !pfnCompare || !pFind)
1703         return -1;
1704
1705     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1706            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1707
1708     if (uOptions & DPAS_SORTED) {
1709         /* array is sorted --> use binary search */
1710         INT l, r, x, n;
1711         LPVOID *lpPtr;
1712
1713         TRACE("binary search\n");
1714
1715         l = (nStart == -1) ? 0 : nStart;
1716         r = hdpa->nItemCount - 1;
1717         lpPtr = hdpa->ptrs;
1718         while (r >= l) {
1719             x = (l + r) / 2;
1720             n = (pfnCompare)(pFind, lpPtr[x], lParam);
1721             if (n < 0)
1722                 r = x - 1;
1723             else
1724                 l = x + 1;
1725             if (n == 0) {
1726                 TRACE("-- ret=%d\n", n);
1727                 return n;
1728             }
1729         }
1730
1731         if (uOptions & DPAS_INSERTBEFORE) {
1732             TRACE("-- ret=%d\n", r);
1733             return r;
1734         }
1735
1736         if (uOptions & DPAS_INSERTAFTER) {
1737             TRACE("-- ret=%d\n", l);
1738             return l;
1739         }
1740     }
1741     else {
1742         /* array is not sorted --> use linear search */
1743         LPVOID *lpPtr;
1744         INT  nIndex;
1745
1746         TRACE("linear search\n");
1747         
1748         nIndex = (nStart == -1)? 0 : nStart;
1749         lpPtr = hdpa->ptrs;
1750         for (; nIndex < hdpa->nItemCount; nIndex++) {
1751             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1752                 TRACE("-- ret=%d\n", nIndex);
1753                 return nIndex;
1754             }
1755         }
1756     }
1757
1758     TRACE("-- not found: ret=-1\n");
1759     return -1;
1760 }
1761
1762
1763 /**************************************************************************
1764  * DPA_CreateEx [COMCTL32.340]
1765  *
1766  * Creates a dynamic pointer array using the specified size and heap.
1767  *
1768  * PARAMS
1769  *     nGrow [I] number of items by which the array grows when it is filled
1770  *     hHeap [I] handle to the heap where the array is stored
1771  *
1772  * RETURNS
1773  *     Success: handle (pointer) to the pointer array.
1774  *     Failure: NULL
1775  */
1776
1777 HDPA WINAPI
1778 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1779 {
1780     HDPA hdpa;
1781
1782     TRACE("(%d 0x%x)\n", nGrow, hHeap);
1783
1784     if (hHeap)
1785         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1786     else
1787         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1788
1789     if (hdpa) {
1790         hdpa->nGrow = MIN(8, nGrow);
1791         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1792         hdpa->nMaxCount = hdpa->nGrow * 2;
1793         hdpa->ptrs =
1794             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1795                                 hdpa->nMaxCount * sizeof(LPVOID));
1796     }
1797
1798     TRACE("-- %p\n", hdpa);
1799
1800     return hdpa;
1801 }
1802
1803
1804 /**************************************************************************
1805  * Notification functions
1806  */
1807
1808 typedef struct tagNOTIFYDATA
1809 {
1810     HWND hwndFrom;
1811     HWND hwndTo;
1812     DWORD  dwParam3;
1813     DWORD  dwParam4;
1814     DWORD  dwParam5;
1815     DWORD  dwParam6;
1816 } NOTIFYDATA, *LPNOTIFYDATA;
1817
1818
1819 /**************************************************************************
1820  * DoNotify [Internal]
1821  */
1822
1823 static LRESULT
1824 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1825 {
1826     NMHDR nmhdr;
1827     LPNMHDR lpNmh = NULL;
1828     UINT idFrom = 0;
1829
1830     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1831            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1832            lpNotify->dwParam5);
1833
1834     if (!lpNotify->hwndTo)
1835         return 0;
1836
1837     if (lpNotify->hwndFrom == -1) {
1838         lpNmh = lpHdr;
1839         idFrom = lpHdr->idFrom;
1840     }
1841     else {
1842         if (lpNotify->hwndFrom) {
1843             HWND hwndParent = GetParent (lpNotify->hwndFrom);
1844             if (hwndParent) {
1845                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1846                 if (hwndParent)
1847                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1848             }
1849         }
1850
1851         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1852
1853         lpNmh->hwndFrom = lpNotify->hwndFrom;
1854         lpNmh->idFrom = idFrom;
1855         lpNmh->code = uCode;
1856     }
1857
1858     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1859 }
1860
1861
1862 /**************************************************************************
1863  * SendNotify [COMCTL32.341]
1864  *
1865  * PARAMS
1866  *     hwndFrom [I]
1867  *     hwndTo   [I]
1868  *     uCode    [I]
1869  *     lpHdr    [I]
1870  *
1871  * RETURNS
1872  *     Success: return value from notification
1873  *     Failure: 0
1874  */
1875
1876 LRESULT WINAPI
1877 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1878                      UINT uCode, LPNMHDR lpHdr)
1879 {
1880     NOTIFYDATA notify;
1881
1882     TRACE("(0x%04x 0x%04x %d %p)\n",
1883            hwndFrom, hwndTo, uCode, lpHdr);
1884
1885     notify.hwndFrom = hwndFrom;
1886     notify.hwndTo   = hwndTo;
1887     notify.dwParam5 = 0;
1888     notify.dwParam6 = 0;
1889
1890     return DoNotify (&notify, uCode, lpHdr);
1891 }
1892
1893
1894 /**************************************************************************
1895  * SendNotifyEx [COMCTL32.342]
1896  *
1897  * PARAMS
1898  *     hwndFrom [I]
1899  *     hwndTo   [I]
1900  *     uCode    [I]
1901  *     lpHdr    [I]
1902  *     dwParam5 [I]
1903  *
1904  * RETURNS
1905  *     Success: return value from notification
1906  *     Failure: 0
1907  */
1908
1909 LRESULT WINAPI
1910 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1911                        LPNMHDR lpHdr, DWORD dwParam5)
1912 {
1913     NOTIFYDATA notify;
1914     HWND hwndNotify;
1915
1916     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1917            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1918
1919     hwndNotify = hwndTo;
1920     if (!hwndTo) {
1921         if (IsWindow (hwndFrom)) {
1922             hwndNotify = GetParent (hwndFrom);
1923             if (!hwndNotify)
1924                 return 0;
1925         }
1926     }
1927
1928     notify.hwndFrom = hwndFrom;
1929     notify.hwndTo   = hwndNotify;
1930     notify.dwParam5 = dwParam5;
1931     notify.dwParam6 = 0;
1932
1933     return DoNotify (&notify, uCode, lpHdr);
1934 }
1935
1936
1937 /**************************************************************************
1938  * StrChrA [COMCTL32.350]
1939  *
1940  */
1941
1942 LPSTR WINAPI
1943 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
1944 {
1945     return strchr (lpString, cChar);
1946 }
1947
1948
1949 /**************************************************************************
1950  * StrStrIA [COMCTL32.355]
1951  */
1952
1953 LPSTR WINAPI
1954 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
1955 {
1956     INT len1, len2, i;
1957     CHAR  first;
1958
1959     if (*lpStr2 == 0)
1960         return ((LPSTR)lpStr1);
1961     len1 = 0;
1962     while (lpStr1[len1] != 0) ++len1;
1963     len2 = 0;
1964     while (lpStr2[len2] != 0) ++len2;
1965     if (len2 == 0)
1966         return ((LPSTR)(lpStr1 + len1));
1967     first = tolower (*lpStr2);
1968     while (len1 >= len2) {
1969         if (tolower(*lpStr1) == first) {
1970             for (i = 1; i < len2; ++i)
1971                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
1972                     break;
1973             if (i >= len2)
1974                 return ((LPSTR)lpStr1);
1975         }
1976         ++lpStr1; --len1;
1977     }
1978     return (NULL);
1979 }
1980
1981
1982 /**************************************************************************
1983  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
1984  */
1985
1986 INT WINAPI
1987 COMCTL32_StrToIntA (LPSTR lpString)
1988 {
1989     return atoi(lpString);
1990 }
1991
1992
1993 /**************************************************************************
1994  * DPA_EnumCallback [COMCTL32.385]
1995  *
1996  * Enumerates all items in a dynamic pointer array.
1997  *
1998  * PARAMS
1999  *     hdpa     [I] handle to the dynamic pointer array
2000  *     enumProc [I]
2001  *     lParam   [I] 
2002  *
2003  * RETURNS
2004  *     none
2005  */
2006
2007 VOID WINAPI
2008 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2009 {
2010     INT i;
2011
2012     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2013
2014     if (!hdpa)
2015         return;
2016     if (hdpa->nItemCount <= 0)
2017         return;
2018
2019     for (i = 0; i < hdpa->nItemCount; i++) {
2020         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2021             return;
2022     }
2023
2024     return;
2025 }
2026
2027
2028 /**************************************************************************
2029  * DPA_DestroyCallback [COMCTL32.386]
2030  *
2031  * Enumerates all items in a dynamic pointer array and destroys it.
2032  *
2033  * PARAMS
2034  *     hdpa     [I] handle to the dynamic pointer array
2035  *     enumProc [I]
2036  *     lParam   [I]
2037  *
2038  * RETURNS
2039  *     Success: TRUE
2040  *     Failure: FALSE
2041  */
2042
2043 BOOL WINAPI
2044 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2045 {
2046     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2047
2048     DPA_EnumCallback (hdpa, enumProc, lParam);
2049
2050     return DPA_Destroy (hdpa);
2051 }
2052
2053
2054 /**************************************************************************
2055  * DSA_EnumCallback [COMCTL32.387]
2056  *
2057  * Enumerates all items in a dynamic storage array.
2058  *
2059  * PARAMS
2060  *     hdsa     [I] handle to the dynamic storage array
2061  *     enumProc [I]
2062  *     lParam   [I]
2063  *
2064  * RETURNS
2065  *     none
2066  */
2067
2068 VOID WINAPI
2069 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2070 {
2071     INT i;
2072
2073     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2074
2075     if (!hdsa)
2076         return;
2077     if (hdsa->nItemCount <= 0)
2078         return;
2079
2080     for (i = 0; i < hdsa->nItemCount; i++) {
2081         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2082         if ((enumProc)(lpItem, lParam) == 0)
2083             return;
2084     }
2085
2086     return;
2087 }
2088
2089
2090 /**************************************************************************
2091  * DSA_DestroyCallback [COMCTL32.388]
2092  *
2093  * Enumerates all items in a dynamic storage array and destroys it.
2094  *
2095  * PARAMS
2096  *     hdsa     [I] handle to the dynamic storage array
2097  *     enumProc [I]
2098  *     lParam   [I]
2099  *
2100  * RETURNS
2101  *     Success: TRUE
2102  *     Failure: FALSE
2103  */
2104
2105 BOOL WINAPI
2106 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2107 {
2108     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2109
2110     DSA_EnumCallback (hdsa, enumProc, lParam);
2111
2112     return DSA_Destroy (hdsa);
2113 }
2114
2115 /**************************************************************************
2116  * StrCSpnA [COMCTL32.356]
2117  *
2118  */
2119 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2120   return strcspn(lpStr, lpSet);
2121 }
2122
2123 /**************************************************************************
2124  * StrChrW [COMCTL32.358]
2125  *
2126  */
2127 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2128   return CRTDLL_wcschr(lpStart, wMatch);
2129 }
2130
2131 /**************************************************************************
2132  * StrCmpNA [COMCTL32.352]
2133  *
2134  */
2135 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2136   return strncmp(lpStr1, lpStr2, nChar);
2137 }
2138
2139 /**************************************************************************
2140  * StrCmpNIA [COMCTL32.353]
2141  *
2142  */
2143 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2144   return strncasecmp(lpStr1, lpStr2, nChar);
2145 }
2146
2147 /**************************************************************************
2148  * StrCmpNW [COMCTL32.360]
2149  *
2150  */
2151 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2152   return CRTDLL_wcsncmp(lpStr1, lpStr2, nChar);
2153 }
2154
2155 /**************************************************************************
2156  * StrCmpNIW [COMCTL32.361]
2157  *
2158  */
2159 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2160   FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2161   return 0;
2162 }
2163
2164 /**************************************************************************
2165  * StrRChrA [COMCTL32.351]
2166  *
2167  */
2168 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch) {
2169   return lstrrchr(lpStart, lpEnd, wMatch); 
2170 }
2171
2172 /**************************************************************************
2173  * StrRChrW [COMCTL32.359]
2174  *
2175  */
2176 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch) {
2177   return lstrrchrw(lpStart, lpEnd, wMatch); 
2178 }
2179
2180 /**************************************************************************
2181  * StrStrA [COMCTL32.354]
2182  *
2183  */
2184 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2185   return strstr(lpFirst, lpSrch);
2186 }
2187
2188 /**************************************************************************
2189  * StrStrW [COMCTL32.362]
2190  *
2191  */
2192 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2193   return CRTDLL_wcsstr(lpFirst, lpSrch);
2194 }
2195
2196 /**************************************************************************
2197  * StrSpnW [COMCTL32.364]
2198  *
2199  */
2200 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2201   LPWSTR lpLoop = lpStr;
2202
2203   /* validate ptr */
2204   if ((lpStr == 0) || (lpSet == 0)) return 0;
2205
2206 /* while(*lpLoop) { if lpLoop++; } */
2207
2208   for(; (*lpLoop != 0); lpLoop++)
2209     if( CRTDLL_wcschr(lpSet, *(WORD*)lpLoop))
2210       return (INT)(lpLoop-lpStr);
2211   
2212   return (INT)(lpLoop-lpStr);
2213 }
2214
2215 /**************************************************************************
2216  * comctl32_410 [COMCTL32.410]
2217  *
2218  * FIXME: What's this supposed to do?
2219  *        Parameter 1 is an HWND, you're on your own for the rest.
2220  */
2221
2222 BOOL WINAPI comctl32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2223
2224    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2225
2226    return TRUE;
2227 }
2228
2229 /**************************************************************************
2230  * comctl32_411 [COMCTL32.411]
2231  *
2232  * FIXME: What's this supposed to do?
2233  *        Parameter 1 is an HWND, you're on your own for the rest.
2234  */
2235
2236 BOOL WINAPI comctl32_411( HWND hw, DWORD b, DWORD c) {
2237
2238    FIXME("(%x, %lx, %lx): stub!\n", hw, b, c);
2239
2240    return TRUE;
2241 }
2242
2243 /**************************************************************************
2244  * comctl32_412 [COMCTL32.412]
2245  *
2246  * FIXME: What's this supposed to do?
2247  *        Parameter 1 is an HWND, you're on your own for the rest.
2248  */
2249
2250 BOOL WINAPI comctl32_412( HWND hwnd, DWORD b, DWORD c)
2251 {
2252     FIXME("(%x, %lx, %lx): stub!\n", hwnd, b, c);
2253
2254     if (IsWindow (hwnd) == FALSE)
2255         return FALSE;
2256
2257     if (b == 0)
2258         return FALSE;
2259
2260
2261     return TRUE;
2262 }
2263
2264 /**************************************************************************
2265  * comctl32_413 [COMCTL32.413]
2266  *
2267  * FIXME: What's this supposed to do?
2268  *        Parameter 1 is an HWND, you're on your own for the rest.
2269  */
2270
2271 BOOL WINAPI comctl32_413( HWND hw, DWORD b, DWORD c, DWORD d) {
2272
2273    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2274
2275    return TRUE;
2276 }
2277
2278 /*************************************************************************
2279  * InitMUILanguage [COMCTL32.70]
2280  *
2281  * FIXME: What's this supposed to do?  Apparently some i18n thing.
2282  *
2283  */
2284
2285 BOOL WINAPI InitMUILanguage( LANGID uiLang) {
2286
2287    FIXME("(%04x): stub!\n", uiLang);
2288
2289    return TRUE;
2290 }
2291