Added mappings for a few messages.
[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 "commctrl.h"
24 #include "objbase.h"
25 #include "winbase.h"
26 #include "winerror.h"
27
28 #include "wine/unicode.h"
29 #include "comctl32.h"
30
31 #include "debugtools.h"
32
33 DEFAULT_DEBUG_CHANNEL(commctrl);
34
35
36 extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
37
38
39 typedef struct _STREAMDATA
40 {
41     DWORD dwSize;
42     DWORD dwData2;
43     DWORD dwItems;
44 } STREAMDATA, *PSTREAMDATA;
45
46 typedef struct _LOADDATA
47 {
48     INT   nCount;
49     PVOID ptr;
50 } LOADDATA, *LPLOADDATA;
51
52 typedef HRESULT CALLBACK (*DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
53
54 INT __cdecl _wtoi(LPWSTR string);
55
56 /**************************************************************************
57  * DPA_LoadStream [COMCTL32.9]
58  *
59  * Loads a dynamic pointer array from a stream
60  *
61  * PARAMS
62  *     phDpa    [O] pointer to a handle to a dynamic pointer array
63  *     loadProc [I] pointer to a callback function
64  *     pStream  [I] pointer to a stream
65  *     lParam   [I] application specific value
66  *
67  * NOTES
68  *     No more information available yet!
69  */
70
71 HRESULT WINAPI
72 DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
73 {
74     HRESULT errCode;
75     LARGE_INTEGER position;
76     ULARGE_INTEGER newPosition;
77     STREAMDATA  streamData;
78     LOADDATA loadData;
79     ULONG ulRead;
80     HDPA hDpa;
81     PVOID *ptr;
82
83     FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
84            phDpa, loadProc, pStream, lParam);
85
86     if (!phDpa || !loadProc || !pStream)
87         return E_INVALIDARG;
88
89     *phDpa = (HDPA)NULL;
90
91     position.s.LowPart = 0;
92     position.s.HighPart = 0;
93
94     errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
95     if (errCode != S_OK)
96         return errCode;
97
98     errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
99     if (errCode != S_OK)
100         return errCode;
101
102     FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
103            streamData.dwSize, streamData.dwData2, streamData.dwItems);
104
105     if (lParam < sizeof(STREAMDATA) ||
106         streamData.dwSize < sizeof(STREAMDATA) ||
107         streamData.dwData2 < 1) {
108         errCode = E_FAIL;
109     }
110
111     /* create the dpa */
112     hDpa = DPA_Create (streamData.dwItems);
113     if (!hDpa)
114         return E_OUTOFMEMORY;
115
116     if (!DPA_Grow (hDpa, streamData.dwItems))
117         return E_OUTOFMEMORY;
118
119     /* load data from the stream into the dpa */
120     ptr = hDpa->ptrs;
121     for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
122         errCode = (loadProc)(&loadData, pStream, lParam);
123         if (errCode != S_OK) {
124             errCode = S_FALSE;
125             break;
126         }
127
128         *ptr = loadData.ptr;
129         ptr++;
130     }
131
132     /* set the number of items */
133     hDpa->nItemCount = loadData.nCount;
134
135     /* store the handle to the dpa */
136     *phDpa = hDpa;
137     FIXME ("new hDpa=%p\n", hDpa);
138
139     return errCode;
140 }
141
142
143 /**************************************************************************
144  * DPA_SaveStream [COMCTL32.10]
145  *
146  * Saves a dynamic pointer array to a stream
147  *
148  * PARAMS
149  *     hDpa     [I] handle to a dynamic pointer array
150  *     loadProc [I] pointer to a callback function
151  *     pStream  [I] pointer to a stream
152  *     lParam   [I] application specific value
153  *
154  * NOTES
155  *     No more information available yet!
156  */
157
158 HRESULT WINAPI
159 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
160 {
161
162     FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
163            hDpa, loadProc, pStream, lParam);
164
165     return E_FAIL;
166 }
167
168
169 /**************************************************************************
170  * DPA_Merge [COMCTL32.11]
171  *
172  * PARAMS
173  *     hdpa1       [I] handle to a dynamic pointer array
174  *     hdpa2       [I] handle to a dynamic pointer array
175  *     dwFlags     [I] flags
176  *     pfnCompare  [I] pointer to sort function
177  *     pfnMerge    [I] pointer to merge function
178  *     lParam      [I] application specific value
179  *
180  * NOTES
181  *     No more information available yet!
182  */
183
184 BOOL WINAPI
185 DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
186            PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
187 {
188     INT nCount;
189     LPVOID *pWork1, *pWork2;
190     INT nResult;
191     INT nIndex;
192
193     TRACE("%p %p %08lx %p %p %08lx)\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     /* working but untrusted implementation */
226
227     pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
228     pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
229
230     nIndex = hdpa1->nItemCount - 1;
231     nCount = hdpa2->nItemCount - 1;
232
233     do
234     {
235         if (nIndex < 0) break;
236         nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
237         TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n", 
238               nResult, nIndex, nCount);
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             nIndex--;
252             pWork1--;
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             nIndex--;
265             pWork1--;
266         }
267         else
268         {
269             if (!dwFlags & 4)
270             {
271                 PVOID ptr;
272
273                 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
274                 if (!ptr)
275                     return FALSE;
276                 DPA_InsertPtr (hdpa1, nIndex, ptr);
277             }
278             nCount--;
279             pWork2--;
280         }
281
282     }
283     while (nCount >= 0);
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  *              FreeMRUList [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 then 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 if 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  * Str_GetPtrWtoA [internal]
818  *
819  * Converts a unicode string into a multi byte string
820  *
821  * PARAMS
822  *     lpSrc   [I] Pointer to the unicode source string
823  *     lpDest  [O] Pointer to caller supplied storage for the multi byte string
824  *     nMaxLen [I] Size, in bytes, of the destination buffer
825  *
826  * RETURNS
827  *     Length, in bytes, of the converted string.
828  */
829
830 INT
831 Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
832 {
833     INT len;
834
835     TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
836
837     if (!lpDest && lpSrc)
838         return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
839
840     if (nMaxLen == 0)
841         return 0;
842
843     if (lpSrc == NULL) {
844         lpDest[0] = '\0';
845         return 0;
846     }
847
848     len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
849     if (len >= nMaxLen)
850         len = nMaxLen - 1;
851
852     WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
853     lpDest[len] = '\0';
854
855     return len;
856 }
857
858
859 /**************************************************************************
860  * Str_SetPtrAtoW [internal]
861  *
862  * Converts a multi byte string to a unicode string.
863  * If the pointer to the destination buffer is NULL a buffer is allocated.
864  * If the destination buffer is too small to keep the converted multi byte
865  * string the destination buffer is reallocated. If the source pointer is
866  * NULL, the destination buffer is freed.
867  *
868  * PARAMS
869  *     lppDest [I/O] pointer to a pointer to the destination buffer
870  *     lpSrc   [I] pointer to a multi byte string
871  *
872  * RETURNS
873  *     TRUE: conversion successful
874  *     FALSE: error
875  */
876
877 BOOL
878 Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
879 {
880     TRACE("(%p %s)\n", lppDest, lpSrc);
881
882     if (lpSrc) {
883         INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
884         LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len*sizeof(WCHAR));
885
886         if (!ptr)
887             return FALSE;
888         MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
889         *lppDest = ptr;
890     }
891     else {
892         if (*lppDest) {
893             COMCTL32_Free (*lppDest);
894             *lppDest = NULL;
895         }
896     }
897
898     return TRUE;
899 }
900
901
902 /**************************************************************************
903  * The DSA-API is a set of functions to create and manipulate arrays of
904  * fixed-size memory blocks. These arrays can store any kind of data
905  * (strings, icons...).
906  */
907
908 /**************************************************************************
909  * DSA_Create [COMCTL32.320] Creates a dynamic storage array
910  *
911  * PARAMS
912  *     nSize [I] size of the array elements
913  *     nGrow [I] number of elements by which the array grows when it is filled
914  *
915  * RETURNS
916  *     Success: pointer to an array control structure. Use this like a handle.
917  *     Failure: NULL
918  */
919
920 HDSA WINAPI
921 DSA_Create (INT nSize, INT nGrow)
922 {
923     HDSA hdsa;
924
925     TRACE("(size=%d grow=%d)\n", nSize, nGrow);
926
927     hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
928     if (hdsa)
929     {
930         hdsa->nItemCount = 0;
931         hdsa->pData = NULL;
932         hdsa->nMaxCount = 0;
933         hdsa->nItemSize = nSize;
934         hdsa->nGrow = max(1, nGrow);
935     }
936
937     return hdsa;
938 }
939
940
941 /**************************************************************************
942  * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
943  *
944  * PARAMS
945  *     hdsa [I] pointer to the array control structure
946  *
947  * RETURNS
948  *     Success: TRUE
949  *     Failure: FALSE
950  */
951
952 BOOL WINAPI
953 DSA_Destroy (const HDSA hdsa)
954 {
955     TRACE("(%p)\n", hdsa);
956
957     if (!hdsa)
958         return FALSE;
959
960     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
961         return FALSE;
962
963     return COMCTL32_Free (hdsa);
964 }
965
966
967 /**************************************************************************
968  * DSA_GetItem [COMCTL32.322] 
969  *
970  * PARAMS
971  *     hdsa   [I] pointer to the array control structure
972  *     nIndex [I] number of the Item to get
973  *     pDest  [O] destination buffer. Has to be >= dwElementSize.
974  *
975  * RETURNS
976  *     Success: TRUE
977  *     Failure: FALSE
978  */
979
980 BOOL WINAPI
981 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
982 {
983     LPVOID pSrc;
984
985     TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
986     
987     if (!hdsa)
988         return FALSE;
989     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
990         return FALSE;
991
992     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
993     memmove (pDest, pSrc, hdsa->nItemSize);
994
995     return TRUE;
996 }
997
998
999 /**************************************************************************
1000  * DSA_GetItemPtr [COMCTL32.323] 
1001  *
1002  * Retrieves a pointer to the specified item.
1003  *
1004  * PARAMS
1005  *     hdsa   [I] pointer to the array control structure
1006  *     nIndex [I] index of the desired item
1007  *
1008  * RETURNS
1009  *     Success: pointer to an item
1010  *     Failure: NULL
1011  */
1012
1013 LPVOID WINAPI
1014 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1015 {
1016     LPVOID pSrc;
1017
1018     TRACE("(%p %d)\n", hdsa, nIndex);
1019
1020     if (!hdsa)
1021         return NULL;
1022     if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1023         return NULL;
1024
1025     pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1026     
1027     TRACE("-- ret=%p\n", pSrc);
1028
1029     return pSrc;
1030 }
1031
1032
1033 /**************************************************************************
1034  * DSA_SetItem [COMCTL32.325] 
1035  *
1036  * Sets the contents of an item in the array.
1037  *
1038  * PARAMS
1039  *     hdsa   [I] pointer to the array control structure
1040  *     nIndex [I] index for the item
1041  *     pSrc   [I] pointer to the new item data
1042  *
1043  * RETURNS
1044  *     Success: TRUE
1045  *     Failure: FALSE
1046  */
1047
1048 BOOL WINAPI
1049 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1050 {
1051     INT  nSize, nNewItems;
1052     LPVOID pDest, lpTemp;
1053     
1054     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1055
1056     if ((!hdsa) || nIndex < 0)
1057         return FALSE;
1058       
1059     if (hdsa->nItemCount <= nIndex) {
1060         /* within the old array */
1061         if (hdsa->nMaxCount > nIndex) {
1062             /* within the allocated space, set a new boundary */
1063             hdsa->nItemCount = nIndex + 1;
1064         }
1065         else {
1066             /* resize the block of memory */
1067             nNewItems =
1068                 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1069             nSize = hdsa->nItemSize * nNewItems;
1070
1071             lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1072             if (!lpTemp)
1073                 return FALSE;
1074
1075             hdsa->nMaxCount = nNewItems;
1076             hdsa->nItemCount = nIndex + 1;
1077             hdsa->pData = lpTemp;
1078         }    
1079     }
1080
1081     /* put the new entry in */
1082     pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1083     TRACE("-- move dest=%p src=%p size=%d\n",
1084            pDest, pSrc, hdsa->nItemSize);
1085     memmove (pDest, pSrc, hdsa->nItemSize);
1086
1087     return TRUE;
1088 }
1089
1090
1091 /**************************************************************************
1092  * DSA_InsertItem [COMCTL32.324] 
1093  *
1094  * PARAMS
1095  *     hdsa   [I] pointer to the array control structure
1096  *     nIndex [I] index for the new item
1097  *     pSrc   [I] pointer to the element
1098  *
1099  * RETURNS
1100  *     Success: position of the new item
1101  *     Failure: -1
1102  */
1103
1104 INT WINAPI
1105 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1106 {
1107     INT   nNewItems, nSize, i;
1108     LPVOID  lpTemp, lpDest;
1109     LPDWORD p;
1110     
1111     TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1112
1113     if ((!hdsa) || nIndex < 0)
1114         return -1;
1115
1116     for (i = 0; i < hdsa->nItemSize; i += 4) {
1117         p = *(DWORD**)((char *) pSrc + i);
1118         if (IsBadStringPtrA ((char*)p, 256))
1119             TRACE("-- %d=%p\n", i, (DWORD*)p);
1120         else
1121             TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
1122     }
1123    
1124     /* when nIndex >= nItemCount then append */
1125     if (nIndex >= hdsa->nItemCount)
1126         nIndex = hdsa->nItemCount;
1127
1128     /* do we need to resize ? */
1129     if (hdsa->nItemCount >= hdsa->nMaxCount) {
1130         nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1131         nSize = hdsa->nItemSize * nNewItems;
1132
1133         lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1134         if (!lpTemp)
1135             return -1;
1136
1137         hdsa->nMaxCount = nNewItems;
1138         hdsa->pData = lpTemp;         
1139     }
1140
1141     /* do we need to move elements ? */
1142     if (nIndex < hdsa->nItemCount) {
1143         lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1144         lpDest = (char *) lpTemp + hdsa->nItemSize;
1145         nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1146         TRACE("-- move dest=%p src=%p size=%d\n",
1147                lpDest, lpTemp, nSize);
1148         memmove (lpDest, lpTemp, nSize);
1149     }
1150
1151     /* ok, we can put the new Item in */
1152     hdsa->nItemCount++;
1153     lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1154     TRACE("-- move dest=%p src=%p size=%d\n",
1155            lpDest, pSrc, hdsa->nItemSize);
1156     memmove (lpDest, pSrc, hdsa->nItemSize);
1157
1158     return nIndex;
1159 }
1160
1161
1162 /**************************************************************************
1163  * DSA_DeleteItem [COMCTL32.326] 
1164  *
1165  * PARAMS
1166  *     hdsa   [I] pointer to the array control structure
1167  *     nIndex [I] index for the element to delete
1168  *
1169  * RETURNS
1170  *     Success: number of the deleted element
1171  *     Failure: -1
1172  */
1173
1174 INT WINAPI
1175 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1176 {
1177     LPVOID lpDest,lpSrc;
1178     INT  nSize;
1179     
1180     TRACE("(%p %d)\n", hdsa, nIndex);
1181
1182     if (!hdsa)
1183         return -1;
1184     if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1185         return -1;
1186
1187     /* do we need to move ? */
1188     if (nIndex < hdsa->nItemCount - 1) {
1189         lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1190         lpSrc = (char *) lpDest + hdsa->nItemSize;
1191         nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1192         TRACE("-- move dest=%p src=%p size=%d\n",
1193                lpDest, lpSrc, nSize);
1194         memmove (lpDest, lpSrc, nSize);
1195     }
1196     
1197     hdsa->nItemCount--;
1198     
1199     /* free memory ? */
1200     if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1201         nSize = hdsa->nItemSize * hdsa->nItemCount;
1202
1203         lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1204         if (!lpDest)
1205             return -1;
1206
1207         hdsa->nMaxCount = hdsa->nItemCount;
1208         hdsa->pData = lpDest;
1209     }
1210
1211     return nIndex;
1212 }
1213
1214
1215 /**************************************************************************
1216  * DSA_DeleteAllItems [COMCTL32.327]
1217  *
1218  * Removes all items and reinitializes the array.
1219  *
1220  * PARAMS
1221  *     hdsa [I] pointer to the array control structure
1222  *
1223  * RETURNS
1224  *     Success: TRUE
1225  *     Failure: FALSE
1226  */
1227
1228 BOOL WINAPI
1229 DSA_DeleteAllItems (const HDSA hdsa)
1230 {
1231     TRACE("(%p)\n", hdsa);
1232
1233     if (!hdsa) 
1234         return FALSE;
1235     if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1236         return FALSE;
1237
1238     hdsa->nItemCount = 0;
1239     hdsa->pData = NULL;
1240     hdsa->nMaxCount = 0;
1241
1242     return TRUE;
1243 }
1244
1245
1246 /**************************************************************************
1247  * The DPA-API is a set of functions to create and manipulate arrays of
1248  * pointers.
1249  */
1250
1251 /**************************************************************************
1252  * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1253  *
1254  * PARAMS
1255  *     nGrow [I] number of items by which the array grows when it is filled
1256  *
1257  * RETURNS
1258  *     Success: handle (pointer) to the pointer array.
1259  *     Failure: NULL
1260  */
1261
1262 HDPA WINAPI
1263 DPA_Create (INT nGrow)
1264 {
1265     HDPA hdpa;
1266
1267     TRACE("(%d)\n", nGrow);
1268
1269     hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1270     if (hdpa) {
1271         hdpa->nGrow = max(8, nGrow);
1272         hdpa->hHeap = COMCTL32_hHeap;
1273         hdpa->nMaxCount = hdpa->nGrow * 2;
1274         hdpa->ptrs =
1275             (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1276     }
1277
1278     TRACE("-- %p\n", hdpa);
1279
1280     return hdpa;
1281 }
1282
1283
1284 /**************************************************************************
1285  * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1286  *
1287  * PARAMS
1288  *     hdpa [I] handle (pointer) to the pointer array
1289  *
1290  * RETURNS
1291  *     Success: TRUE
1292  *     Failure: FALSE
1293  */
1294
1295 BOOL WINAPI
1296 DPA_Destroy (const HDPA hdpa)
1297 {
1298     TRACE("(%p)\n", hdpa);
1299
1300     if (!hdpa)
1301         return FALSE;
1302
1303     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1304         return FALSE;
1305
1306     return HeapFree (hdpa->hHeap, 0, hdpa);
1307 }
1308
1309
1310 /**************************************************************************
1311  * DPA_Grow [COMCTL32.330]
1312  *
1313  * Sets the growth amount.
1314  *
1315  * PARAMS
1316  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
1317  *     nGrow [I] number of items by which the array grows when it's too small
1318  *
1319  * RETURNS
1320  *     Success: TRUE
1321  *     Failure: FALSE
1322  */
1323
1324 BOOL WINAPI
1325 DPA_Grow (const HDPA hdpa, INT nGrow)
1326 {
1327     TRACE("(%p %d)\n", hdpa, nGrow);
1328
1329     if (!hdpa)
1330         return FALSE;
1331
1332     hdpa->nGrow = max(8, nGrow);
1333
1334     return TRUE;
1335 }
1336
1337
1338 /**************************************************************************
1339  * DPA_Clone [COMCTL32.331]
1340  *
1341  * Copies a pointer array to an other one or creates a copy
1342  *
1343  * PARAMS
1344  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
1345  *     hdpaNew [O] handle (pointer) to the destination pointer array
1346  *
1347  * RETURNS
1348  *     Success: pointer to the destination pointer array.
1349  *     Failure: NULL
1350  *
1351  * NOTES
1352  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1353  *       array will be created and it's handle (pointer) is returned.
1354  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1355  *       this implementation just returns NULL.
1356  */
1357
1358 HDPA WINAPI
1359 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1360 {
1361     INT nNewItems, nSize;
1362     HDPA hdpaTemp;
1363
1364     if (!hdpa)
1365         return NULL;
1366
1367     TRACE("(%p %p)\n", hdpa, hdpaNew);
1368
1369     if (!hdpaNew) {
1370         /* create a new DPA */
1371         hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1372                                     sizeof(DPA));
1373         hdpaTemp->hHeap = hdpa->hHeap;
1374         hdpaTemp->nGrow = hdpa->nGrow;
1375     }
1376     else
1377         hdpaTemp = hdpaNew;
1378
1379     if (hdpaTemp->ptrs) {
1380         /* remove old pointer array */
1381         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1382         hdpaTemp->ptrs = NULL;
1383         hdpaTemp->nItemCount = 0;
1384         hdpaTemp->nMaxCount = 0;
1385     }
1386
1387     /* create a new pointer array */
1388     nNewItems = hdpaTemp->nGrow *
1389                 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1390     nSize = nNewItems * sizeof(LPVOID);
1391     hdpaTemp->ptrs =
1392         (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1393     hdpaTemp->nMaxCount = nNewItems;
1394
1395     /* clone the pointer array */
1396     hdpaTemp->nItemCount = hdpa->nItemCount;
1397     memmove (hdpaTemp->ptrs, hdpa->ptrs,
1398              hdpaTemp->nItemCount * sizeof(LPVOID));
1399
1400     return hdpaTemp;
1401 }
1402
1403
1404 /**************************************************************************
1405  * DPA_GetPtr [COMCTL32.332]
1406  *
1407  * Retrieves a pointer from a dynamic pointer array
1408  *
1409  * PARAMS
1410  *     hdpa   [I] handle (pointer) to the pointer array
1411  *     nIndex [I] array index of the desired pointer
1412  *
1413  * RETURNS
1414  *     Success: pointer
1415  *     Failure: NULL
1416  */
1417
1418 LPVOID WINAPI
1419 DPA_GetPtr (const HDPA hdpa, INT i)
1420 {
1421     TRACE("(%p %d)\n", hdpa, i);
1422
1423     if (!hdpa)
1424         return NULL;
1425     if (!hdpa->ptrs) {
1426         WARN("no pointer array.\n");
1427         return NULL;
1428     }
1429     if ((i < 0) || (i >= hdpa->nItemCount)) {
1430         WARN("not enough pointers in array (%d vs %d).\n",i,hdpa->nItemCount);
1431         return NULL;
1432     }
1433
1434     TRACE("-- %p\n", hdpa->ptrs[i]);
1435
1436     return hdpa->ptrs[i];
1437 }
1438
1439
1440 /**************************************************************************
1441  * DPA_GetPtrIndex [COMCTL32.333]
1442  *
1443  * Retrieves the index of the specified pointer
1444  *
1445  * PARAMS
1446  *     hdpa   [I] handle (pointer) to the pointer array
1447  *     p      [I] pointer
1448  *
1449  * RETURNS
1450  *     Success: index of the specified pointer
1451  *     Failure: -1
1452  */
1453
1454 INT WINAPI
1455 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1456 {
1457     INT i;
1458
1459     if (!hdpa->ptrs)
1460         return -1;
1461
1462     for (i = 0; i < hdpa->nItemCount; i++) {
1463         if (hdpa->ptrs[i] == p)
1464             return i;
1465     }
1466
1467     return -1;
1468 }
1469
1470
1471 /**************************************************************************
1472  * DPA_InsertPtr [COMCTL32.334]
1473  *
1474  * Inserts a pointer into a dynamic pointer array
1475  *
1476  * PARAMS
1477  *     hdpa [I] handle (pointer) to the array
1478  *     i    [I] array index
1479  *     p    [I] pointer to insert
1480  *
1481  * RETURNS
1482  *     Success: index of the inserted pointer
1483  *     Failure: -1
1484  */
1485
1486 INT WINAPI
1487 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1488 {
1489     INT   nNewItems, nSize, nIndex = 0;
1490     LPVOID  *lpTemp, *lpDest;
1491
1492     TRACE("(%p %d %p)\n", hdpa, i, p);
1493
1494     if ((!hdpa) || (i < 0))
1495         return -1;
1496
1497     if (!hdpa->ptrs) {
1498         hdpa->ptrs =
1499             (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1500                                 2 * hdpa->nGrow * sizeof(LPVOID));
1501         if (!hdpa->ptrs)
1502             return -1;
1503         hdpa->nMaxCount = hdpa->nGrow * 2;
1504         nIndex = 0;
1505     }
1506     else {
1507         if (hdpa->nItemCount >= hdpa->nMaxCount) {
1508             TRACE("-- resizing\n");
1509             nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1510             nSize = nNewItems * sizeof(LPVOID);
1511
1512             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1513                                            hdpa->ptrs, nSize);
1514             if (!lpTemp)
1515                 return -1;
1516             hdpa->nMaxCount = nNewItems;
1517             hdpa->ptrs = lpTemp;
1518         }
1519
1520         if (i >= hdpa->nItemCount) {
1521             nIndex = hdpa->nItemCount;
1522             TRACE("-- appending at %d\n", nIndex);
1523         }
1524         else {
1525             TRACE("-- inserting at %d\n", i);
1526             lpTemp = hdpa->ptrs + i;
1527             lpDest = lpTemp + 1;
1528             nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
1529             TRACE("-- move dest=%p src=%p size=%x\n",
1530                    lpDest, lpTemp, nSize);
1531             memmove (lpDest, lpTemp, nSize);
1532             nIndex = i;
1533         }
1534     }
1535
1536     /* insert item */
1537     hdpa->nItemCount++;
1538     hdpa->ptrs[nIndex] = p;
1539
1540     return nIndex;
1541 }
1542
1543
1544 /**************************************************************************
1545  * DPA_SetPtr [COMCTL32.335]
1546  *
1547  * Sets a pointer in the pointer array
1548  *
1549  * PARAMS
1550  *     hdpa [I] handle (pointer) to the pointer array
1551  *     i    [I] index of the pointer that will be set
1552  *     p    [I] pointer to be set
1553  *
1554  * RETURNS
1555  *     Success: TRUE
1556  *     Failure: FALSE
1557  */
1558
1559 BOOL WINAPI
1560 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1561 {
1562     LPVOID *lpTemp;
1563     
1564     TRACE("(%p %d %p)\n", hdpa, i, p);
1565
1566     if ((!hdpa) || i < 0)
1567         return FALSE;
1568       
1569     if (hdpa->nItemCount <= i) {
1570         /* within the old array */
1571         if (hdpa->nMaxCount > i) {
1572             /* within the allocated space, set a new boundary */
1573             hdpa->nItemCount = i+1;
1574         }
1575         else {
1576             /* resize the block of memory */
1577             INT nNewItems =
1578                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1579             INT nSize = nNewItems * sizeof(LPVOID);
1580
1581             lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1582                                            hdpa->ptrs, nSize);
1583             if (!lpTemp)
1584                 return FALSE;
1585
1586             hdpa->nItemCount = nNewItems;
1587             hdpa->ptrs = lpTemp;        
1588         }    
1589     }
1590
1591     /* put the new entry in */
1592     hdpa->ptrs[i] = p;
1593
1594     return TRUE;
1595 }
1596
1597
1598 /**************************************************************************
1599  * DPA_DeletePtr [COMCTL32.336]
1600  *
1601  * Removes a pointer from the pointer array.
1602  *
1603  * PARAMS
1604  *     hdpa [I] handle (pointer) to the pointer array
1605  *     i    [I] index of the pointer that will be deleted
1606  *
1607  * RETURNS
1608  *     Success: deleted pointer
1609  *     Failure: NULL
1610  */
1611
1612 LPVOID WINAPI
1613 DPA_DeletePtr (const HDPA hdpa, INT i)
1614 {
1615     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1616     INT  nSize;
1617     
1618     TRACE("(%p %d)\n", hdpa, i);
1619
1620     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1621         return NULL;
1622
1623     lpTemp = hdpa->ptrs[i];
1624
1625     /* do we need to move ?*/
1626     if (i < hdpa->nItemCount - 1) {
1627         lpDest = hdpa->ptrs + i;
1628         lpSrc = lpDest + 1;
1629         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1630         TRACE("-- move dest=%p src=%p size=%x\n",
1631                lpDest, lpSrc, nSize);
1632         memmove (lpDest, lpSrc, nSize);
1633     }
1634     
1635     hdpa->nItemCount --;
1636     
1637     /* free memory ?*/
1638     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1639         INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
1640         nSize = nNewItems * sizeof(LPVOID);
1641         lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1642                                       hdpa->ptrs, nSize);
1643         if (!lpDest)
1644             return NULL;
1645
1646         hdpa->nMaxCount = nNewItems;
1647         hdpa->ptrs = (LPVOID*)lpDest;         
1648     }
1649
1650     return lpTemp;
1651 }
1652
1653
1654 /**************************************************************************
1655  * DPA_DeleteAllPtrs [COMCTL32.337]
1656  *
1657  * Removes all pointers and reinitializes the array.
1658  *
1659  * PARAMS
1660  *     hdpa [I] handle (pointer) to the pointer array
1661  *
1662  * RETURNS
1663  *     Success: TRUE
1664  *     Failure: FALSE
1665  */
1666
1667 BOOL WINAPI
1668 DPA_DeleteAllPtrs (const HDPA hdpa)
1669 {
1670     TRACE("(%p)\n", hdpa);
1671
1672     if (!hdpa) 
1673         return FALSE;
1674
1675     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1676         return FALSE;
1677
1678     hdpa->nItemCount = 0;
1679     hdpa->nMaxCount = hdpa->nGrow * 2;
1680     hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1681                                      hdpa->nMaxCount * sizeof(LPVOID));
1682
1683     return TRUE;
1684 }
1685
1686
1687 /**************************************************************************
1688  * DPA_QuickSort [Internal]
1689  *
1690  * Ordinary quicksort (used by DPA_Sort).
1691  *
1692  * PARAMS
1693  *     lpPtrs     [I] pointer to the pointer array
1694  *     l          [I] index of the "left border" of the partition
1695  *     r          [I] index of the "right border" of the partition
1696  *     pfnCompare [I] pointer to the compare function
1697  *     lParam     [I] user defined value (3rd parameter in compare function)
1698  *
1699  * RETURNS
1700  *     NONE
1701  */
1702
1703 static VOID
1704 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1705                PFNDPACOMPARE pfnCompare, LPARAM lParam)
1706 {
1707     INT m;
1708     LPVOID t;
1709
1710     TRACE("l=%i r=%i\n", l, r);
1711  
1712     if (l==r)    /* one element is always sorted */
1713         return;
1714     if (r<l)     /* oops, got it in the wrong order */
1715         {
1716         DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
1717         return;
1718         }
1719     m = (l+r)/2; /* divide by two */
1720     DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
1721     DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
1722
1723     /* join the two sides */
1724     while( (l<=m) && (m<r) ) 
1725     {
1726         if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
1727         {
1728             t = lpPtrs[m+1];
1729             memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof lpPtrs[l]);
1730             lpPtrs[l] = t;
1731
1732             m++;
1733         }
1734         l++;
1735     }
1736 }
1737
1738
1739 /**************************************************************************
1740  * DPA_Sort [COMCTL32.338]
1741  *
1742  * Sorts a pointer array using a user defined compare function
1743  *
1744  * PARAMS
1745  *     hdpa       [I] handle (pointer) to the pointer array
1746  *     pfnCompare [I] pointer to the compare function
1747  *     lParam     [I] user defined value (3rd parameter of compare function)
1748  *
1749  * RETURNS
1750  *     Success: TRUE
1751  *     Failure: FALSE
1752  */
1753
1754 BOOL WINAPI
1755 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1756 {
1757     if (!hdpa || !pfnCompare)
1758         return FALSE;
1759
1760     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1761
1762     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1763         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1764                        pfnCompare, lParam);
1765
1766     return TRUE;
1767 }
1768
1769
1770 /**************************************************************************
1771  * DPA_Search [COMCTL32.339]
1772  *
1773  * Searches a pointer array for a specified pointer
1774  *
1775  * PARAMS
1776  *     hdpa       [I] handle (pointer) to the pointer array
1777  *     pFind      [I] pointer to search for
1778  *     nStart     [I] start index
1779  *     pfnCompare [I] pointer to the compare function
1780  *     lParam     [I] user defined value (3rd parameter of compare function)
1781  *     uOptions   [I] search options
1782  *
1783  * RETURNS
1784  *     Success: index of the pointer in the array.
1785  *     Failure: -1
1786  *
1787  * NOTES
1788  *     Binary search taken from R.Sedgewick "Algorithms in C"!
1789  *     Function is NOT tested!
1790  *     If something goes wrong, blame HIM not ME! (Eric Kohl)
1791  */
1792
1793 INT WINAPI
1794 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1795             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1796 {
1797     if (!hdpa || !pfnCompare || !pFind)
1798         return -1;
1799
1800     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1801            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1802
1803     if (uOptions & DPAS_SORTED) {
1804         /* array is sorted --> use binary search */
1805         INT l, r, x, n;
1806         LPVOID *lpPtr;
1807
1808         TRACE("binary search\n");
1809
1810         l = (nStart == -1) ? 0 : nStart;
1811         r = hdpa->nItemCount - 1;
1812         lpPtr = hdpa->ptrs;
1813         while (r >= l) {
1814             x = (l + r) / 2;
1815             n = (pfnCompare)(pFind, lpPtr[x], lParam);
1816             if (n < 0)
1817                 r = x - 1;
1818             else
1819                 l = x + 1;
1820             if (n == 0) {
1821                 TRACE("-- ret=%d\n", n);
1822                 return n;
1823             }
1824         }
1825
1826         if (uOptions & DPAS_INSERTBEFORE) {
1827             TRACE("-- ret=%d\n", r);
1828             return r;
1829         }
1830
1831         if (uOptions & DPAS_INSERTAFTER) {
1832             TRACE("-- ret=%d\n", l);
1833             return l;
1834         }
1835     }
1836     else {
1837         /* array is not sorted --> use linear search */
1838         LPVOID *lpPtr;
1839         INT  nIndex;
1840
1841         TRACE("linear search\n");
1842         
1843         nIndex = (nStart == -1)? 0 : nStart;
1844         lpPtr = hdpa->ptrs;
1845         for (; nIndex < hdpa->nItemCount; nIndex++) {
1846             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1847                 TRACE("-- ret=%d\n", nIndex);
1848                 return nIndex;
1849             }
1850         }
1851     }
1852
1853     TRACE("-- not found: ret=-1\n");
1854     return -1;
1855 }
1856
1857
1858 /**************************************************************************
1859  * DPA_CreateEx [COMCTL32.340]
1860  *
1861  * Creates a dynamic pointer array using the specified size and heap.
1862  *
1863  * PARAMS
1864  *     nGrow [I] number of items by which the array grows when it is filled
1865  *     hHeap [I] handle to the heap where the array is stored
1866  *
1867  * RETURNS
1868  *     Success: handle (pointer) to the pointer array.
1869  *     Failure: NULL
1870  */
1871
1872 HDPA WINAPI
1873 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1874 {
1875     HDPA hdpa;
1876
1877     TRACE("(%d 0x%x)\n", nGrow, hHeap);
1878
1879     if (hHeap)
1880         hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1881     else
1882         hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1883
1884     if (hdpa) {
1885         hdpa->nGrow = min(8, nGrow);
1886         hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1887         hdpa->nMaxCount = hdpa->nGrow * 2;
1888         hdpa->ptrs =
1889             (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1890                                 hdpa->nMaxCount * sizeof(LPVOID));
1891     }
1892
1893     TRACE("-- %p\n", hdpa);
1894
1895     return hdpa;
1896 }
1897
1898
1899 /**************************************************************************
1900  * Notification functions
1901  */
1902
1903 typedef struct tagNOTIFYDATA
1904 {
1905     HWND hwndFrom;
1906     HWND hwndTo;
1907     DWORD  dwParam3;
1908     DWORD  dwParam4;
1909     DWORD  dwParam5;
1910     DWORD  dwParam6;
1911 } NOTIFYDATA, *LPNOTIFYDATA;
1912
1913
1914 /**************************************************************************
1915  * DoNotify [Internal]
1916  */
1917
1918 static LRESULT
1919 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1920 {
1921     NMHDR nmhdr;
1922     LPNMHDR lpNmh = NULL;
1923     UINT idFrom = 0;
1924
1925     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1926            lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1927            lpNotify->dwParam5);
1928
1929     if (!lpNotify->hwndTo)
1930         return 0;
1931
1932     if (lpNotify->hwndFrom == -1) {
1933         lpNmh = lpHdr;
1934         idFrom = lpHdr->idFrom;
1935     }
1936     else {
1937         if (lpNotify->hwndFrom) {
1938             HWND hwndParent = GetParent (lpNotify->hwndFrom);
1939             if (hwndParent) {
1940                 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1941                 if (hwndParent)
1942                     idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1943             }
1944         }
1945
1946         lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1947
1948         lpNmh->hwndFrom = lpNotify->hwndFrom;
1949         lpNmh->idFrom = idFrom;
1950         lpNmh->code = uCode;
1951     }
1952
1953     return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1954 }
1955
1956
1957 /**************************************************************************
1958  * SendNotify [COMCTL32.341]
1959  *
1960  * PARAMS
1961  *     hwndFrom [I]
1962  *     hwndTo   [I]
1963  *     uCode    [I]
1964  *     lpHdr    [I]
1965  *
1966  * RETURNS
1967  *     Success: return value from notification
1968  *     Failure: 0
1969  */
1970
1971 LRESULT WINAPI
1972 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1973                      UINT uCode, LPNMHDR lpHdr)
1974 {
1975     NOTIFYDATA notify;
1976
1977     TRACE("(0x%04x 0x%04x %d %p)\n",
1978            hwndFrom, hwndTo, uCode, lpHdr);
1979
1980     notify.hwndFrom = hwndFrom;
1981     notify.hwndTo   = hwndTo;
1982     notify.dwParam5 = 0;
1983     notify.dwParam6 = 0;
1984
1985     return DoNotify (&notify, uCode, lpHdr);
1986 }
1987
1988
1989 /**************************************************************************
1990  * SendNotifyEx [COMCTL32.342]
1991  *
1992  * PARAMS
1993  *     hwndFrom [I]
1994  *     hwndTo   [I]
1995  *     uCode    [I]
1996  *     lpHdr    [I]
1997  *     dwParam5 [I]
1998  *
1999  * RETURNS
2000  *     Success: return value from notification
2001  *     Failure: 0
2002  */
2003
2004 LRESULT WINAPI
2005 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2006                        LPNMHDR lpHdr, DWORD dwParam5)
2007 {
2008     NOTIFYDATA notify;
2009     HWND hwndNotify;
2010
2011     TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
2012            hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2013
2014     hwndNotify = hwndTo;
2015     if (!hwndTo) {
2016         if (IsWindow (hwndFrom)) {
2017             hwndNotify = GetParent (hwndFrom);
2018             if (!hwndNotify)
2019                 return 0;
2020         }
2021     }
2022
2023     notify.hwndFrom = hwndFrom;
2024     notify.hwndTo   = hwndNotify;
2025     notify.dwParam5 = dwParam5;
2026     notify.dwParam6 = 0;
2027
2028     return DoNotify (&notify, uCode, lpHdr);
2029 }
2030
2031
2032 /**************************************************************************
2033  * StrChrA [COMCTL32.350]
2034  *
2035  */
2036
2037 LPSTR WINAPI
2038 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
2039 {
2040     return strchr (lpString, cChar);
2041 }
2042
2043
2044 /**************************************************************************
2045  * StrStrIA [COMCTL32.355]
2046  */
2047
2048 LPSTR WINAPI
2049 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
2050 {
2051     INT len1, len2, i;
2052     CHAR  first;
2053
2054     if (*lpStr2 == 0)
2055         return ((LPSTR)lpStr1);
2056     len1 = 0;
2057     while (lpStr1[len1] != 0) ++len1;
2058     len2 = 0;
2059     while (lpStr2[len2] != 0) ++len2;
2060     if (len2 == 0)
2061         return ((LPSTR)(lpStr1 + len1));
2062     first = tolower (*lpStr2);
2063     while (len1 >= len2) {
2064         if (tolower(*lpStr1) == first) {
2065             for (i = 1; i < len2; ++i)
2066                 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
2067                     break;
2068             if (i >= len2)
2069                 return ((LPSTR)lpStr1);
2070         }
2071         ++lpStr1; --len1;
2072     }
2073     return (NULL);
2074 }
2075
2076
2077 /**************************************************************************
2078  * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
2079  */
2080
2081 INT WINAPI
2082 COMCTL32_StrToIntA (LPSTR lpString)
2083 {
2084     return atoi(lpString);
2085 }
2086
2087 /**************************************************************************
2088  * StrToIntW [COMCTL32.365] Converts a wide char string to a signed integer.
2089  */
2090
2091 INT WINAPI
2092 COMCTL32_StrToIntW (LPWSTR lpString)
2093 {
2094     return _wtoi(lpString);
2095 }
2096
2097
2098 /**************************************************************************
2099  * DPA_EnumCallback [COMCTL32.385]
2100  *
2101  * Enumerates all items in a dynamic pointer array.
2102  *
2103  * PARAMS
2104  *     hdpa     [I] handle to the dynamic pointer array
2105  *     enumProc [I]
2106  *     lParam   [I] 
2107  *
2108  * RETURNS
2109  *     none
2110  */
2111
2112 VOID WINAPI
2113 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2114 {
2115     INT i;
2116
2117     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2118
2119     if (!hdpa)
2120         return;
2121     if (hdpa->nItemCount <= 0)
2122         return;
2123
2124     for (i = 0; i < hdpa->nItemCount; i++) {
2125         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2126             return;
2127     }
2128
2129     return;
2130 }
2131
2132
2133 /**************************************************************************
2134  * DPA_DestroyCallback [COMCTL32.386]
2135  *
2136  * Enumerates all items in a dynamic pointer array and destroys it.
2137  *
2138  * PARAMS
2139  *     hdpa     [I] handle to the dynamic pointer array
2140  *     enumProc [I]
2141  *     lParam   [I]
2142  *
2143  * RETURNS
2144  *     Success: TRUE
2145  *     Failure: FALSE
2146  */
2147
2148 BOOL WINAPI
2149 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2150 {
2151     TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2152
2153     DPA_EnumCallback (hdpa, enumProc, lParam);
2154
2155     return DPA_Destroy (hdpa);
2156 }
2157
2158
2159 /**************************************************************************
2160  * DSA_EnumCallback [COMCTL32.387]
2161  *
2162  * Enumerates all items in a dynamic storage array.
2163  *
2164  * PARAMS
2165  *     hdsa     [I] handle to the dynamic storage array
2166  *     enumProc [I]
2167  *     lParam   [I]
2168  *
2169  * RETURNS
2170  *     none
2171  */
2172
2173 VOID WINAPI
2174 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2175 {
2176     INT i;
2177
2178     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2179
2180     if (!hdsa)
2181         return;
2182     if (hdsa->nItemCount <= 0)
2183         return;
2184
2185     for (i = 0; i < hdsa->nItemCount; i++) {
2186         LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2187         if ((enumProc)(lpItem, lParam) == 0)
2188             return;
2189     }
2190
2191     return;
2192 }
2193
2194
2195 /**************************************************************************
2196  * DSA_DestroyCallback [COMCTL32.388]
2197  *
2198  * Enumerates all items in a dynamic storage array and destroys it.
2199  *
2200  * PARAMS
2201  *     hdsa     [I] handle to the dynamic storage array
2202  *     enumProc [I]
2203  *     lParam   [I]
2204  *
2205  * RETURNS
2206  *     Success: TRUE
2207  *     Failure: FALSE
2208  */
2209
2210 BOOL WINAPI
2211 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2212 {
2213     TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2214
2215     DSA_EnumCallback (hdsa, enumProc, lParam);
2216
2217     return DSA_Destroy (hdsa);
2218 }
2219
2220 /**************************************************************************
2221  * StrCSpnA [COMCTL32.356]
2222  *
2223  */
2224 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2225   return strcspn(lpStr, lpSet);
2226 }
2227
2228 /**************************************************************************
2229  * StrChrW [COMCTL32.358]
2230  *
2231  */
2232 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2233   return strchrW(lpStart, wMatch);
2234 }
2235
2236 /**************************************************************************
2237  * StrCmpNA [COMCTL32.352]
2238  *
2239  */
2240 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2241   return strncmp(lpStr1, lpStr2, nChar);
2242 }
2243
2244 /**************************************************************************
2245  * StrCmpNIA [COMCTL32.353]
2246  *
2247  */
2248 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2249   return strncasecmp(lpStr1, lpStr2, nChar);
2250 }
2251
2252 /**************************************************************************
2253  * StrCmpNW [COMCTL32.360]
2254  *
2255  */
2256 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2257   return strncmpW(lpStr1, lpStr2, nChar);
2258 }
2259
2260 /**************************************************************************
2261  * StrCmpNIW [COMCTL32.361]
2262  *
2263  */
2264 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2265   FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2266   return 0;
2267 }
2268
2269 /**************************************************************************
2270  * StrRChrA [COMCTL32.351]
2271  *
2272  */
2273 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
2274 {
2275     LPCSTR lpGotIt = NULL;
2276     BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
2277
2278     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2279
2280     if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
2281
2282     for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
2283     {
2284         if (*lpStart != LOBYTE(wMatch)) continue;
2285         if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
2286         lpGotIt = lpStart;
2287     }    
2288     return (LPSTR)lpGotIt;
2289 }
2290
2291
2292 /**************************************************************************
2293  * StrRChrW [COMCTL32.359]
2294  *
2295  */
2296 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
2297 {
2298     LPCWSTR lpGotIt = NULL;
2299
2300     TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2301     if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
2302
2303     for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
2304         if (*lpStart == wMatch) lpGotIt = lpStart;
2305
2306     return (LPWSTR)lpGotIt;
2307 }
2308
2309
2310 /**************************************************************************
2311  * StrStrA [COMCTL32.354]
2312  *
2313  */
2314 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2315   return strstr(lpFirst, lpSrch);
2316 }
2317
2318 /**************************************************************************
2319  * StrStrW [COMCTL32.362]
2320  *
2321  */
2322 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2323   return strstrW(lpFirst, lpSrch);
2324 }
2325
2326 /**************************************************************************
2327  * StrSpnW [COMCTL32.364]
2328  *
2329  */
2330 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2331   LPWSTR lpLoop = lpStr;
2332
2333   /* validate ptr */
2334   if ((lpStr == 0) || (lpSet == 0)) return 0;
2335
2336 /* while(*lpLoop) { if lpLoop++; } */
2337
2338   for(; (*lpLoop != 0); lpLoop++)
2339     if( strchrW(lpSet, *(WORD*)lpLoop))
2340       return (INT)(lpLoop-lpStr);
2341   
2342   return (INT)(lpLoop-lpStr);
2343 }
2344
2345 /**************************************************************************
2346  * @ [COMCTL32.410]
2347  *
2348  * FIXME: What's this supposed to do?
2349  *        Parameter 1 is an HWND, you're on your own for the rest.
2350  */
2351
2352 BOOL WINAPI COMCTL32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2353
2354    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2355
2356    return TRUE;
2357 }
2358
2359 /**************************************************************************
2360  * @ [COMCTL32.411]
2361  *
2362  * FIXME: What's this supposed to do?
2363  *        Parameter 1 is an HWND, you're on your own for the rest.
2364  */
2365
2366 BOOL WINAPI COMCTL32_411( HWND hw, DWORD b, DWORD c) {
2367
2368    FIXME("(%x, %lx, %lx): stub!\n", hw, b, c);
2369
2370    return TRUE;
2371 }
2372
2373 /**************************************************************************
2374  * @ [COMCTL32.412]
2375  *
2376  * FIXME: What's this supposed to do?
2377  *        Parameter 1 is an HWND, you're on your own for the rest.
2378  */
2379
2380 BOOL WINAPI COMCTL32_412( HWND hwnd, DWORD b, DWORD c)
2381 {
2382     FIXME("(%x, %lx, %lx): stub!\n", hwnd, b, c);
2383
2384     if (IsWindow (hwnd) == FALSE)
2385         return FALSE;
2386
2387     if (b == 0)
2388         return FALSE;
2389
2390
2391     return TRUE;
2392 }
2393
2394 /**************************************************************************
2395  * @ [COMCTL32.413]
2396  *
2397  * FIXME: What's this supposed to do?
2398  *        Parameter 1 is an HWND, you're on your own for the rest.
2399  */
2400
2401 BOOL WINAPI COMCTL32_413( HWND hw, DWORD b, DWORD c, DWORD d) {
2402
2403    FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2404
2405    return TRUE;
2406 }
2407
2408
2409 /**************************************************************************
2410  * @ [COMCTL32.415]
2411  *
2412  * FIXME: What's this supposed to do?
2413  *        Parameter 1 is an HWND, you're on your own for the rest.
2414  */
2415
2416 BOOL WINAPI COMCTL32_415( HWND hwnd, DWORD b, DWORD c, DWORD d, DWORD e)
2417 {
2418
2419    FIXME("(%x, %lx, %lx, %lx, %lx): stub!\n", hwnd, b, c, d, e);
2420
2421    return TRUE;
2422 }