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