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