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