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