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