2 * Undocumented functions from COMCTL32.DLL
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
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).
15 * - Add more functions.
16 * - Write some documentation.
20 #include <stdlib.h> /* atoi */
30 #include "wine/unicode.h"
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(commctrl);
38 extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
41 typedef struct _STREAMDATA
46 } STREAMDATA, *PSTREAMDATA;
48 typedef struct _LOADDATA
52 } LOADDATA, *LPLOADDATA;
54 typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
56 INT __cdecl _wtoi(LPWSTR string);
58 /**************************************************************************
59 * DPA_LoadStream [COMCTL32.9]
61 * Loads a dynamic pointer array from a stream
64 * phDpa [O] pointer to a handle to a dynamic pointer array
65 * loadProc [I] pointer to a callback function
66 * pStream [I] pointer to a stream
67 * lParam [I] application specific value
70 * No more information available yet!
74 DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
77 LARGE_INTEGER position;
78 ULARGE_INTEGER newPosition;
79 STREAMDATA streamData;
85 FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
86 phDpa, loadProc, pStream, lParam);
88 if (!phDpa || !loadProc || !pStream)
93 position.s.LowPart = 0;
94 position.s.HighPart = 0;
97 * Zero out our streamData
99 memset(&streamData,0,sizeof(STREAMDATA));
101 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
105 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
109 FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
110 streamData.dwSize, streamData.dwData2, streamData.dwItems);
112 if ( ulRead < sizeof(STREAMDATA) ||
113 lParam < sizeof(STREAMDATA) ||
114 streamData.dwSize < sizeof(STREAMDATA) ||
115 streamData.dwData2 < 1) {
119 if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
120 return E_OUTOFMEMORY;
123 hDpa = DPA_Create (streamData.dwItems);
125 return E_OUTOFMEMORY;
127 if (!DPA_Grow (hDpa, streamData.dwItems))
128 return E_OUTOFMEMORY;
130 /* load data from the stream into the dpa */
132 for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
133 errCode = (loadProc)(&loadData, pStream, lParam);
134 if (errCode != S_OK) {
143 /* set the number of items */
144 hDpa->nItemCount = loadData.nCount;
146 /* store the handle to the dpa */
148 FIXME ("new hDpa=%p\n", hDpa);
154 /**************************************************************************
155 * DPA_SaveStream [COMCTL32.10]
157 * Saves a dynamic pointer array to a stream
160 * hDpa [I] handle to a dynamic pointer array
161 * loadProc [I] pointer to a callback function
162 * pStream [I] pointer to a stream
163 * lParam [I] application specific value
166 * No more information available yet!
170 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
173 FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
174 hDpa, loadProc, pStream, lParam);
180 /**************************************************************************
181 * DPA_Merge [COMCTL32.11]
184 * hdpa1 [I] handle to a dynamic pointer array
185 * hdpa2 [I] handle to a dynamic pointer array
187 * pfnCompare [I] pointer to sort function
188 * pfnMerge [I] pointer to merge function
189 * lParam [I] application specific value
192 * No more information available yet!
196 DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
197 PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
200 LPVOID *pWork1, *pWork2;
204 TRACE("%p %p %08lx %p %p %08lx)\n",
205 hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
207 if (IsBadWritePtr (hdpa1, sizeof(DPA)))
210 if (IsBadWritePtr (hdpa2, sizeof(DPA)))
213 if (IsBadCodePtr ((FARPROC)pfnCompare))
216 if (IsBadCodePtr ((FARPROC)pfnMerge))
219 if (!(dwFlags & DPAM_NOSORT)) {
220 TRACE("sorting dpa's!\n");
221 if (hdpa1->nItemCount > 0)
222 DPA_Sort (hdpa1, pfnCompare, lParam);
223 TRACE ("dpa 1 sorted!\n");
224 if (hdpa2->nItemCount > 0)
225 DPA_Sort (hdpa2, pfnCompare, lParam);
226 TRACE ("dpa 2 sorted!\n");
229 if (hdpa2->nItemCount < 1)
232 TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
233 hdpa1->nItemCount, hdpa2->nItemCount);
236 /* working but untrusted implementation */
238 pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
239 pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
241 nIndex = hdpa1->nItemCount - 1;
242 nCount = hdpa2->nItemCount - 1;
247 if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) {
248 /* Now insert the remaining new items into DPA 1 */
249 TRACE("%d items to be inserted at start of DPA 1\n",
251 for (i=nCount; i>=0; i--) {
254 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
257 DPA_InsertPtr (hdpa1, 0, ptr);
263 nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
264 TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
265 nResult, nIndex, nCount);
271 ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam);
281 else if (nResult > 0)
283 /* item in DPA 1 missing from DPA 2 */
284 if (dwFlags & DPAM_DELETE)
286 /* Now delete the extra item in DPA1 */
289 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
291 (pfnMerge)(2, ptr, NULL, lParam);
298 /* new item in DPA 2 */
299 if (dwFlags & DPAM_INSERT)
301 /* Now insert the new item in DPA 1 */
304 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
307 DPA_InsertPtr (hdpa1, nIndex+1, ptr);
320 /**************************************************************************
321 * Alloc [COMCTL32.71]
323 * Allocates memory block from the dll's private heap
326 * dwSize [I] size of the allocated memory block
329 * Success: pointer to allocated memory block
334 COMCTL32_Alloc (DWORD dwSize)
338 TRACE("(0x%lx)\n", dwSize);
340 lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
342 TRACE("-- ret=%p\n", lpPtr);
348 /**************************************************************************
349 * ReAlloc [COMCTL32.72]
351 * Changes the size of an allocated memory block or allocates a memory
352 * block using the dll's private heap.
355 * lpSrc [I] pointer to memory block which will be resized
356 * dwSize [I] new size of the memory block.
359 * Success: pointer to the resized memory block
363 * If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
364 * block like COMCTL32_Alloc.
368 COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
372 TRACE("(%p 0x%08lx)\n", lpSrc, dwSize);
375 lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
377 lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
379 TRACE("-- ret=%p\n", lpDest);
385 /**************************************************************************
388 * Frees an allocated memory block from the dll's private heap.
391 * lpMem [I] pointer to memory block which will be freed
399 COMCTL32_Free (LPVOID lpMem)
401 TRACE("(%p)\n", lpMem);
403 return HeapFree (COMCTL32_hHeap, 0, lpMem);
407 /**************************************************************************
408 * GetSize [COMCTL32.74]
410 * Retrieves the size of the specified memory block from the dll's
414 * lpMem [I] pointer to an allocated memory block
417 * Success: size of the specified memory block
422 COMCTL32_GetSize (LPVOID lpMem)
424 TRACE("(%p)\n", lpMem);
426 return HeapSize (COMCTL32_hHeap, 0, lpMem);
430 /**************************************************************************
431 * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
434 * Stored in the reg. as a set of values under a single key. Each item in the
435 * list has a value name that is a single char. 'a' - 'z', '{', '|' or '}'.
436 * The order of the list is stored with value name 'MRUList' which is a string
437 * containing the value names (i.e. 'a', 'b', etc.) in the relevant order.
440 typedef struct tagCREATEMRULISTA
442 DWORD cbSize; /* size of struct */
443 DWORD nMaxItems; /* max no. of items in list */
444 DWORD dwFlags; /* see below */
445 HKEY hKey; /* root reg. key under which list is saved */
446 LPCSTR lpszSubKey; /* reg. subkey */
447 PROC lpfnCompare; /* item compare proc */
448 } CREATEMRULISTA, *LPCREATEMRULISTA;
450 typedef struct tagCREATEMRULISTW
452 DWORD cbSize; /* size of struct */
453 DWORD nMaxItems; /* max no. of items in list */
454 DWORD dwFlags; /* see below */
455 HKEY hKey; /* root reg. key under which list is saved */
456 LPCWSTR lpszSubKey; /* reg. subkey */
457 PROC lpfnCompare; /* item compare proc */
458 } CREATEMRULISTW, *LPCREATEMRULISTW;
461 #define MRUF_STRING_LIST 0 /* list will contain strings */
462 #define MRUF_BINARY_LIST 1 /* list will contain binary data */
463 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
465 /* If list is a string list lpfnCompare has the following prototype
466 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
467 * for binary lists the prototype is
468 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
469 * where cbData is the no. of bytes to compare.
470 * Need to check what return value means identical - 0?
473 typedef struct tagWINEMRUITEM
475 DWORD size; /* size of data stored */
476 DWORD itemFlag; /* flags */
478 } WINEMRUITEM, *LPWINEMRUITEM;
481 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
483 typedef struct tagWINEMRULIST
485 CREATEMRULISTW extview; /* original create information */
486 BOOL isUnicode; /* is compare fn Unicode */
487 DWORD wineFlags; /* internal flags */
488 DWORD cursize; /* current size of realMRU */
489 LPSTR realMRU; /* pointer to string of index names */
490 LPWINEMRUITEM *array; /* array of pointers to data */
491 /* in 'a' to 'z' order */
492 } WINEMRULIST, *LPWINEMRULIST;
495 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */
497 /**************************************************************************
498 * MRU_SaveChanged - Localize MRU saving code
501 VOID MRU_SaveChanged( LPWINEMRULIST mp )
507 WCHAR emptyW[] = {'\0'};
509 /* or should we do the following instead of RegOpenKeyEx:
512 /* open the sub key */
513 if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
514 0, KEY_WRITE, &newkey))) {
515 /* not present - what to do ??? */
516 ERR("Can not open key, error=%d, attempting to create\n",
518 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
521 REG_OPTION_NON_VOLATILE,
522 KEY_READ | KEY_WRITE,
526 ERR("failed to create key /%s/, err=%d\n",
527 debugstr_w(mp->extview.lpszSubKey), err);
531 if (mp->wineFlags & WMRUF_CHANGED) {
532 mp->wineFlags &= ~WMRUF_CHANGED;
533 err = RegSetValueExA(newkey, "MRUList", 0, REG_SZ,
534 mp->realMRU, strlen(mp->realMRU) + 1);
536 ERR("error saving MRUList, err=%d\n", err);
538 TRACE("saving MRUList=/%s/\n", mp->realMRU);
541 for(i=0; i<mp->cursize; i++) {
542 witem = mp->array[i];
543 if (witem->itemFlag & WMRUIF_CHANGED) {
544 witem->itemFlag &= ~WMRUIF_CHANGED;
545 realname[0] = 'a' + i;
546 err = RegSetValueExW(newkey, realname, 0,
547 (mp->extview.dwFlags & MRUF_BINARY_LIST) ?
549 &witem->datastart, witem->size);
551 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
553 TRACE("saving value for name /%s/ size=%ld\n",
554 debugstr_w(realname), witem->size);
557 RegCloseKey( newkey );
560 /**************************************************************************
561 * FreeMRUList [COMCTL32.152]
564 * hMRUList [I] Handle to list.
568 FreeMRUList (HANDLE hMRUList)
570 LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList;
574 if (mp->wineFlags & WMRUF_CHANGED) {
575 /* need to open key and then save the info */
576 MRU_SaveChanged( mp );
579 for(i=0; i<mp->extview.nMaxItems; i++) {
581 COMCTL32_Free(mp->array[i]);
583 COMCTL32_Free(mp->realMRU);
584 COMCTL32_Free(mp->array);
585 COMCTL32_Free((LPWSTR)mp->extview.lpszSubKey);
586 return COMCTL32_Free(mp);
590 /**************************************************************************
591 * FindMRUData [COMCTL32.169]
593 * Searches binary list for item that matches lpData of length cbData.
594 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
595 * corresponding to item's reg. name will be stored in it ('a' -> 0).
598 * hList [I] list handle
599 * lpData [I] data to find
600 * cbData [I] length of data
601 * lpRegNum [O] position in registry (maybe NULL)
604 * Position in list 0 -> MRU. -1 if item not found.
607 FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum)
609 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
613 if (!mp->extview.lpfnCompare) {
614 ERR("MRU list not properly created. No compare procedure.\n");
618 if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
619 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
620 NULL, 0, NULL, NULL);
621 dataA = COMCTL32_Alloc(len);
622 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
625 for(i=0; i<mp->cursize; i++) {
626 if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
627 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
633 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
636 DWORD len = WideCharToMultiByte(CP_ACP, 0,
637 (LPWSTR)&mp->array[i]->datastart, -1,
638 NULL, 0, NULL, NULL);
639 LPSTR itemA = COMCTL32_Alloc(len);
641 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
642 itemA, len, NULL, NULL);
644 cmp = mp->extview.lpfnCompare(dataA, itemA);
645 COMCTL32_Free(itemA);
652 COMCTL32_Free(dataA);
657 if (lpRegNum && (ret != -1))
660 TRACE("(%08x, %p, %ld, %p) returning %d\n",
661 hList, lpData, cbData, lpRegNum, ret);
667 /**************************************************************************
668 * AddMRUData [COMCTL32.167]
670 * Add item to MRU binary list. If item already exists in list then it is
671 * simply moved up to the top of the list and not added again. If list is
672 * full then the least recently used item is removed to make room.
675 * hList [I] Handle to list.
676 * lpData [I] ptr to data to add.
677 * cbData [I] no. of bytes of data.
680 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
684 AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
686 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
690 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) < 0) {
691 /* either add a new entry or replace oldest */
692 if (mp->cursize < mp->extview.nMaxItems) {
693 /* Add in a new item */
694 replace = mp->cursize;
698 /* get the oldest entry and replace data */
699 replace = mp->realMRU[mp->cursize - 1] - 'a';
700 COMCTL32_Free(mp->array[replace]);
704 /* free up the old data */
705 COMCTL32_Free(mp->array[replace]);
708 /* Allocate space for new item and move in the data */
709 mp->array[replace] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(cbData +
710 sizeof(WINEMRUITEM));
711 witem->itemFlag |= WMRUIF_CHANGED;
712 witem->size = cbData;
713 memcpy( &witem->datastart, lpData, cbData);
715 /* now rotate MRU list */
716 mp->wineFlags |= WMRUF_CHANGED;
717 for(i=mp->cursize-1; i>=1; i--) {
718 mp->realMRU[i] = mp->realMRU[i-1];
720 mp->realMRU[0] = replace + 'a';
721 TRACE("(%08x, %p, %ld) adding data, /%c/ now most current\n",
722 hList, lpData, cbData, replace+'a');
725 if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
726 /* save changed stuff right now */
727 MRU_SaveChanged( mp );
733 /**************************************************************************
734 * AddMRUStringW [COMCTL32.401]
736 * Add item to MRU string list. If item already exists in list them it is
737 * simply moved up to the top of the list and not added again. If list is
738 * full then the least recently used item is removed to make room.
741 * hList [I] Handle to list.
742 * lpszString [I] ptr to string to add.
745 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
749 AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
751 FIXME("(%08x, %s) empty stub!\n", hList, debugstr_w(lpszString));
756 /**************************************************************************
757 * AddMRUStringA [COMCTL32.153]
760 AddMRUStringA(HANDLE hList, LPCSTR lpszString)
762 FIXME("(%08x, %s) empty stub!\n", hList, debugstr_a(lpszString));
767 /**************************************************************************
768 * DelMRUString [COMCTL32.156]
770 * Removes item from either string or binary list (despite its name)
773 * hList [I] list handle
774 * nItemPos [I] item position to remove 0 -> MRU
777 * TRUE if successful, FALSE if nItemPos is out of range.
780 DelMRUString(HANDLE hList, INT nItemPos)
782 FIXME("(%08x, %d): stub\n", hList, nItemPos);
786 /**************************************************************************
787 * FindMRUStringW [COMCTL32.402]
790 FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
796 /**************************************************************************
797 * FindMRUStringA [COMCTL32.155]
799 * Searches string list for item that matches lpszString.
800 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
801 * corresponding to item's reg. name will be stored in it ('a' -> 0).
804 * hList [I] list handle
805 * lpszString [I] string to find
806 * lpRegNum [O] position in registry (maybe NULL)
809 * Position in list 0 -> MRU. -1 if item not found.
812 FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
814 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
815 LPWSTR stringW = COMCTL32_Alloc(len * sizeof(WCHAR));
818 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
819 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
820 COMCTL32_Free(stringW);
824 /*************************************************************************
825 * CreateMRUListLazy_common
827 HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
831 DWORD datasize, dwdisp;
835 WCHAR emptyW[] = {'\0'};
837 /* get space to save indices that will turn into names
838 * but in order of most to least recently used
840 mp->realMRU = (LPSTR) COMCTL32_Alloc(mp->extview.nMaxItems + 2);
842 /* get space to save pointers to actual data in order of
843 * 'a' to 'z' (0 to n).
845 mp->array = (LPVOID) COMCTL32_Alloc(mp->extview.nMaxItems *
848 /* open the sub key */
849 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
852 REG_OPTION_NON_VOLATILE,
853 KEY_READ | KEY_WRITE,
857 /* error - what to do ??? */
858 ERR("(%lu %lu %lx %lx \"%s\" %p): Can not open key, error=%d\n",
859 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
860 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
861 mp->extview.lpfnCompare, err);
865 /* get values from key 'MRUList' */
867 datasize = mp->extview.nMaxItems + 1;
868 if((err=RegQueryValueExA( newkey, "MRUList", 0, &type, mp->realMRU,
870 /* not present - set size to 1 (will become 0 later) */
875 TRACE("MRU list = %s\n", mp->realMRU);
877 mp->cursize = datasize - 1;
878 /* datasize now has number of items in the MRUList */
880 /* get actual values for each entry */
882 for(i=0; i<mp->cursize; i++) {
883 realname[0] = 'a' + i;
884 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
885 /* not present - what to do ??? */
886 ERR("Key %s not found 1\n", debugstr_w(realname));
888 mp->array[i] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(datasize +
889 sizeof(WINEMRUITEM));
890 witem->size = datasize;
891 if(RegQueryValueExW( newkey, realname, 0, &type,
892 &witem->datastart, &datasize)) {
893 /* not present - what to do ??? */
894 ERR("Key %s not found 2\n", debugstr_w(realname));
897 RegCloseKey( newkey );
902 TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n",
903 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
904 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
905 mp->extview.lpfnCompare, mp->cursize);
909 /**************************************************************************
910 * CreateMRUListLazyW [COMCTL32.404]
913 CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
920 if (lpcml->cbSize < sizeof(CREATEMRULISTW))
923 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
924 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
925 mp->extview.lpszSubKey = COMCTL32_Alloc((strlenW(lpcml->lpszSubKey) + 1) *
927 strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
928 mp->isUnicode = TRUE;
930 return CreateMRUListLazy_common(mp);
933 /**************************************************************************
934 * CreateMRUListLazyA [COMCTL32.157]
937 CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
945 if (lpcml->cbSize < sizeof(CREATEMRULISTA))
948 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
949 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
950 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
951 mp->extview.lpszSubKey = COMCTL32_Alloc(len * sizeof(WCHAR));
952 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
953 (LPWSTR)mp->extview.lpszSubKey, len);
954 mp->isUnicode = FALSE;
955 return CreateMRUListLazy_common(mp);
958 /**************************************************************************
959 * CreateMRUListW [COMCTL32.400]
962 * lpcml [I] ptr to CREATEMRULIST structure.
965 * Handle to MRU list.
968 CreateMRUListW (LPCREATEMRULISTW lpcml)
970 return CreateMRUListLazyW(lpcml, 0, 0, 0);
973 /**************************************************************************
974 * CreateMRUListA [COMCTL32.151]
977 CreateMRUListA (LPCREATEMRULISTA lpcml)
979 return CreateMRUListLazyA (lpcml, 0, 0, 0);
983 /**************************************************************************
984 * EnumMRUListW [COMCTL32.403]
986 * Enumerate item in a list
989 * hList [I] list handle
990 * nItemPos [I] item position to enumerate
991 * lpBuffer [O] buffer to receive item
992 * nBufferSize [I] size of buffer
995 * For binary lists specifies how many bytes were copied to buffer, for
996 * string lists specifies full length of string. Enumerating past the end
997 * of list returns -1.
998 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
1001 INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1004 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1005 LPWINEMRUITEM witem;
1006 INT desired, datasize;
1008 if (nItemPos >= mp->cursize) return -1;
1009 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1010 desired = mp->realMRU[nItemPos];
1012 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1013 witem = mp->array[desired];
1014 datasize = min( witem->size, nBufferSize );
1015 memcpy( lpBuffer, &witem->datastart, datasize);
1016 TRACE("(%08x, %d, %p, %ld): returning len=%d\n",
1017 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1021 /**************************************************************************
1022 * EnumMRUListA [COMCTL32.154]
1025 INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1028 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1029 LPWINEMRUITEM witem;
1030 INT desired, datasize;
1033 if (nItemPos >= mp->cursize) return -1;
1034 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1035 desired = mp->realMRU[nItemPos];
1037 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1038 witem = mp->array[desired];
1039 if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
1040 datasize = min( witem->size, nBufferSize );
1041 memcpy( lpBuffer, &witem->datastart, datasize);
1043 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1044 NULL, 0, NULL, NULL);
1045 datasize = min( witem->size, nBufferSize );
1046 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1047 lpBuffer, datasize, NULL, NULL);
1049 TRACE("(%08x, %d, %p, %ld): returning len=%d\n",
1050 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1055 /**************************************************************************
1056 * Str_GetPtrA [COMCTL32.233]
1067 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1071 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1073 if (!lpDest && lpSrc)
1074 return strlen (lpSrc);
1079 if (lpSrc == NULL) {
1084 len = strlen (lpSrc);
1088 RtlMoveMemory (lpDest, lpSrc, len);
1095 /**************************************************************************
1096 * Str_SetPtrA [COMCTL32.234]
1106 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
1108 TRACE("(%p %p)\n", lppDest, lpSrc);
1111 LPSTR ptr = COMCTL32_ReAlloc (*lppDest, strlen (lpSrc) + 1);
1114 strcpy (ptr, lpSrc);
1119 COMCTL32_Free (*lppDest);
1128 /**************************************************************************
1129 * Str_GetPtrW [COMCTL32.235]
1140 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
1144 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1146 if (!lpDest && lpSrc)
1147 return strlenW (lpSrc);
1152 if (lpSrc == NULL) {
1157 len = strlenW (lpSrc);
1161 RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
1162 lpDest[len] = L'\0';
1168 /**************************************************************************
1169 * Str_SetPtrW [COMCTL32.236]
1179 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
1181 TRACE("(%p %p)\n", lppDest, lpSrc);
1184 INT len = strlenW (lpSrc) + 1;
1185 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
1188 strcpyW (ptr, lpSrc);
1193 COMCTL32_Free (*lppDest);
1202 /**************************************************************************
1203 * Str_GetPtrWtoA [internal]
1205 * Converts a unicode string into a multi byte string
1208 * lpSrc [I] Pointer to the unicode source string
1209 * lpDest [O] Pointer to caller supplied storage for the multi byte string
1210 * nMaxLen [I] Size, in bytes, of the destination buffer
1213 * Length, in bytes, of the converted string.
1217 Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1221 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
1223 if (!lpDest && lpSrc)
1224 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1229 if (lpSrc == NULL) {
1234 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1238 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
1245 /**************************************************************************
1246 * Str_SetPtrAtoW [internal]
1248 * Converts a multi byte string to a unicode string.
1249 * If the pointer to the destination buffer is NULL a buffer is allocated.
1250 * If the destination buffer is too small to keep the converted multi byte
1251 * string the destination buffer is reallocated. If the source pointer is
1252 * NULL, the destination buffer is freed.
1255 * lppDest [I/O] pointer to a pointer to the destination buffer
1256 * lpSrc [I] pointer to a multi byte string
1259 * TRUE: conversion successful
1264 Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1266 TRACE("(%p %s)\n", lppDest, lpSrc);
1269 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1270 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len*sizeof(WCHAR));
1274 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
1279 COMCTL32_Free (*lppDest);
1288 /**************************************************************************
1289 * The DSA-API is a set of functions to create and manipulate arrays of
1290 * fixed-size memory blocks. These arrays can store any kind of data
1291 * (strings, icons...).
1294 /**************************************************************************
1295 * DSA_Create [COMCTL32.320] Creates a dynamic storage array
1298 * nSize [I] size of the array elements
1299 * nGrow [I] number of elements by which the array grows when it is filled
1302 * Success: pointer to an array control structure. Use this like a handle.
1307 DSA_Create (INT nSize, INT nGrow)
1311 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
1313 hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
1316 hdsa->nItemCount = 0;
1318 hdsa->nMaxCount = 0;
1319 hdsa->nItemSize = nSize;
1320 hdsa->nGrow = max(1, nGrow);
1327 /**************************************************************************
1328 * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
1331 * hdsa [I] pointer to the array control structure
1339 DSA_Destroy (const HDSA hdsa)
1341 TRACE("(%p)\n", hdsa);
1346 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1349 return COMCTL32_Free (hdsa);
1353 /**************************************************************************
1354 * DSA_GetItem [COMCTL32.322]
1357 * hdsa [I] pointer to the array control structure
1358 * nIndex [I] number of the Item to get
1359 * pDest [O] destination buffer. Has to be >= dwElementSize.
1367 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
1371 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
1375 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1378 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1379 memmove (pDest, pSrc, hdsa->nItemSize);
1385 /**************************************************************************
1386 * DSA_GetItemPtr [COMCTL32.323]
1388 * Retrieves a pointer to the specified item.
1391 * hdsa [I] pointer to the array control structure
1392 * nIndex [I] index of the desired item
1395 * Success: pointer to an item
1400 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1404 TRACE("(%p %d)\n", hdsa, nIndex);
1408 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1411 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1413 TRACE("-- ret=%p\n", pSrc);
1419 /**************************************************************************
1420 * DSA_SetItem [COMCTL32.325]
1422 * Sets the contents of an item in the array.
1425 * hdsa [I] pointer to the array control structure
1426 * nIndex [I] index for the item
1427 * pSrc [I] pointer to the new item data
1435 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1437 INT nSize, nNewItems;
1438 LPVOID pDest, lpTemp;
1440 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1442 if ((!hdsa) || nIndex < 0)
1445 if (hdsa->nItemCount <= nIndex) {
1446 /* within the old array */
1447 if (hdsa->nMaxCount > nIndex) {
1448 /* within the allocated space, set a new boundary */
1449 hdsa->nItemCount = nIndex + 1;
1452 /* resize the block of memory */
1454 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1455 nSize = hdsa->nItemSize * nNewItems;
1457 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1461 hdsa->nMaxCount = nNewItems;
1462 hdsa->nItemCount = nIndex + 1;
1463 hdsa->pData = lpTemp;
1467 /* put the new entry in */
1468 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1469 TRACE("-- move dest=%p src=%p size=%d\n",
1470 pDest, pSrc, hdsa->nItemSize);
1471 memmove (pDest, pSrc, hdsa->nItemSize);
1477 /**************************************************************************
1478 * DSA_InsertItem [COMCTL32.324]
1481 * hdsa [I] pointer to the array control structure
1482 * nIndex [I] index for the new item
1483 * pSrc [I] pointer to the element
1486 * Success: position of the new item
1491 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1493 INT nNewItems, nSize;
1494 LPVOID lpTemp, lpDest;
1496 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1498 if ((!hdsa) || nIndex < 0)
1501 /* when nIndex >= nItemCount then append */
1502 if (nIndex >= hdsa->nItemCount)
1503 nIndex = hdsa->nItemCount;
1505 /* do we need to resize ? */
1506 if (hdsa->nItemCount >= hdsa->nMaxCount) {
1507 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1508 nSize = hdsa->nItemSize * nNewItems;
1510 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1514 hdsa->nMaxCount = nNewItems;
1515 hdsa->pData = lpTemp;
1518 /* do we need to move elements ? */
1519 if (nIndex < hdsa->nItemCount) {
1520 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1521 lpDest = (char *) lpTemp + hdsa->nItemSize;
1522 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1523 TRACE("-- move dest=%p src=%p size=%d\n",
1524 lpDest, lpTemp, nSize);
1525 memmove (lpDest, lpTemp, nSize);
1528 /* ok, we can put the new Item in */
1530 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1531 TRACE("-- move dest=%p src=%p size=%d\n",
1532 lpDest, pSrc, hdsa->nItemSize);
1533 memmove (lpDest, pSrc, hdsa->nItemSize);
1539 /**************************************************************************
1540 * DSA_DeleteItem [COMCTL32.326]
1543 * hdsa [I] pointer to the array control structure
1544 * nIndex [I] index for the element to delete
1547 * Success: number of the deleted element
1552 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1554 LPVOID lpDest,lpSrc;
1557 TRACE("(%p %d)\n", hdsa, nIndex);
1561 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1564 /* do we need to move ? */
1565 if (nIndex < hdsa->nItemCount - 1) {
1566 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1567 lpSrc = (char *) lpDest + hdsa->nItemSize;
1568 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1569 TRACE("-- move dest=%p src=%p size=%d\n",
1570 lpDest, lpSrc, nSize);
1571 memmove (lpDest, lpSrc, nSize);
1577 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1578 nSize = hdsa->nItemSize * hdsa->nItemCount;
1580 lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1584 hdsa->nMaxCount = hdsa->nItemCount;
1585 hdsa->pData = lpDest;
1592 /**************************************************************************
1593 * DSA_DeleteAllItems [COMCTL32.327]
1595 * Removes all items and reinitializes the array.
1598 * hdsa [I] pointer to the array control structure
1606 DSA_DeleteAllItems (const HDSA hdsa)
1608 TRACE("(%p)\n", hdsa);
1612 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1615 hdsa->nItemCount = 0;
1617 hdsa->nMaxCount = 0;
1623 /**************************************************************************
1624 * The DPA-API is a set of functions to create and manipulate arrays of
1628 /**************************************************************************
1629 * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1632 * nGrow [I] number of items by which the array grows when it is filled
1635 * Success: handle (pointer) to the pointer array.
1640 DPA_Create (INT nGrow)
1644 TRACE("(%d)\n", nGrow);
1646 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1648 hdpa->nGrow = max(8, nGrow);
1649 hdpa->hHeap = COMCTL32_hHeap;
1650 hdpa->nMaxCount = hdpa->nGrow * 2;
1652 (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1655 TRACE("-- %p\n", hdpa);
1661 /**************************************************************************
1662 * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1665 * hdpa [I] handle (pointer) to the pointer array
1673 DPA_Destroy (const HDPA hdpa)
1675 TRACE("(%p)\n", hdpa);
1680 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1683 return HeapFree (hdpa->hHeap, 0, hdpa);
1687 /**************************************************************************
1688 * DPA_Grow [COMCTL32.330]
1690 * Sets the growth amount.
1693 * hdpa [I] handle (pointer) to the existing (source) pointer array
1694 * nGrow [I] number of items by which the array grows when it's too small
1702 DPA_Grow (const HDPA hdpa, INT nGrow)
1704 TRACE("(%p %d)\n", hdpa, nGrow);
1709 hdpa->nGrow = max(8, nGrow);
1715 /**************************************************************************
1716 * DPA_Clone [COMCTL32.331]
1718 * Copies a pointer array to an other one or creates a copy
1721 * hdpa [I] handle (pointer) to the existing (source) pointer array
1722 * hdpaNew [O] handle (pointer) to the destination pointer array
1725 * Success: pointer to the destination pointer array.
1729 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1730 * array will be created and it's handle (pointer) is returned.
1731 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1732 * this implementation just returns NULL.
1736 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1738 INT nNewItems, nSize;
1744 TRACE("(%p %p)\n", hdpa, hdpaNew);
1747 /* create a new DPA */
1748 hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1750 hdpaTemp->hHeap = hdpa->hHeap;
1751 hdpaTemp->nGrow = hdpa->nGrow;
1756 if (hdpaTemp->ptrs) {
1757 /* remove old pointer array */
1758 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1759 hdpaTemp->ptrs = NULL;
1760 hdpaTemp->nItemCount = 0;
1761 hdpaTemp->nMaxCount = 0;
1764 /* create a new pointer array */
1765 nNewItems = hdpaTemp->nGrow *
1766 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1767 nSize = nNewItems * sizeof(LPVOID);
1769 (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1770 hdpaTemp->nMaxCount = nNewItems;
1772 /* clone the pointer array */
1773 hdpaTemp->nItemCount = hdpa->nItemCount;
1774 memmove (hdpaTemp->ptrs, hdpa->ptrs,
1775 hdpaTemp->nItemCount * sizeof(LPVOID));
1781 /**************************************************************************
1782 * DPA_GetPtr [COMCTL32.332]
1784 * Retrieves a pointer from a dynamic pointer array
1787 * hdpa [I] handle (pointer) to the pointer array
1788 * nIndex [I] array index of the desired pointer
1796 DPA_GetPtr (const HDPA hdpa, INT i)
1798 TRACE("(%p %d)\n", hdpa, i);
1803 WARN("no pointer array.\n");
1806 if ((i < 0) || (i >= hdpa->nItemCount)) {
1807 WARN("not enough pointers in array (%d vs %d).\n",i,hdpa->nItemCount);
1811 TRACE("-- %p\n", hdpa->ptrs[i]);
1813 return hdpa->ptrs[i];
1817 /**************************************************************************
1818 * DPA_GetPtrIndex [COMCTL32.333]
1820 * Retrieves the index of the specified pointer
1823 * hdpa [I] handle (pointer) to the pointer array
1827 * Success: index of the specified pointer
1832 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1839 for (i = 0; i < hdpa->nItemCount; i++) {
1840 if (hdpa->ptrs[i] == p)
1848 /**************************************************************************
1849 * DPA_InsertPtr [COMCTL32.334]
1851 * Inserts a pointer into a dynamic pointer array
1854 * hdpa [I] handle (pointer) to the array
1856 * p [I] pointer to insert
1859 * Success: index of the inserted pointer
1864 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1866 INT nNewItems, nSize, nIndex = 0;
1867 LPVOID *lpTemp, *lpDest;
1869 TRACE("(%p %d %p)\n", hdpa, i, p);
1871 if ((!hdpa) || (i < 0))
1876 (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1877 2 * hdpa->nGrow * sizeof(LPVOID));
1880 hdpa->nMaxCount = hdpa->nGrow * 2;
1884 if (hdpa->nItemCount >= hdpa->nMaxCount) {
1885 TRACE("-- resizing\n");
1886 nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1887 nSize = nNewItems * sizeof(LPVOID);
1889 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1893 hdpa->nMaxCount = nNewItems;
1894 hdpa->ptrs = lpTemp;
1897 if (i >= hdpa->nItemCount) {
1898 nIndex = hdpa->nItemCount;
1899 TRACE("-- appending at %d\n", nIndex);
1902 TRACE("-- inserting at %d\n", i);
1903 lpTemp = hdpa->ptrs + i;
1904 lpDest = lpTemp + 1;
1905 nSize = (hdpa->nItemCount - i) * sizeof(LPVOID);
1906 TRACE("-- move dest=%p src=%p size=%x\n",
1907 lpDest, lpTemp, nSize);
1908 memmove (lpDest, lpTemp, nSize);
1915 hdpa->ptrs[nIndex] = p;
1921 /**************************************************************************
1922 * DPA_SetPtr [COMCTL32.335]
1924 * Sets a pointer in the pointer array
1927 * hdpa [I] handle (pointer) to the pointer array
1928 * i [I] index of the pointer that will be set
1929 * p [I] pointer to be set
1937 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1941 TRACE("(%p %d %p)\n", hdpa, i, p);
1943 if ((!hdpa) || i < 0)
1946 if (hdpa->nItemCount <= i) {
1947 /* within the old array */
1948 if (hdpa->nMaxCount > i) {
1949 /* within the allocated space, set a new boundary */
1950 hdpa->nItemCount = i+1;
1953 /* resize the block of memory */
1955 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1956 INT nSize = nNewItems * sizeof(LPVOID);
1958 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1963 hdpa->nItemCount = nNewItems;
1964 hdpa->ptrs = lpTemp;
1968 /* put the new entry in */
1975 /**************************************************************************
1976 * DPA_DeletePtr [COMCTL32.336]
1978 * Removes a pointer from the pointer array.
1981 * hdpa [I] handle (pointer) to the pointer array
1982 * i [I] index of the pointer that will be deleted
1985 * Success: deleted pointer
1990 DPA_DeletePtr (const HDPA hdpa, INT i)
1992 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1995 TRACE("(%p %d)\n", hdpa, i);
1997 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
2000 lpTemp = hdpa->ptrs[i];
2002 /* do we need to move ?*/
2003 if (i < hdpa->nItemCount - 1) {
2004 lpDest = hdpa->ptrs + i;
2006 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
2007 TRACE("-- move dest=%p src=%p size=%x\n",
2008 lpDest, lpSrc, nSize);
2009 memmove (lpDest, lpSrc, nSize);
2012 hdpa->nItemCount --;
2015 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
2016 INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
2017 nSize = nNewItems * sizeof(LPVOID);
2018 lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2023 hdpa->nMaxCount = nNewItems;
2024 hdpa->ptrs = (LPVOID*)lpDest;
2031 /**************************************************************************
2032 * DPA_DeleteAllPtrs [COMCTL32.337]
2034 * Removes all pointers and reinitializes the array.
2037 * hdpa [I] handle (pointer) to the pointer array
2045 DPA_DeleteAllPtrs (const HDPA hdpa)
2047 TRACE("(%p)\n", hdpa);
2052 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2055 hdpa->nItemCount = 0;
2056 hdpa->nMaxCount = hdpa->nGrow * 2;
2057 hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2058 hdpa->nMaxCount * sizeof(LPVOID));
2064 /**************************************************************************
2065 * DPA_QuickSort [Internal]
2067 * Ordinary quicksort (used by DPA_Sort).
2070 * lpPtrs [I] pointer to the pointer array
2071 * l [I] index of the "left border" of the partition
2072 * r [I] index of the "right border" of the partition
2073 * pfnCompare [I] pointer to the compare function
2074 * lParam [I] user defined value (3rd parameter in compare function)
2081 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2082 PFNDPACOMPARE pfnCompare, LPARAM lParam)
2087 TRACE("l=%i r=%i\n", l, r);
2089 if (l==r) /* one element is always sorted */
2091 if (r<l) /* oops, got it in the wrong order */
2093 DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2096 m = (l+r)/2; /* divide by two */
2097 DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2098 DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2100 /* join the two sides */
2101 while( (l<=m) && (m<r) )
2103 if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2106 memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof lpPtrs[l]);
2116 /**************************************************************************
2117 * DPA_Sort [COMCTL32.338]
2119 * Sorts a pointer array using a user defined compare function
2122 * hdpa [I] handle (pointer) to the pointer array
2123 * pfnCompare [I] pointer to the compare function
2124 * lParam [I] user defined value (3rd parameter of compare function)
2132 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2134 if (!hdpa || !pfnCompare)
2137 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2139 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2140 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2141 pfnCompare, lParam);
2147 /**************************************************************************
2148 * DPA_Search [COMCTL32.339]
2150 * Searches a pointer array for a specified pointer
2153 * hdpa [I] handle (pointer) to the pointer array
2154 * pFind [I] pointer to search for
2155 * nStart [I] start index
2156 * pfnCompare [I] pointer to the compare function
2157 * lParam [I] user defined value (3rd parameter of compare function)
2158 * uOptions [I] search options
2161 * Success: index of the pointer in the array.
2165 * Binary search taken from R.Sedgewick "Algorithms in C"!
2166 * Function is NOT tested!
2167 * If something goes wrong, blame HIM not ME! (Eric Kohl)
2171 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2172 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2174 if (!hdpa || !pfnCompare || !pFind)
2177 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2178 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2180 if (uOptions & DPAS_SORTED) {
2181 /* array is sorted --> use binary search */
2185 TRACE("binary search\n");
2187 l = (nStart == -1) ? 0 : nStart;
2188 r = hdpa->nItemCount - 1;
2192 n = (pfnCompare)(pFind, lpPtr[x], lParam);
2198 TRACE("-- ret=%d\n", n);
2203 if (uOptions & DPAS_INSERTBEFORE) {
2204 TRACE("-- ret=%d\n", r);
2208 if (uOptions & DPAS_INSERTAFTER) {
2209 TRACE("-- ret=%d\n", l);
2214 /* array is not sorted --> use linear search */
2218 TRACE("linear search\n");
2220 nIndex = (nStart == -1)? 0 : nStart;
2222 for (; nIndex < hdpa->nItemCount; nIndex++) {
2223 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2224 TRACE("-- ret=%d\n", nIndex);
2230 TRACE("-- not found: ret=-1\n");
2235 /**************************************************************************
2236 * DPA_CreateEx [COMCTL32.340]
2238 * Creates a dynamic pointer array using the specified size and heap.
2241 * nGrow [I] number of items by which the array grows when it is filled
2242 * hHeap [I] handle to the heap where the array is stored
2245 * Success: handle (pointer) to the pointer array.
2250 DPA_CreateEx (INT nGrow, HANDLE hHeap)
2254 TRACE("(%d 0x%x)\n", nGrow, hHeap);
2257 hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
2259 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
2262 hdpa->nGrow = min(8, nGrow);
2263 hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
2264 hdpa->nMaxCount = hdpa->nGrow * 2;
2266 (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
2267 hdpa->nMaxCount * sizeof(LPVOID));
2270 TRACE("-- %p\n", hdpa);
2276 /**************************************************************************
2277 * Notification functions
2280 typedef struct tagNOTIFYDATA
2288 } NOTIFYDATA, *LPNOTIFYDATA;
2291 /**************************************************************************
2292 * DoNotify [Internal]
2296 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2299 LPNMHDR lpNmh = NULL;
2302 TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
2303 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2304 lpNotify->dwParam5);
2306 if (!lpNotify->hwndTo)
2309 if (lpNotify->hwndFrom == -1) {
2311 idFrom = lpHdr->idFrom;
2314 if (lpNotify->hwndFrom) {
2315 HWND hwndParent = GetParent (lpNotify->hwndFrom);
2317 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
2318 /* the following is done even if the return from above
2319 * is zero. GLA 12/2001 */
2320 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2324 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2326 lpNmh->hwndFrom = lpNotify->hwndFrom;
2327 lpNmh->idFrom = idFrom;
2328 lpNmh->code = uCode;
2331 return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2335 /**************************************************************************
2336 * SendNotify [COMCTL32.341]
2345 * Success: return value from notification
2350 COMCTL32_SendNotify (HWND hwndTo, HWND hwndFrom,
2351 UINT uCode, LPNMHDR lpHdr)
2355 TRACE("(0x%04x 0x%04x %d %p)\n",
2356 hwndTo, hwndFrom, uCode, lpHdr);
2358 notify.hwndFrom = hwndFrom;
2359 notify.hwndTo = hwndTo;
2360 notify.dwParam5 = 0;
2361 notify.dwParam6 = 0;
2363 return DoNotify (¬ify, uCode, lpHdr);
2367 /**************************************************************************
2368 * SendNotifyEx [COMCTL32.342]
2378 * Success: return value from notification
2383 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2384 LPNMHDR lpHdr, DWORD dwParam5)
2389 TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
2390 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2392 hwndNotify = hwndTo;
2394 if (IsWindow (hwndFrom)) {
2395 hwndNotify = GetParent (hwndFrom);
2401 notify.hwndFrom = hwndFrom;
2402 notify.hwndTo = hwndNotify;
2403 notify.dwParam5 = dwParam5;
2404 notify.dwParam6 = 0;
2406 return DoNotify (¬ify, uCode, lpHdr);
2410 /**************************************************************************
2411 * StrChrA [COMCTL32.350]
2416 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
2418 return strchr (lpString, cChar);
2422 /**************************************************************************
2423 * StrStrIA [COMCTL32.355]
2427 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
2433 return ((LPSTR)lpStr1);
2435 while (lpStr1[len1] != 0) ++len1;
2437 while (lpStr2[len2] != 0) ++len2;
2439 return ((LPSTR)(lpStr1 + len1));
2440 first = tolower (*lpStr2);
2441 while (len1 >= len2) {
2442 if (tolower(*lpStr1) == first) {
2443 for (i = 1; i < len2; ++i)
2444 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
2447 return ((LPSTR)lpStr1);
2455 /**************************************************************************
2456 * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
2460 COMCTL32_StrToIntA (LPSTR lpString)
2462 return atoi(lpString);
2465 /**************************************************************************
2466 * StrToIntW [COMCTL32.365] Converts a wide char string to a signed integer.
2470 COMCTL32_StrToIntW (LPWSTR lpString)
2472 return _wtoi(lpString);
2476 /**************************************************************************
2477 * DPA_EnumCallback [COMCTL32.385]
2479 * Enumerates all items in a dynamic pointer array.
2482 * hdpa [I] handle to the dynamic pointer array
2491 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2495 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2499 if (hdpa->nItemCount <= 0)
2502 for (i = 0; i < hdpa->nItemCount; i++) {
2503 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2511 /**************************************************************************
2512 * DPA_DestroyCallback [COMCTL32.386]
2514 * Enumerates all items in a dynamic pointer array and destroys it.
2517 * hdpa [I] handle to the dynamic pointer array
2527 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2529 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2531 DPA_EnumCallback (hdpa, enumProc, lParam);
2533 return DPA_Destroy (hdpa);
2537 /**************************************************************************
2538 * DSA_EnumCallback [COMCTL32.387]
2540 * Enumerates all items in a dynamic storage array.
2543 * hdsa [I] handle to the dynamic storage array
2552 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2556 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2560 if (hdsa->nItemCount <= 0)
2563 for (i = 0; i < hdsa->nItemCount; i++) {
2564 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2565 if ((enumProc)(lpItem, lParam) == 0)
2573 /**************************************************************************
2574 * DSA_DestroyCallback [COMCTL32.388]
2576 * Enumerates all items in a dynamic storage array and destroys it.
2579 * hdsa [I] handle to the dynamic storage array
2589 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2591 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2593 DSA_EnumCallback (hdsa, enumProc, lParam);
2595 return DSA_Destroy (hdsa);
2598 /**************************************************************************
2599 * StrCSpnA [COMCTL32.356]
2602 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2603 return strcspn(lpStr, lpSet);
2606 /**************************************************************************
2607 * StrChrW [COMCTL32.358]
2610 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2611 return strchrW(lpStart, wMatch);
2614 /**************************************************************************
2615 * StrCmpNA [COMCTL32.352]
2618 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2619 return strncmp(lpStr1, lpStr2, nChar);
2622 /**************************************************************************
2623 * StrCmpNIA [COMCTL32.353]
2626 INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2627 return strncasecmp(lpStr1, lpStr2, nChar);
2630 /**************************************************************************
2631 * StrCmpNW [COMCTL32.360]
2634 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2635 return strncmpW(lpStr1, lpStr2, nChar);
2638 /**************************************************************************
2639 * StrCmpNIW [COMCTL32.361]
2642 INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2643 FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2647 /**************************************************************************
2648 * StrRChrA [COMCTL32.351]
2651 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
2653 LPCSTR lpGotIt = NULL;
2654 BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
2656 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2658 if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
2660 for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
2662 if (*lpStart != LOBYTE(wMatch)) continue;
2663 if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
2666 return (LPSTR)lpGotIt;
2670 /**************************************************************************
2671 * StrRChrW [COMCTL32.359]
2674 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
2676 LPCWSTR lpGotIt = NULL;
2678 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2679 if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
2681 for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
2682 if (*lpStart == wMatch) lpGotIt = lpStart;
2684 return (LPWSTR)lpGotIt;
2688 /**************************************************************************
2689 * StrStrA [COMCTL32.354]
2692 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2693 return strstr(lpFirst, lpSrch);
2696 /**************************************************************************
2697 * StrStrW [COMCTL32.362]
2700 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2701 return strstrW(lpFirst, lpSrch);
2704 /**************************************************************************
2705 * StrSpnW [COMCTL32.364]
2708 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2709 LPWSTR lpLoop = lpStr;
2712 if ((lpStr == 0) || (lpSet == 0)) return 0;
2714 /* while(*lpLoop) { if lpLoop++; } */
2716 for(; (*lpLoop != 0); lpLoop++)
2717 if( strchrW(lpSet, *(WORD*)lpLoop))
2718 return (INT)(lpLoop-lpStr);
2720 return (INT)(lpLoop-lpStr);
2723 /**************************************************************************
2726 * FIXME: What's this supposed to do?
2727 * Parameter 1 is an HWND, you're on your own for the rest.
2730 BOOL WINAPI COMCTL32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2732 FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2737 /**************************************************************************
2740 * FIXME: What's this supposed to do?
2741 * Parameter 1 is an HWND, you're on your own for the rest.
2744 BOOL WINAPI COMCTL32_411( HWND hw, DWORD b, DWORD c) {
2746 FIXME("(%x, %lx, %lx): stub!\n", hw, b, c);
2751 /**************************************************************************
2754 * FIXME: What's this supposed to do?
2755 * Parameter 1 is an HWND, you're on your own for the rest.
2758 BOOL WINAPI COMCTL32_412( HWND hwnd, DWORD b, DWORD c)
2760 FIXME("(%x, %lx, %lx): stub!\n", hwnd, b, c);
2762 if (IsWindow (hwnd) == FALSE)
2772 /**************************************************************************
2775 * FIXME: What's this supposed to do?
2776 * Parameter 1 is an HWND, you're on your own for the rest.
2779 BOOL WINAPI COMCTL32_413( HWND hw, DWORD b, DWORD c, DWORD d) {
2781 FIXME("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2787 /**************************************************************************
2790 * FIXME: What's this supposed to do?
2791 * Parameter 1 is an HWND, you're on your own for the rest.
2794 BOOL WINAPI COMCTL32_415( HWND hwnd, DWORD b, DWORD c, DWORD d, DWORD e)
2797 FIXME("(%x, %lx, %lx, %lx, %lx): stub!\n", hwnd, b, c, d, e);
2802 /**************************************************************************
2805 * FIXME: What's this supposed to do?
2808 BOOL WINAPI COMCTL32_419( DWORD a, DWORD b, DWORD c, DWORD d)
2811 FIXME("(%lx, %lx, %lx, %lx): stub!\n", a, b, c, d);