2 * Undocumented functions from COMCTL32.DLL
4 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
7 * All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
8 * Do NOT rely on names or contents of undocumented structures and types!!!
9 * These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
10 * COMCTL32.DLL (internally).
13 * - Add more functions.
14 * - Write some documentation.
18 #include <stdlib.h> /* atoi */
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(commctrl)
30 extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
33 * We put some function prototypes here that don't seem to belong in
34 * any header file. When they find their place, we can remove them.
36 extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR, WCHAR);
37 extern LPSTR WINAPI lstrrchr(LPCSTR, LPCSTR, WORD);
38 extern LPWSTR WINAPI lstrrchrw(LPCWSTR, LPCWSTR, WORD);
39 extern LPWSTR WINAPI strstrw(LPCWSTR, LPCWSTR);
42 typedef struct _STREAMDATA
47 } STREAMDATA, *PSTREAMDATA;
49 typedef struct _LOADDATA
53 } LOADDATA, *LPLOADDATA;
55 typedef HRESULT(CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
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)
94 position.HighPart = 0;
96 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
100 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
104 FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
105 streamData.dwSize, streamData.dwData2, streamData.dwItems);
107 if (lParam < sizeof(STREAMDATA) ||
108 streamData.dwSize < sizeof(STREAMDATA) ||
109 streamData.dwData2 < 1) {
114 hDpa = DPA_Create (streamData.dwItems);
116 return E_OUTOFMEMORY;
118 if (!DPA_Grow (hDpa, streamData.dwItems))
119 return E_OUTOFMEMORY;
121 /* load data from the stream into the dpa */
123 for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
124 errCode = (loadProc)(&loadData, pStream, lParam);
125 if (errCode != S_OK) {
134 /* set the number of items */
135 hDpa->nItemCount = loadData.nCount;
137 /* store the handle to the dpa */
139 FIXME ("new hDpa=%p\n", hDpa);
145 /**************************************************************************
146 * DPA_SaveStream [COMCTL32.10]
148 * Saves a dynamic pointer array to a stream
151 * hDpa [I] handle to a dynamic pointer array
152 * loadProc [I] pointer to a callback function
153 * pStream [I] pointer to a stream
154 * lParam [I] application specific value
157 * No more information available yet!
161 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
164 FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
165 hDpa, loadProc, pStream, lParam);
171 /**************************************************************************
172 * DPA_Merge [COMCTL32.11]
175 * hdpa1 [I] handle to a dynamic pointer array
176 * hdpa2 [I] handle to a dynamic pointer array
178 * pfnSort [I] pointer to sort function
179 * pfnMerge [I] pointer to merge function
180 * lParam [I] application specific value
183 * No more information available yet!
187 DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
188 PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
192 #if 0 /* these go with the "incomplete implementation" below */
193 LPVOID pWork1, pWork2;
199 TRACE("(%p %p %08lx %p %p %08lx): semi stub!\n",
200 hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
202 if (IsBadWritePtr (hdpa1, sizeof(DPA)))
205 if (IsBadWritePtr (hdpa2, sizeof(DPA)))
208 if (IsBadCodePtr ((FARPROC)pfnCompare))
211 if (IsBadCodePtr ((FARPROC)pfnMerge))
214 if (dwFlags & DPAM_SORT) {
215 TRACE("sorting dpa's!\n");
216 if (hdpa1->nItemCount > 0)
217 DPA_Sort (hdpa1, pfnCompare, lParam);
218 TRACE ("dpa 1 sorted!\n");
219 if (hdpa2->nItemCount > 0)
220 DPA_Sort (hdpa2, pfnCompare, lParam);
221 TRACE ("dpa 2 sorted!\n");
224 if (hdpa2->nItemCount < 1)
227 TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
228 hdpa1->nItemCount, hdpa2->nItemCount);
231 /* preliminary hack - simply append the pointer list hdpa2 to hdpa1*/
232 for (nCount = 0; nCount < hdpa2->nItemCount; nCount++)
233 DPA_InsertPtr (hdpa1, hdpa1->nItemCount + 1, hdpa2->ptrs[nCount]);
236 /* incomplete 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;
246 nResult = (pfnCompare)(pWork1, pWork2, lParam);
252 ptr = (pfnMerge)(1, pWork1, pWork2, lParam);
260 else if (nResult < 0)
266 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
268 (pfnMerge)(2, ptr, NULL, lParam);
277 ptr = (pfnMerge)(3, pWork2, NULL, lParam);
280 DPA_InsertPtr (hdpa1, nIndex, ptr);
297 /**************************************************************************
298 * Alloc [COMCTL32.71]
300 * Allocates memory block from the dll's private heap
303 * dwSize [I] size of the allocated memory block
306 * Success: pointer to allocated memory block
311 COMCTL32_Alloc (DWORD dwSize)
315 TRACE("(0x%lx)\n", dwSize);
317 lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
319 TRACE("-- ret=%p\n", lpPtr);
325 /**************************************************************************
326 * ReAlloc [COMCTL32.72]
328 * Changes the size of an allocated memory block or allocates a memory
329 * block using the dll's private heap.
332 * lpSrc [I] pointer to memory block which will be resized
333 * dwSize [I] new size of the memory block.
336 * Success: pointer to the resized memory block
340 * If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
341 * block like COMCTL32_Alloc.
345 COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
349 TRACE("(%p 0x%08lx)\n", lpSrc, dwSize);
352 lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
354 lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
356 TRACE("-- ret=%p\n", lpDest);
362 /**************************************************************************
365 * Frees an allocated memory block from the dll's private heap.
368 * lpMem [I] pointer to memory block which will be freed
376 COMCTL32_Free (LPVOID lpMem)
378 TRACE("(%p)\n", lpMem);
380 return HeapFree (COMCTL32_hHeap, 0, lpMem);
384 /**************************************************************************
385 * GetSize [COMCTL32.74]
387 * Retrieves the size of the specified memory block from the dll's
391 * lpMem [I] pointer to an allocated memory block
394 * Success: size of the specified memory block
399 COMCTL32_GetSize (LPVOID lpMem)
401 TRACE("(%p)\n", lpMem);
403 return HeapSize (COMCTL32_hHeap, 0, lpMem);
407 /**************************************************************************
408 * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
414 typedef struct tagMRUINFO
422 } MRUINFO, *LPMRUINFO;
425 typedef struct tagMRU
427 DWORD dwParam1; /* some kind of flag */
436 CreateMRUListLazyA (LPMRUINFO lpmi, DWORD dwParam2,
437 DWORD dwParam3, DWORD dwParam4);
440 /**************************************************************************
441 * CreateMRUListA [COMCTL32.151]
450 CreateMRUListA (LPMRUINFO lpmi)
452 return CreateMRUListLazyA (lpmi, 0, 0, 0);
457 FreeMRUListA (HMRU hmru)
459 FIXME("(%p) empty stub!\n", hmru);
462 if (!(hmru->dwParam1 & 1001)) {
463 RegSetValueExA (hmru->hKeyMRU, "MRUList", 0, REG_SZ,
465 lstrlenA (hmru->lpszMRUString));
469 RegClosKey (hmru->hkeyMRU
470 COMCTL32_Free32 (hmru->lpszMRUString);
473 return COMCTL32_Free (hmru);
479 AddMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
482 FIXME("(%lx %lx %lx) empty stub!\n",
483 dwParam1, dwParam2, dwParam3);
490 FindMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
493 FIXME("(%lx %lx %lx %lx) empty stub!\n",
494 dwParam1, dwParam2, dwParam3, dwParam4);
501 CreateMRUListLazyA (LPMRUINFO lpmi, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
510 * DWORD dwDisposition; */
512 /* internal variables */
515 FIXME("(%p) empty stub!\n", lpmi);
518 FIXME("(%lx %lx %lx %lx \"%s\" %lx)\n",
519 lpmi->dwParam1, lpmi->dwParam2, lpmi->dwParam3,
520 (DWORD)lpmi->hkeyMain, lpmi->lpszSubKey, lpmi->dwParam6);
523 /* dummy pointer creation */
524 ptr = COMCTL32_Alloc (32);
526 FIXME("-- ret = %p\n", ptr);
534 /**************************************************************************
535 * Str_GetPtrA [COMCTL32.233]
546 Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
550 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
552 if (!lpDest && lpSrc)
553 return lstrlenA (lpSrc);
563 len = lstrlenA (lpSrc);
567 RtlMoveMemory (lpDest, lpSrc, len);
574 /**************************************************************************
575 * Str_SetPtrA [COMCTL32.234]
585 Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
587 TRACE("(%p %p)\n", lppDest, lpSrc);
590 LPSTR ptr = COMCTL32_ReAlloc (*lppDest, lstrlenA (lpSrc) + 1);
593 lstrcpyA (ptr, lpSrc);
598 COMCTL32_Free (*lppDest);
607 /**************************************************************************
608 * Str_GetPtrW [COMCTL32.235]
619 Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
623 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
625 if (!lpDest && lpSrc)
626 return lstrlenW (lpSrc);
636 len = lstrlenW (lpSrc);
640 RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
647 /**************************************************************************
648 * Str_SetPtrW [COMCTL32.236]
658 Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
660 TRACE("(%p %p)\n", lppDest, lpSrc);
663 INT len = lstrlenW (lpSrc) + 1;
664 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
667 lstrcpyW (ptr, lpSrc);
672 COMCTL32_Free (*lppDest);
681 /**************************************************************************
682 * The DSA-API is a set of functions to create and manipulate arrays of
683 * fix sized memory blocks. These arrays can store any kind of data
684 * (strings, icons...).
687 /**************************************************************************
688 * DSA_Create [COMCTL32.320] Creates a dynamic storage array
691 * nSize [I] size of the array elements
692 * nGrow [I] number of elements by which the array grows when it is filled
695 * Success: pointer to a array control structure. use this like a handle.
700 DSA_Create (INT nSize, INT nGrow)
704 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
706 hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
709 hdsa->nItemCount = 0;
712 hdsa->nItemSize = nSize;
713 hdsa->nGrow = MAX(1, nGrow);
720 /**************************************************************************
721 * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
724 * hdsa [I] pointer to the array control structure
732 DSA_Destroy (const HDSA hdsa)
734 TRACE("(%p)\n", hdsa);
739 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
742 return COMCTL32_Free (hdsa);
746 /**************************************************************************
747 * DSA_GetItem [COMCTL32.322]
750 * hdsa [I] pointer to the array control structure
751 * nIndex [I] number of the Item to get
752 * pDest [O] destination buffer. Has to be >= dwElementSize.
760 DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
764 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
768 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
771 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
772 memmove (pDest, pSrc, hdsa->nItemSize);
778 /**************************************************************************
779 * DSA_GetItemPtr [COMCTL32.323]
781 * Retrieves a pointer to the specified item.
784 * hdsa [I] pointer to the array control structure
785 * nIndex [I] index of the desired item
788 * Success: pointer to an item
793 DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
797 TRACE("(%p %d)\n", hdsa, nIndex);
801 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
804 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
806 TRACE("-- ret=%p\n", pSrc);
812 /**************************************************************************
813 * DSA_SetItem [COMCTL32.325]
815 * Sets the contents of an item in the array.
818 * hdsa [I] pointer to the array control structure
819 * nIndex [I] index for the item
820 * pSrc [I] pointer to the new item data
828 DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
830 INT nSize, nNewItems;
831 LPVOID pDest, lpTemp;
833 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
835 if ((!hdsa) || nIndex < 0)
838 if (hdsa->nItemCount <= nIndex) {
839 /* within the old array */
840 if (hdsa->nMaxCount > nIndex) {
841 /* within the allocated space, set a new boundary */
842 hdsa->nItemCount = nIndex + 1;
845 /* resize the block of memory */
847 hdsa->nGrow * ((INT)((nIndex - 1) / hdsa->nGrow) + 1);
848 nSize = hdsa->nItemSize * nNewItems;
850 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
854 hdsa->nMaxCount = nNewItems;
855 hdsa->nItemCount = nIndex + 1;
856 hdsa->pData = lpTemp;
860 /* put the new entry in */
861 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
862 TRACE("-- move dest=%p src=%p size=%d\n",
863 pDest, pSrc, hdsa->nItemSize);
864 memmove (pDest, pSrc, hdsa->nItemSize);
870 /**************************************************************************
871 * DSA_InsertItem [COMCTL32.325]
874 * hdsa [I] pointer to the array control structure
875 * nIndex [I] index for the new item
876 * pSrc [I] pointer to the element
879 * Success: position of the new item
884 DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
886 INT nNewItems, nSize, i;
887 LPVOID lpTemp, lpDest;
890 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
892 if ((!hdsa) || nIndex < 0)
895 for (i = 0; i < hdsa->nItemSize; i += 4) {
896 p = *(DWORD**)((char *) pSrc + i);
897 if (IsBadStringPtrA ((char*)p, 256))
898 TRACE("-- %d=%p\n", i, (DWORD*)p);
900 TRACE("-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
903 /* when nIndex > nItemCount then append */
904 if (nIndex >= hdsa->nItemCount)
905 nIndex = hdsa->nItemCount;
907 /* do we need to resize ? */
908 if (hdsa->nItemCount >= hdsa->nMaxCount) {
909 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
910 nSize = hdsa->nItemSize * nNewItems;
912 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
916 hdsa->nMaxCount = nNewItems;
917 hdsa->pData = lpTemp;
920 /* do we need to move elements ? */
921 if (nIndex < hdsa->nItemCount) {
922 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
923 lpDest = (char *) lpTemp + hdsa->nItemSize;
924 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
925 TRACE("-- move dest=%p src=%p size=%d\n",
926 lpDest, lpTemp, nSize);
927 memmove (lpDest, lpTemp, nSize);
930 /* ok, we can put the new Item in */
932 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
933 TRACE("-- move dest=%p src=%p size=%d\n",
934 lpDest, pSrc, hdsa->nItemSize);
935 memmove (lpDest, pSrc, hdsa->nItemSize);
937 return hdsa->nItemCount;
941 /**************************************************************************
942 * DSA_DeleteItem [COMCTL32.326]
945 * hdsa [I] pointer to the array control structure
946 * nIndex [I] index for the element to delete
949 * Success: number of the deleted element
954 DSA_DeleteItem (const HDSA hdsa, INT nIndex)
959 TRACE("(%p %d)\n", hdsa, nIndex);
963 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
966 /* do we need to move ? */
967 if (nIndex < hdsa->nItemCount - 1) {
968 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
969 lpSrc = (char *) lpDest + hdsa->nItemSize;
970 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
971 TRACE("-- move dest=%p src=%p size=%d\n",
972 lpDest, lpSrc, nSize);
973 memmove (lpDest, lpSrc, nSize);
979 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
980 nSize = hdsa->nItemSize * hdsa->nItemCount;
982 lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
986 hdsa->nMaxCount = hdsa->nItemCount;
987 hdsa->pData = lpDest;
994 /**************************************************************************
995 * DSA_DeleteAllItems [COMCTL32.326]
997 * Removes all items and reinitializes the array.
1000 * hdsa [I] pointer to the array control structure
1008 DSA_DeleteAllItems (const HDSA hdsa)
1010 TRACE("(%p)\n", hdsa);
1014 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1017 hdsa->nItemCount = 0;
1019 hdsa->nMaxCount = 0;
1025 /**************************************************************************
1026 * The DPA-API is a set of functions to create and manipulate arrays of
1030 /**************************************************************************
1031 * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1034 * nGrow [I] number of items by which the array grows when it is filled
1037 * Success: handle (pointer) to the pointer array.
1042 DPA_Create (INT nGrow)
1046 TRACE("(%d)\n", nGrow);
1048 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1050 hdpa->nGrow = MAX(8, nGrow);
1051 hdpa->hHeap = COMCTL32_hHeap;
1052 hdpa->nMaxCount = hdpa->nGrow * 2;
1054 (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1057 TRACE("-- %p\n", hdpa);
1063 /**************************************************************************
1064 * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1067 * hdpa [I] handle (pointer) to the pointer array
1075 DPA_Destroy (const HDPA hdpa)
1077 TRACE("(%p)\n", hdpa);
1082 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1085 return HeapFree (hdpa->hHeap, 0, hdpa);
1089 /**************************************************************************
1090 * DPA_Grow [COMCTL32.330]
1092 * Sets the growth amount.
1095 * hdpa [I] handle (pointer) to the existing (source) pointer array
1096 * nGrow [I] number of items, the array grows, when it's too small
1104 DPA_Grow (const HDPA hdpa, INT nGrow)
1106 TRACE("(%p %d)\n", hdpa, nGrow);
1111 hdpa->nGrow = MAX(8, nGrow);
1117 /**************************************************************************
1118 * DPA_Clone [COMCTL32.331]
1120 * Copies a pointer array to an other one or creates a copy
1123 * hdpa [I] handle (pointer) to the existing (source) pointer array
1124 * hdpaNew [O] handle (pointer) to the destination pointer array
1127 * Success: pointer to the destination pointer array.
1131 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1132 * array will be created and it's handle (pointer) is returned.
1133 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1134 * this implementation just returns NULL.
1138 DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1140 INT nNewItems, nSize;
1146 TRACE("(%p %p)\n", hdpa, hdpaNew);
1149 /* create a new DPA */
1150 hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1152 hdpaTemp->hHeap = hdpa->hHeap;
1153 hdpaTemp->nGrow = hdpa->nGrow;
1158 if (hdpaTemp->ptrs) {
1159 /* remove old pointer array */
1160 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1161 hdpaTemp->ptrs = NULL;
1162 hdpaTemp->nItemCount = 0;
1163 hdpaTemp->nMaxCount = 0;
1166 /* create a new pointer array */
1167 nNewItems = hdpaTemp->nGrow *
1168 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1169 nSize = nNewItems * sizeof(LPVOID);
1171 (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1172 hdpaTemp->nMaxCount = nNewItems;
1174 /* clone the pointer array */
1175 hdpaTemp->nItemCount = hdpa->nItemCount;
1176 memmove (hdpaTemp->ptrs, hdpa->ptrs,
1177 hdpaTemp->nItemCount * sizeof(LPVOID));
1183 /**************************************************************************
1184 * DPA_GetPtr [COMCTL32.332]
1186 * Retrieves a pointer from a dynamic pointer array
1189 * hdpa [I] handle (pointer) to the pointer array
1190 * nIndex [I] array index of the desired pointer
1198 DPA_GetPtr (const HDPA hdpa, INT i)
1200 TRACE("(%p %d)\n", hdpa, i);
1206 if ((i < 0) || (i >= hdpa->nItemCount))
1209 TRACE("-- %p\n", hdpa->ptrs[i]);
1211 return hdpa->ptrs[i];
1215 /**************************************************************************
1216 * DPA_GetPtrIndex [COMCTL32.333]
1218 * Retrieves the index of the specified pointer
1221 * hdpa [I] handle (pointer) to the pointer array
1225 * Success: index of the specified pointer
1230 DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1237 for (i = 0; i < hdpa->nItemCount; i++) {
1238 if (hdpa->ptrs[i] == p)
1246 /**************************************************************************
1247 * DPA_InsertPtr [COMCTL32.334]
1249 * Inserts a pointer into a dynamic pointer array
1252 * hdpa [I] handle (pointer) to the array
1254 * p [I] pointer to insert
1257 * Success: index of the inserted pointer
1262 DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1264 INT nNewItems, nSize, nIndex = 0;
1265 LPVOID *lpTemp, *lpDest;
1267 TRACE("(%p %d %p)\n", hdpa, i, p);
1269 if ((!hdpa) || (i < 0))
1274 (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1275 2 * hdpa->nGrow * sizeof(LPVOID));
1278 hdpa->nMaxCount = hdpa->nGrow * 2;
1282 if (hdpa->nItemCount >= hdpa->nMaxCount) {
1283 TRACE("-- resizing\n");
1284 nNewItems = hdpa->nMaxCount + hdpa->nGrow;
1285 nSize = nNewItems * sizeof(LPVOID);
1287 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1291 hdpa->nMaxCount = nNewItems;
1292 hdpa->ptrs = lpTemp;
1295 if (i >= hdpa->nItemCount) {
1296 nIndex = hdpa->nItemCount;
1297 TRACE("-- appending at %d\n", nIndex);
1300 TRACE("-- inserting at %d\n", i);
1301 lpTemp = hdpa->ptrs + i;
1302 lpDest = lpTemp + 1;
1303 nSize = (hdpa->nItemCount - i) * sizeof(LPVOID);
1304 TRACE("-- move dest=%p src=%p size=%x\n",
1305 lpDest, lpTemp, nSize);
1306 memmove (lpDest, lpTemp, nSize);
1313 hdpa->ptrs[nIndex] = p;
1319 /**************************************************************************
1320 * DPA_SetPtr [COMCTL32.335]
1322 * Sets a pointer in the pointer array
1325 * hdpa [I] handle (pointer) to the pointer array
1326 * i [I] index of the pointer that will be set
1327 * p [I] pointer to be set
1335 DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1339 TRACE("(%p %d %p)\n", hdpa, i, p);
1341 if ((!hdpa) || i < 0)
1344 if (hdpa->nItemCount <= i) {
1345 /* within the old array */
1346 if (hdpa->nMaxCount > i) {
1347 /* within the allocated space, set a new boundary */
1348 hdpa->nItemCount = i;
1351 /* resize the block of memory */
1353 hdpa->nGrow * ((INT)((i - 1) / hdpa->nGrow) + 1);
1354 INT nSize = nNewItems * sizeof(LPVOID);
1356 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1361 hdpa->nItemCount = nNewItems;
1362 hdpa->ptrs = lpTemp;
1366 /* put the new entry in */
1373 /**************************************************************************
1374 * DPA_DeletePtr [COMCTL32.336]
1376 * Removes a pointer from the pointer array.
1379 * hdpa [I] handle (pointer) to the pointer array
1380 * i [I] index of the pointer that will be deleted
1383 * Success: deleted pointer
1388 DPA_DeletePtr (const HDPA hdpa, INT i)
1390 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1393 TRACE("(%p %d)\n", hdpa, i);
1395 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1398 lpTemp = hdpa->ptrs[i];
1400 /* do we need to move ?*/
1401 if (i < hdpa->nItemCount - 1) {
1402 lpDest = hdpa->ptrs + i;
1404 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1405 TRACE("-- move dest=%p src=%p size=%x\n",
1406 lpDest, lpSrc, nSize);
1407 memmove (lpDest, lpSrc, nSize);
1410 hdpa->nItemCount --;
1413 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
1414 INT nNewItems = MIN(hdpa->nGrow * 2, hdpa->nItemCount);
1415 nSize = nNewItems * sizeof(LPVOID);
1416 lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1421 hdpa->nMaxCount = nNewItems;
1422 hdpa->ptrs = (LPVOID*)lpDest;
1429 /**************************************************************************
1430 * DPA_DeleteAllPtrs [COMCTL32.337]
1432 * Removes all pointers and reinitializes the array.
1435 * hdpa [I] handle (pointer) to the pointer array
1443 DPA_DeleteAllPtrs (const HDPA hdpa)
1445 TRACE("(%p)\n", hdpa);
1450 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1453 hdpa->nItemCount = 0;
1454 hdpa->nMaxCount = hdpa->nGrow * 2;
1455 hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1456 hdpa->nMaxCount * sizeof(LPVOID));
1462 /**************************************************************************
1463 * DPA_QuickSort [Internal]
1465 * Ordinary quicksort (used by DPA_Sort).
1468 * lpPtrs [I] pointer to the pointer array
1469 * l [I] index of the "left border" of the partition
1470 * r [I] index of the "right border" of the partition
1471 * pfnCompare [I] pointer to the compare function
1472 * lParam [I] user defined value (3rd parameter in compare function)
1479 DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
1480 PFNDPACOMPARE pfnCompare, LPARAM lParam)
1485 TRACE("l=%i r=%i\n", l, r);
1489 v = lpPtrs[(int)(l+r)/2];
1491 while ((pfnCompare)(lpPtrs[i], v, lParam) > 0) i++;
1492 while ((pfnCompare)(lpPtrs[j], v, lParam) < 0) j--;
1496 lpPtrs[i++] = lpPtrs[j];
1500 if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
1501 if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
1505 /**************************************************************************
1506 * DPA_Sort [COMCTL32.338]
1508 * Sorts a pointer array using a user defined compare function
1511 * hdpa [I] handle (pointer) to the pointer array
1512 * pfnCompare [I] pointer to the compare function
1513 * lParam [I] user defined value (3rd parameter of compare function)
1521 DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
1523 if (!hdpa || !pfnCompare)
1526 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
1528 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
1529 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
1530 pfnCompare, lParam);
1536 /**************************************************************************
1537 * DPA_Search [COMCTL32.339]
1539 * Searches a pointer array for a specified pointer
1542 * hdpa [I] handle (pointer) to the pointer array
1543 * pFind [I] pointer to search for
1544 * nStart [I] start index
1545 * pfnCompare [I] pointer to the compare function
1546 * lParam [I] user defined value (3rd parameter of compare function)
1547 * uOptions [I] search options
1550 * Success: index of the pointer in the array.
1554 * Binary search taken from R.Sedgewick "Algorithms in C"!
1555 * Function is NOT tested!
1556 * If something goes wrong, blame HIM not ME! (Eric Kohl)
1560 DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
1561 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
1563 if (!hdpa || !pfnCompare || !pFind)
1566 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
1567 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
1569 if (uOptions & DPAS_SORTED) {
1570 /* array is sorted --> use binary search */
1574 TRACE("binary search\n");
1576 l = (nStart == -1) ? 0 : nStart;
1577 r = hdpa->nItemCount - 1;
1581 n = (pfnCompare)(pFind, lpPtr[x], lParam);
1587 TRACE("-- ret=%d\n", n);
1592 if (uOptions & DPAS_INSERTBEFORE) {
1593 TRACE("-- ret=%d\n", r);
1597 if (uOptions & DPAS_INSERTAFTER) {
1598 TRACE("-- ret=%d\n", l);
1603 /* array is not sorted --> use linear search */
1607 TRACE("linear search\n");
1609 nIndex = (nStart == -1)? 0 : nStart;
1611 for (; nIndex < hdpa->nItemCount; nIndex++) {
1612 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
1613 TRACE("-- ret=%d\n", nIndex);
1619 TRACE("-- not found: ret=-1\n");
1624 /**************************************************************************
1625 * DPA_CreateEx [COMCTL32.340]
1627 * Creates a dynamic pointer array using the specified size and heap.
1630 * nGrow [I] number of items by which the array grows when it is filled
1631 * hHeap [I] handle to the heap where the array is stored
1634 * Success: handle (pointer) to the pointer array.
1639 DPA_CreateEx (INT nGrow, HANDLE hHeap)
1643 TRACE("(%d 0x%x)\n", nGrow, hHeap);
1646 hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
1648 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1651 hdpa->nGrow = MIN(8, nGrow);
1652 hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
1653 hdpa->nMaxCount = hdpa->nGrow * 2;
1655 (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
1656 hdpa->nMaxCount * sizeof(LPVOID));
1659 TRACE("-- %p\n", hdpa);
1665 /**************************************************************************
1666 * Notification functions
1669 typedef struct tagNOTIFYDATA
1677 } NOTIFYDATA, *LPNOTIFYDATA;
1680 /**************************************************************************
1681 * DoNotify [Internal]
1685 DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
1688 LPNMHDR lpNmh = NULL;
1691 TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1692 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
1693 lpNotify->dwParam5);
1695 if (!lpNotify->hwndTo)
1698 if (lpNotify->hwndFrom == -1) {
1700 idFrom = lpHdr->idFrom;
1703 if (lpNotify->hwndFrom) {
1704 HWND hwndParent = GetParent (lpNotify->hwndFrom);
1706 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
1708 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
1712 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1714 lpNmh->hwndFrom = lpNotify->hwndFrom;
1715 lpNmh->idFrom = idFrom;
1716 lpNmh->code = uCode;
1719 return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
1723 /**************************************************************************
1724 * SendNotify [COMCTL32.341]
1733 * Success: return value from notification
1738 COMCTL32_SendNotify (HWND hwndFrom, HWND hwndTo,
1739 UINT uCode, LPNMHDR lpHdr)
1743 TRACE("(0x%04x 0x%04x %d %p)\n",
1744 hwndFrom, hwndTo, uCode, lpHdr);
1746 notify.hwndFrom = hwndFrom;
1747 notify.hwndTo = hwndTo;
1748 notify.dwParam5 = 0;
1749 notify.dwParam6 = 0;
1751 return DoNotify (¬ify, uCode, lpHdr);
1755 /**************************************************************************
1756 * SendNotifyEx [COMCTL32.342]
1766 * Success: return value from notification
1771 COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
1772 LPNMHDR lpHdr, DWORD dwParam5)
1777 TRACE("(0x%04x 0x%04x %d %p 0x%08lx)\n",
1778 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
1780 hwndNotify = hwndTo;
1782 if (IsWindow (hwndFrom)) {
1783 hwndNotify = GetParent (hwndFrom);
1789 notify.hwndFrom = hwndFrom;
1790 notify.hwndTo = hwndNotify;
1791 notify.dwParam5 = dwParam5;
1792 notify.dwParam6 = 0;
1794 return DoNotify (¬ify, uCode, lpHdr);
1798 /**************************************************************************
1799 * StrChrA [COMCTL32.350]
1804 COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
1806 return strchr (lpString, cChar);
1810 /**************************************************************************
1811 * StrStrIA [COMCTL32.355]
1815 COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
1821 return ((LPSTR)lpStr1);
1823 while (lpStr1[len1] != 0) ++len1;
1825 while (lpStr2[len2] != 0) ++len2;
1827 return ((LPSTR)(lpStr1 + len1));
1828 first = tolower (*lpStr2);
1829 while (len1 >= len2) {
1830 if (tolower(*lpStr1) == first) {
1831 for (i = 1; i < len2; ++i)
1832 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
1835 return ((LPSTR)lpStr1);
1843 /**************************************************************************
1844 * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
1848 COMCTL32_StrToIntA (LPSTR lpString)
1850 return atoi(lpString);
1854 /**************************************************************************
1855 * DPA_EnumCallback [COMCTL32.385]
1857 * Enumerates all items in a dynamic pointer array.
1860 * hdpa [I] handle to the dynamic pointer array
1869 DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1873 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1877 if (hdpa->nItemCount <= 0)
1880 for (i = 0; i < hdpa->nItemCount; i++) {
1881 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
1889 /**************************************************************************
1890 * DPA_DestroyCallback [COMCTL32.386]
1892 * Enumerates all items in a dynamic pointer array and destroys it.
1895 * hdpa [I] handle to the dynamic pointer array
1905 DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
1907 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
1909 DPA_EnumCallback (hdpa, enumProc, lParam);
1911 return DPA_Destroy (hdpa);
1915 /**************************************************************************
1916 * DSA_EnumCallback [COMCTL32.387]
1918 * Enumerates all items in a dynamic storage array.
1921 * hdsa [I] handle to the dynamic storage array
1930 DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1934 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1938 if (hdsa->nItemCount <= 0)
1941 for (i = 0; i < hdsa->nItemCount; i++) {
1942 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
1943 if ((enumProc)(lpItem, lParam) == 0)
1951 /**************************************************************************
1952 * DSA_DestroyCallback [COMCTL32.388]
1954 * Enumerates all items in a dynamic storage array and destroys it.
1957 * hdsa [I] handle to the dynamic storage array
1967 DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
1969 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
1971 DSA_EnumCallback (hdsa, enumProc, lParam);
1973 return DSA_Destroy (hdsa);
1976 /**************************************************************************
1977 * StrCSpnA [COMCTL32.356]
1980 INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
1981 return strcspn(lpStr, lpSet);
1984 /**************************************************************************
1985 * StrChrW [COMCTL32.358]
1988 LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
1989 return CRTDLL_wcschr(lpStart, wMatch);
1992 /**************************************************************************
1993 * StrCmpNA [COMCTL32.352]
1996 INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
1997 return lstrncmpA(lpStr1, lpStr2, nChar);
2000 /**************************************************************************
2001 * StrCmpNW [COMCTL32.360]
2004 INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2005 return lstrncmpW(lpStr1, lpStr2, nChar);
2008 /**************************************************************************
2009 * StrRChrA [COMCTL32.351]
2012 LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch) {
2013 return lstrrchr(lpStart, lpEnd, wMatch);
2016 /**************************************************************************
2017 * StrRChrW [COMCTL32.359]
2020 LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch) {
2021 return lstrrchrw(lpStart, lpEnd, wMatch);
2024 /**************************************************************************
2025 * StrStrA [COMCTL32.354]
2028 LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2029 return strstr(lpFirst, lpSrch);
2032 /**************************************************************************
2033 * StrStrW [COMCTL32.362]
2036 LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2037 return strstrw(lpFirst, lpSrch);
2040 /**************************************************************************
2041 * StrSpnW [COMCTL32.364]
2044 INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2045 LPWSTR lpLoop = lpStr;
2048 if ((lpStr == 0) || (lpSet == 0)) return 0;
2050 /* while(*lpLoop) { if lpLoop++; } */
2052 for(; (*lpLoop != 0); lpLoop++)
2053 if( CRTDLL_wcschr(lpSet, *(WORD*)lpLoop))
2054 return (INT)(lpLoop-lpStr);
2056 return (INT)(lpLoop-lpStr);
2059 /**************************************************************************
2060 * comctl32_410 [COMCTL32.410]
2062 * FIXME: What's this supposed to do?
2063 * Parameter 1 is an HWND, you're on your own for the rest.
2066 BOOL WINAPI comctl32_410( HWND hw, DWORD b, DWORD c, DWORD d) {
2068 FIXME_(commctrl)("(%x, %lx, %lx, %lx): stub!\n", hw, b, c, d);
2073 /*************************************************************************
2074 * InitMUILanguage [COMCTL32.70]
2076 * FIXME: What's this supposed to do? Apparently some i18n thing.
2080 BOOL WINAPI InitMUILanguage( DWORD a ) {
2082 FIXME_(commctrl)("(%lx): stub!\n", a);