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