diff --git a/dlls/comctl32/Makefile.in b/dlls/comctl32/Makefile.in index 2f0abc169a3..d06412c11ee 100644 --- a/dlls/comctl32/Makefile.in +++ b/dlls/comctl32/Makefile.in @@ -15,7 +15,9 @@ C_SRCS = \ comctl32undoc.c \ commctrl.c \ datetime.c \ + dpa.c \ draglist.c \ + dsa.c \ flatsb.c \ header.c \ hotkey.c \ diff --git a/dlls/comctl32/comctl32undoc.c b/dlls/comctl32/comctl32undoc.c index 038cf46696d..65e018e1c53 100644 --- a/dlls/comctl32/comctl32undoc.c +++ b/dlls/comctl32/comctl32undoc.c @@ -55,313 +55,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(commctrl); -struct _DSA -{ - INT nItemCount; - LPVOID pData; - INT nMaxCount; - INT nItemSize; - INT nGrow; -}; - -struct _DPA -{ - INT nItemCount; - LPVOID *ptrs; - HANDLE hHeap; - INT nGrow; - INT nMaxCount; -}; - -typedef struct _STREAMDATA -{ - DWORD dwSize; - DWORD dwData2; - DWORD dwItems; -} STREAMDATA, *PSTREAMDATA; - -typedef struct _LOADDATA -{ - INT nCount; - PVOID ptr; -} LOADDATA, *LPLOADDATA; - -typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM); - static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 }; -/************************************************************************** - * DPA_LoadStream [COMCTL32.9] - * - * Loads a dynamic pointer array from a stream - * - * PARAMS - * phDpa [O] pointer to a handle to a dynamic pointer array - * loadProc [I] pointer to a callback function - * pStream [I] pointer to a stream - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, - IStream *pStream, LPARAM lParam) -{ - HRESULT errCode; - LARGE_INTEGER position; - ULARGE_INTEGER newPosition; - STREAMDATA streamData; - LOADDATA loadData; - ULONG ulRead; - HDPA hDpa; - PVOID *ptr; - - FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n", - phDpa, loadProc, pStream, lParam); - - if (!phDpa || !loadProc || !pStream) - return E_INVALIDARG; - - *phDpa = (HDPA)NULL; - - position.QuadPart = 0; - - /* - * Zero out our streamData - */ - memset(&streamData,0,sizeof(STREAMDATA)); - - errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition); - if (errCode != S_OK) - return errCode; - - errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead); - if (errCode != S_OK) - return errCode; - - FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n", - streamData.dwSize, streamData.dwData2, streamData.dwItems); - - if ( ulRead < sizeof(STREAMDATA) || - lParam < sizeof(STREAMDATA) || - streamData.dwSize < sizeof(STREAMDATA) || - streamData.dwData2 < 1) { - errCode = E_FAIL; - } - - if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */ - return E_OUTOFMEMORY; - - /* create the dpa */ - hDpa = DPA_Create (streamData.dwItems); - if (!hDpa) - return E_OUTOFMEMORY; - - if (!DPA_Grow (hDpa, streamData.dwItems)) - return E_OUTOFMEMORY; - - /* load data from the stream into the dpa */ - ptr = hDpa->ptrs; - for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) { - errCode = (loadProc)(&loadData, pStream, lParam); - if (errCode != S_OK) { - errCode = S_FALSE; - break; - } - - *ptr = loadData.ptr; - ptr++; - } - - /* set the number of items */ - hDpa->nItemCount = loadData.nCount; - - /* store the handle to the dpa */ - *phDpa = hDpa; - FIXME ("new hDpa=%p, errorcode=%lx\n", hDpa, errCode); - - return errCode; -} - - -/************************************************************************** - * DPA_SaveStream [COMCTL32.10] - * - * Saves a dynamic pointer array to a stream - * - * PARAMS - * hDpa [I] handle to a dynamic pointer array - * loadProc [I] pointer to a callback function - * pStream [I] pointer to a stream - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, - IStream *pStream, LPARAM lParam) -{ - - FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n", - hDpa, loadProc, pStream, lParam); - - return E_FAIL; -} - - -/************************************************************************** - * DPA_Merge [COMCTL32.11] - * - * Merge two dynamic pointers arrays. - * - * PARAMS - * hdpa1 [I] handle to a dynamic pointer array - * hdpa2 [I] handle to a dynamic pointer array - * dwFlags [I] flags - * pfnCompare [I] pointer to sort function - * pfnMerge [I] pointer to merge function - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags, - PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, - LPARAM lParam) -{ - INT nCount; - LPVOID *pWork1, *pWork2; - INT nResult, i; - INT nIndex; - - TRACE("%p %p %08lx %p %p %08lx)\n", - hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam); - - if (IsBadWritePtr (hdpa1, sizeof(*hdpa1))) - return FALSE; - - if (IsBadWritePtr (hdpa2, sizeof(*hdpa2))) - return FALSE; - - if (IsBadCodePtr ((FARPROC)pfnCompare)) - return FALSE; - - if (IsBadCodePtr ((FARPROC)pfnMerge)) - return FALSE; - - if (!(dwFlags & DPAM_NOSORT)) { - TRACE("sorting dpa's!\n"); - if (hdpa1->nItemCount > 0) - DPA_Sort (hdpa1, pfnCompare, lParam); - TRACE ("dpa 1 sorted!\n"); - if (hdpa2->nItemCount > 0) - DPA_Sort (hdpa2, pfnCompare, lParam); - TRACE ("dpa 2 sorted!\n"); - } - - if (hdpa2->nItemCount < 1) - return TRUE; - - TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n", - hdpa1->nItemCount, hdpa2->nItemCount); - - - /* working but untrusted implementation */ - - pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]); - pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]); - - nIndex = hdpa1->nItemCount - 1; - nCount = hdpa2->nItemCount - 1; - - do - { - if (nIndex < 0) { - if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) { - /* Now insert the remaining new items into DPA 1 */ - TRACE("%d items to be inserted at start of DPA 1\n", - nCount+1); - for (i=nCount; i>=0; i--) { - PVOID ptr; - - ptr = (pfnMerge)(3, *pWork2, NULL, lParam); - if (!ptr) - return FALSE; - DPA_InsertPtr (hdpa1, 0, ptr); - pWork2--; - } - } - break; - } - nResult = (pfnCompare)(*pWork1, *pWork2, lParam); - TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n", - nResult, nIndex, nCount); - - if (nResult == 0) - { - PVOID ptr; - - ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam); - if (!ptr) - return FALSE; - - nCount--; - pWork2--; - *pWork1 = ptr; - nIndex--; - pWork1--; - } - else if (nResult > 0) - { - /* item in DPA 1 missing from DPA 2 */ - if (dwFlags & DPAM_DELETE) - { - /* Now delete the extra item in DPA1 */ - PVOID ptr; - - ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1); - - (pfnMerge)(2, ptr, NULL, lParam); - } - nIndex--; - pWork1--; - } - else - { - /* new item in DPA 2 */ - if (dwFlags & DPAM_INSERT) - { - /* Now insert the new item in DPA 1 */ - PVOID ptr; - - ptr = (pfnMerge)(3, *pWork2, NULL, lParam); - if (!ptr) - return FALSE; - DPA_InsertPtr (hdpa1, nIndex+1, ptr); - } - nCount--; - pWork2--; - } - - } - while (nCount >= 0); - - return TRUE; -} - - /************************************************************************** * Alloc [COMCTL32.71] * @@ -1415,912 +1110,6 @@ BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc) } -/************************************************************************** - * DSA_Create [COMCTL32.320] - * - * Creates a dynamic storage array - * - * PARAMS - * nSize [I] size of the array elements - * nGrow [I] number of elements by which the array grows when it is filled - * - * RETURNS - * Success: pointer to an array control structure. Use this like a handle. - * Failure: NULL - * - * NOTES - * The DSA_ functions can be used to create and manipulate arrays of - * fixed-size memory blocks. These arrays can store any kind of data - * (e.g. strings and icons). - */ -HDSA WINAPI DSA_Create (INT nSize, INT nGrow) -{ - HDSA hdsa; - - TRACE("(size=%d grow=%d)\n", nSize, nGrow); - - hdsa = Alloc (sizeof(*hdsa)); - if (hdsa) - { - hdsa->nItemCount = 0; - hdsa->pData = NULL; - hdsa->nMaxCount = 0; - hdsa->nItemSize = nSize; - hdsa->nGrow = max(1, nGrow); - } - - return hdsa; -} - - -/************************************************************************** - * DSA_Destroy [COMCTL32.321] - * - * Destroys a dynamic storage array - * - * PARAMS - * hdsa [I] pointer to the array control structure - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_Destroy (const HDSA hdsa) -{ - TRACE("(%p)\n", hdsa); - - if (!hdsa) - return FALSE; - - if (hdsa->pData && (!Free (hdsa->pData))) - return FALSE; - - return Free (hdsa); -} - - -/************************************************************************** - * DSA_GetItem [COMCTL32.322] - * - * Copies the specified item into a caller-supplied buffer. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] number of the Item to get - * pDest [O] destination buffer. Has to be >= dwElementSize. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest) -{ - LPVOID pSrc; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); - - if (!hdsa) - return FALSE; - if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) - return FALSE; - - pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - memmove (pDest, pSrc, hdsa->nItemSize); - - return TRUE; -} - - -/************************************************************************** - * DSA_GetItemPtr [COMCTL32.323] - * - * Retrieves a pointer to the specified item. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index of the desired item - * - * RETURNS - * Success: pointer to an item - * Failure: NULL - */ -LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex) -{ - LPVOID pSrc; - - TRACE("(%p %d)\n", hdsa, nIndex); - - if (!hdsa) - return NULL; - if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) - return NULL; - - pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - - TRACE("-- ret=%p\n", pSrc); - - return pSrc; -} - - -/************************************************************************** - * DSA_SetItem [COMCTL32.325] - * - * Sets the contents of an item in the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the item - * pSrc [I] pointer to the new item data - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) -{ - INT nSize, nNewItems; - LPVOID pDest, lpTemp; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); - - if ((!hdsa) || nIndex < 0) - return FALSE; - - if (hdsa->nItemCount <= nIndex) { - /* within the old array */ - if (hdsa->nMaxCount > nIndex) { - /* within the allocated space, set a new boundary */ - hdsa->nItemCount = nIndex + 1; - } - else { - /* resize the block of memory */ - nNewItems = - hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1); - nSize = hdsa->nItemSize * nNewItems; - - lpTemp = ReAlloc (hdsa->pData, nSize); - if (!lpTemp) - return FALSE; - - hdsa->nMaxCount = nNewItems; - hdsa->nItemCount = nIndex + 1; - hdsa->pData = lpTemp; - } - } - - /* put the new entry in */ - pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - TRACE("-- move dest=%p src=%p size=%d\n", - pDest, pSrc, hdsa->nItemSize); - memmove (pDest, pSrc, hdsa->nItemSize); - - return TRUE; -} - - -/************************************************************************** - * DSA_InsertItem [COMCTL32.324] - * - * Inserts an item into the array at the specified index. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the new item - * pSrc [I] pointer to the element - * - * RETURNS - * Success: position of the new item - * Failure: -1 - */ -INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) -{ - INT nNewItems, nSize; - LPVOID lpTemp, lpDest; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); - - if ((!hdsa) || nIndex < 0) - return -1; - - /* when nIndex >= nItemCount then append */ - if (nIndex >= hdsa->nItemCount) - nIndex = hdsa->nItemCount; - - /* do we need to resize ? */ - if (hdsa->nItemCount >= hdsa->nMaxCount) { - nNewItems = hdsa->nMaxCount + hdsa->nGrow; - nSize = hdsa->nItemSize * nNewItems; - - lpTemp = ReAlloc (hdsa->pData, nSize); - if (!lpTemp) - return -1; - - hdsa->nMaxCount = nNewItems; - hdsa->pData = lpTemp; - } - - /* do we need to move elements ? */ - if (nIndex < hdsa->nItemCount) { - lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - lpDest = (char *) lpTemp + hdsa->nItemSize; - nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, lpTemp, nSize); - memmove (lpDest, lpTemp, nSize); - } - - /* ok, we can put the new Item in */ - hdsa->nItemCount++; - lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, pSrc, hdsa->nItemSize); - memmove (lpDest, pSrc, hdsa->nItemSize); - - return nIndex; -} - - -/************************************************************************** - * DSA_DeleteItem [COMCTL32.326] - * - * Deletes the specified item from the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the element to delete - * - * RETURNS - * Success: number of the deleted element - * Failure: -1 - */ -INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex) -{ - LPVOID lpDest,lpSrc; - INT nSize; - - TRACE("(%p %d)\n", hdsa, nIndex); - - if (!hdsa) - return -1; - if (nIndex < 0 || nIndex >= hdsa->nItemCount) - return -1; - - /* do we need to move ? */ - if (nIndex < hdsa->nItemCount - 1) { - lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - lpSrc = (char *) lpDest + hdsa->nItemSize; - nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, lpSrc, nSize); - memmove (lpDest, lpSrc, nSize); - } - - hdsa->nItemCount--; - - /* free memory ? */ - if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { - nSize = hdsa->nItemSize * hdsa->nItemCount; - - lpDest = ReAlloc (hdsa->pData, nSize); - if (!lpDest) - return -1; - - hdsa->nMaxCount = hdsa->nItemCount; - hdsa->pData = lpDest; - } - - return nIndex; -} - - -/************************************************************************** - * DSA_DeleteAllItems [COMCTL32.327] - * - * Removes all items and reinitializes the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa) -{ - TRACE("(%p)\n", hdsa); - - if (!hdsa) - return FALSE; - if (hdsa->pData && (!Free (hdsa->pData))) - return FALSE; - - hdsa->nItemCount = 0; - hdsa->pData = NULL; - hdsa->nMaxCount = 0; - - return TRUE; -} - - -/************************************************************************** - * DPA_Destroy [COMCTL32.329] - * - * Destroys a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Destroy (const HDPA hdpa) -{ - TRACE("(%p)\n", hdpa); - - if (!hdpa) - return FALSE; - - if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) - return FALSE; - - return HeapFree (hdpa->hHeap, 0, hdpa); -} - - -/************************************************************************** - * DPA_Grow [COMCTL32.330] - * - * Sets the growth amount. - * - * PARAMS - * hdpa [I] handle (pointer) to the existing (source) pointer array - * nGrow [I] number of items by which the array grows when it's too small - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow) -{ - TRACE("(%p %d)\n", hdpa, nGrow); - - if (!hdpa) - return FALSE; - - hdpa->nGrow = max(8, nGrow); - - return TRUE; -} - - -/************************************************************************** - * DPA_Clone [COMCTL32.331] - * - * Copies a pointer array to an other one or creates a copy - * - * PARAMS - * hdpa [I] handle (pointer) to the existing (source) pointer array - * hdpaNew [O] handle (pointer) to the destination pointer array - * - * RETURNS - * Success: pointer to the destination pointer array. - * Failure: NULL - * - * NOTES - * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer - * array will be created and it's handle (pointer) is returned. - * - If 'hdpa' is a NULL-Pointer, the original implementation crashes, - * this implementation just returns NULL. - */ -HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew) -{ - INT nNewItems, nSize; - HDPA hdpaTemp; - - if (!hdpa) - return NULL; - - TRACE("(%p %p)\n", hdpa, hdpaNew); - - if (!hdpaNew) { - /* create a new DPA */ - hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - sizeof(*hdpaTemp)); - hdpaTemp->hHeap = hdpa->hHeap; - hdpaTemp->nGrow = hdpa->nGrow; - } - else - hdpaTemp = hdpaNew; - - if (hdpaTemp->ptrs) { - /* remove old pointer array */ - HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs); - hdpaTemp->ptrs = NULL; - hdpaTemp->nItemCount = 0; - hdpaTemp->nMaxCount = 0; - } - - /* create a new pointer array */ - nNewItems = hdpaTemp->nGrow * - ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1); - nSize = nNewItems * sizeof(LPVOID); - hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize); - hdpaTemp->nMaxCount = nNewItems; - - /* clone the pointer array */ - hdpaTemp->nItemCount = hdpa->nItemCount; - memmove (hdpaTemp->ptrs, hdpa->ptrs, - hdpaTemp->nItemCount * sizeof(LPVOID)); - - return hdpaTemp; -} - - -/************************************************************************** - * DPA_GetPtr [COMCTL32.332] - * - * Retrieves a pointer from a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * nIndex [I] array index of the desired pointer - * - * RETURNS - * Success: pointer - * Failure: NULL - */ -LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex) -{ - TRACE("(%p %d)\n", hdpa, nIndex); - - if (!hdpa) - return NULL; - if (!hdpa->ptrs) { - WARN("no pointer array.\n"); - return NULL; - } - if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) { - WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount); - return NULL; - } - - TRACE("-- %p\n", hdpa->ptrs[nIndex]); - - return hdpa->ptrs[nIndex]; -} - - -/************************************************************************** - * DPA_GetPtrIndex [COMCTL32.333] - * - * Retrieves the index of the specified pointer - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * p [I] pointer - * - * RETURNS - * Success: index of the specified pointer - * Failure: -1 - */ -INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p) -{ - INT i; - - if (!hdpa || !hdpa->ptrs) - return -1; - - for (i = 0; i < hdpa->nItemCount; i++) { - if (hdpa->ptrs[i] == p) - return i; - } - - return -1; -} - - -/************************************************************************** - * DPA_InsertPtr [COMCTL32.334] - * - * Inserts a pointer into a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the array - * i [I] array index - * p [I] pointer to insert - * - * RETURNS - * Success: index of the inserted pointer - * Failure: -1 - */ -INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p) -{ - TRACE("(%p %d %p)\n", hdpa, i, p); - - if (!hdpa || i < 0) return -1; - - if (i >= 0x7fff) - i = hdpa->nItemCount; - - if (i >= hdpa->nItemCount) - return DPA_SetPtr(hdpa, i, p) ? i : -1; - - /* create empty spot at the end */ - if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1; - memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID)); - hdpa->ptrs[i] = p; - return i; -} - -/************************************************************************** - * DPA_SetPtr [COMCTL32.335] - * - * Sets a pointer in the pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * i [I] index of the pointer that will be set - * p [I] pointer to be set - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p) -{ - LPVOID *lpTemp; - - TRACE("(%p %d %p)\n", hdpa, i, p); - - if (!hdpa || i < 0 || i > 0x7fff) - return FALSE; - - if (hdpa->nItemCount <= i) { - /* within the old array */ - if (hdpa->nMaxCount <= i) { - /* resize the block of memory */ - INT nNewItems = - hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1); - INT nSize = nNewItems * sizeof(LPVOID); - - if (hdpa->ptrs) - lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize); - else - lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize); - - if (!lpTemp) - return FALSE; - - hdpa->nMaxCount = nNewItems; - hdpa->ptrs = lpTemp; - } - hdpa->nItemCount = i+1; - } - - /* put the new entry in */ - hdpa->ptrs[i] = p; - - return TRUE; -} - - -/************************************************************************** - * DPA_DeletePtr [COMCTL32.336] - * - * Removes a pointer from the pointer array. - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * i [I] index of the pointer that will be deleted - * - * RETURNS - * Success: deleted pointer - * Failure: NULL - */ -LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i) -{ - LPVOID *lpDest, *lpSrc, lpTemp = NULL; - INT nSize; - - TRACE("(%p %d)\n", hdpa, i); - - if ((!hdpa) || i < 0 || i >= hdpa->nItemCount) - return NULL; - - lpTemp = hdpa->ptrs[i]; - - /* do we need to move ?*/ - if (i < hdpa->nItemCount - 1) { - lpDest = hdpa->ptrs + i; - lpSrc = lpDest + 1; - nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID); - TRACE("-- move dest=%p src=%p size=%x\n", - lpDest, lpSrc, nSize); - memmove (lpDest, lpSrc, nSize); - } - - hdpa->nItemCount --; - - /* free memory ?*/ - if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) { - INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount); - nSize = nNewItems * sizeof(LPVOID); - lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->ptrs, nSize); - if (!lpDest) - return NULL; - - hdpa->nMaxCount = nNewItems; - hdpa->ptrs = (LPVOID*)lpDest; - } - - return lpTemp; -} - - -/************************************************************************** - * DPA_DeleteAllPtrs [COMCTL32.337] - * - * Removes all pointers and reinitializes the array. - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa) -{ - TRACE("(%p)\n", hdpa); - - if (!hdpa) - return FALSE; - - if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) - return FALSE; - - hdpa->nItemCount = 0; - hdpa->nMaxCount = hdpa->nGrow * 2; - hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->nMaxCount * sizeof(LPVOID)); - - return TRUE; -} - - -/************************************************************************** - * DPA_QuickSort [Internal] - * - * Ordinary quicksort (used by DPA_Sort). - * - * PARAMS - * lpPtrs [I] pointer to the pointer array - * l [I] index of the "left border" of the partition - * r [I] index of the "right border" of the partition - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter in compare function) - * - * RETURNS - * NONE - */ -static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r, - PFNDPACOMPARE pfnCompare, LPARAM lParam) -{ - INT m; - LPVOID t; - - TRACE("l=%i r=%i\n", l, r); - - if (l==r) /* one element is always sorted */ - return; - if (r0) - { - t = lpPtrs[m+1]; - memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l])); - lpPtrs[l] = t; - - m++; - } - l++; - } -} - - -/************************************************************************** - * DPA_Sort [COMCTL32.338] - * - * Sorts a pointer array using a user defined compare function - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter of compare function) - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam) -{ - if (!hdpa || !pfnCompare) - return FALSE; - - TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam); - - if ((hdpa->nItemCount > 1) && (hdpa->ptrs)) - DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1, - pfnCompare, lParam); - - return TRUE; -} - - -/************************************************************************** - * DPA_Search [COMCTL32.339] - * - * Searches a pointer array for a specified pointer - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * pFind [I] pointer to search for - * nStart [I] start index - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter of compare function) - * uOptions [I] search options - * - * RETURNS - * Success: index of the pointer in the array. - * Failure: -1 - * - * NOTES - * Binary search taken from R.Sedgewick "Algorithms in C"! - * Function is NOT tested! - * If something goes wrong, blame HIM not ME! (Eric Kohl) - */ -INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart, - PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions) -{ - if (!hdpa || !pfnCompare || !pFind) - return -1; - - TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n", - hdpa, pFind, nStart, pfnCompare, lParam, uOptions); - - if (uOptions & DPAS_SORTED) { - /* array is sorted --> use binary search */ - INT l, r, x, n; - LPVOID *lpPtr; - - TRACE("binary search\n"); - - l = (nStart == -1) ? 0 : nStart; - r = hdpa->nItemCount - 1; - lpPtr = hdpa->ptrs; - while (r >= l) { - x = (l + r) / 2; - n = (pfnCompare)(pFind, lpPtr[x], lParam); - if (n < 0) - r = x - 1; - else - l = x + 1; - if (n == 0) { - TRACE("-- ret=%d\n", n); - return n; - } - } - - if (uOptions & DPAS_INSERTBEFORE) { - if (r == -1) r = 0; - TRACE("-- ret=%d\n", r); - return r; - } - - if (uOptions & DPAS_INSERTAFTER) { - TRACE("-- ret=%d\n", l); - return l; - } - } - else { - /* array is not sorted --> use linear search */ - LPVOID *lpPtr; - INT nIndex; - - TRACE("linear search\n"); - - nIndex = (nStart == -1)? 0 : nStart; - lpPtr = hdpa->ptrs; - for (; nIndex < hdpa->nItemCount; nIndex++) { - if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) { - TRACE("-- ret=%d\n", nIndex); - return nIndex; - } - } - } - - TRACE("-- not found: ret=-1\n"); - return -1; -} - - -/************************************************************************** - * DPA_CreateEx [COMCTL32.340] - * - * Creates a dynamic pointer array using the specified size and heap. - * - * PARAMS - * nGrow [I] number of items by which the array grows when it is filled - * hHeap [I] handle to the heap where the array is stored - * - * RETURNS - * Success: handle (pointer) to the pointer array. - * Failure: NULL - * - * NOTES - * The DPA_ functions can be used to create and manipulate arrays of - * pointers. - */ -HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap) -{ - HDPA hdpa; - - TRACE("(%d %p)\n", nGrow, hHeap); - - if (hHeap) - hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa)); - else - hdpa = Alloc (sizeof(*hdpa)); - - if (hdpa) { - hdpa->nGrow = max(8, nGrow); - hdpa->hHeap = hHeap ? hHeap : GetProcessHeap(); - hdpa->nMaxCount = hdpa->nGrow * 2; - hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->nMaxCount * sizeof(LPVOID)); - } - - TRACE("-- %p\n", hdpa); - - return hdpa; -} - - -/************************************************************************** - * DPA_Create [COMCTL32.328] - * - * Creates a dynamic pointer array. - * - * PARAMS - * nGrow [I] number of items by which the array grows when it is filled - * - * RETURNS - * Success: handle (pointer) to the pointer array. - * Failure: NULL - * - * NOTES - * The DPA_ functions can be used to create and manipulate arrays of - * pointers. - */ -HDPA WINAPI DPA_Create (INT nGrow) -{ - return DPA_CreateEx( nGrow, 0 ); -} - - /************************************************************************** * Notification functions */ @@ -2454,120 +1243,3 @@ LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode, return DoNotify (¬ify, uCode, lpHdr); } - - - - -/************************************************************************** - * DPA_EnumCallback [COMCTL32.385] - * - * Enumerates all items in a dynamic pointer array. - * - * PARAMS - * hdpa [I] handle to the dynamic pointer array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, - LPVOID lParam) -{ - INT i; - - TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); - - if (!hdpa) - return; - if (hdpa->nItemCount <= 0) - return; - - for (i = 0; i < hdpa->nItemCount; i++) { - if ((enumProc)(hdpa->ptrs[i], lParam) == 0) - return; - } - - return; -} - - -/************************************************************************** - * DPA_DestroyCallback [COMCTL32.386] - * - * Enumerates all items in a dynamic pointer array and destroys it. - * - * PARAMS - * hdpa [I] handle to the dynamic pointer array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, - LPVOID lParam) -{ - TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); - - DPA_EnumCallback (hdpa, enumProc, lParam); - DPA_Destroy (hdpa); -} - - -/************************************************************************** - * DSA_EnumCallback [COMCTL32.387] - * - * Enumerates all items in a dynamic storage array. - * - * PARAMS - * hdsa [I] handle to the dynamic storage array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, - LPVOID lParam) -{ - INT i; - - TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); - - if (!hdsa) - return; - if (hdsa->nItemCount <= 0) - return; - - for (i = 0; i < hdsa->nItemCount; i++) { - LPVOID lpItem = DSA_GetItemPtr (hdsa, i); - if ((enumProc)(lpItem, lParam) == 0) - return; - } - - return; -} - - -/************************************************************************** - * DSA_DestroyCallback [COMCTL32.388] - * - * Enumerates all items in a dynamic storage array and destroys it. - * - * PARAMS - * hdsa [I] handle to the dynamic storage array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, - LPVOID lParam) -{ - TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); - - DSA_EnumCallback (hdsa, enumProc, lParam); - DSA_Destroy (hdsa); -} diff --git a/dlls/comctl32/dpa.c b/dlls/comctl32/dpa.c new file mode 100644 index 00000000000..4ce92d29fa0 --- /dev/null +++ b/dlls/comctl32/dpa.c @@ -0,0 +1,978 @@ +/* + * Dynamic pointer array (DPA) implementation + * + * Copyright 1998 Eric Kohl + * 1998 Juergen Schmied + * 2000 Eric Kohl for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * These functions were involuntarily documented by Microsoft in 2002 as + * the outcome of an anti-trust suit brought by various U.S. governments. + * As a result the specifications on MSDN are inaccurate, incomplete + * and misleading. A much more complete (unofficial) documentation is + * available at: + * + * http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32 + */ + +#define COBJMACROS + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "commctrl.h" +#include "objbase.h" + +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dpa); + +struct _DPA +{ + INT nItemCount; + LPVOID *ptrs; + HANDLE hHeap; + INT nGrow; + INT nMaxCount; +}; + +typedef struct _STREAMDATA +{ + DWORD dwSize; + DWORD dwData2; + DWORD dwItems; +} STREAMDATA, *PSTREAMDATA; + +typedef struct _LOADDATA +{ + INT nCount; + PVOID ptr; +} LOADDATA, *LPLOADDATA; + +typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM); + + +/************************************************************************** + * DPA_LoadStream [COMCTL32.9] + * + * Loads a dynamic pointer array from a stream + * + * PARAMS + * phDpa [O] pointer to a handle to a dynamic pointer array + * loadProc [I] pointer to a callback function + * pStream [I] pointer to a stream + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, + IStream *pStream, LPARAM lParam) +{ + HRESULT errCode; + LARGE_INTEGER position; + ULARGE_INTEGER newPosition; + STREAMDATA streamData; + LOADDATA loadData; + ULONG ulRead; + HDPA hDpa; + PVOID *ptr; + + FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n", + phDpa, loadProc, pStream, lParam); + + if (!phDpa || !loadProc || !pStream) + return E_INVALIDARG; + + *phDpa = (HDPA)NULL; + + position.QuadPart = 0; + + /* + * Zero out our streamData + */ + memset(&streamData,0,sizeof(STREAMDATA)); + + errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition); + if (errCode != S_OK) + return errCode; + + errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead); + if (errCode != S_OK) + return errCode; + + FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n", + streamData.dwSize, streamData.dwData2, streamData.dwItems); + + if ( ulRead < sizeof(STREAMDATA) || + lParam < sizeof(STREAMDATA) || + streamData.dwSize < sizeof(STREAMDATA) || + streamData.dwData2 < 1) { + errCode = E_FAIL; + } + + if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */ + return E_OUTOFMEMORY; + + /* create the dpa */ + hDpa = DPA_Create (streamData.dwItems); + if (!hDpa) + return E_OUTOFMEMORY; + + if (!DPA_Grow (hDpa, streamData.dwItems)) + return E_OUTOFMEMORY; + + /* load data from the stream into the dpa */ + ptr = hDpa->ptrs; + for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) { + errCode = (loadProc)(&loadData, pStream, lParam); + if (errCode != S_OK) { + errCode = S_FALSE; + break; + } + + *ptr = loadData.ptr; + ptr++; + } + + /* set the number of items */ + hDpa->nItemCount = loadData.nCount; + + /* store the handle to the dpa */ + *phDpa = hDpa; + FIXME ("new hDpa=%p, errorcode=%lx\n", hDpa, errCode); + + return errCode; +} + + +/************************************************************************** + * DPA_SaveStream [COMCTL32.10] + * + * Saves a dynamic pointer array to a stream + * + * PARAMS + * hDpa [I] handle to a dynamic pointer array + * loadProc [I] pointer to a callback function + * pStream [I] pointer to a stream + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, + IStream *pStream, LPARAM lParam) +{ + + FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n", + hDpa, loadProc, pStream, lParam); + + return E_FAIL; +} + + +/************************************************************************** + * DPA_Merge [COMCTL32.11] + * + * Merge two dynamic pointers arrays. + * + * PARAMS + * hdpa1 [I] handle to a dynamic pointer array + * hdpa2 [I] handle to a dynamic pointer array + * dwFlags [I] flags + * pfnCompare [I] pointer to sort function + * pfnMerge [I] pointer to merge function + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags, + PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, + LPARAM lParam) +{ + INT nCount; + LPVOID *pWork1, *pWork2; + INT nResult, i; + INT nIndex; + + TRACE("%p %p %08lx %p %p %08lx)\n", + hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam); + + if (IsBadWritePtr (hdpa1, sizeof(*hdpa1))) + return FALSE; + + if (IsBadWritePtr (hdpa2, sizeof(*hdpa2))) + return FALSE; + + if (IsBadCodePtr ((FARPROC)pfnCompare)) + return FALSE; + + if (IsBadCodePtr ((FARPROC)pfnMerge)) + return FALSE; + + if (!(dwFlags & DPAM_NOSORT)) { + TRACE("sorting dpa's!\n"); + if (hdpa1->nItemCount > 0) + DPA_Sort (hdpa1, pfnCompare, lParam); + TRACE ("dpa 1 sorted!\n"); + if (hdpa2->nItemCount > 0) + DPA_Sort (hdpa2, pfnCompare, lParam); + TRACE ("dpa 2 sorted!\n"); + } + + if (hdpa2->nItemCount < 1) + return TRUE; + + TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n", + hdpa1->nItemCount, hdpa2->nItemCount); + + + /* working but untrusted implementation */ + + pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]); + pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]); + + nIndex = hdpa1->nItemCount - 1; + nCount = hdpa2->nItemCount - 1; + + do + { + if (nIndex < 0) { + if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) { + /* Now insert the remaining new items into DPA 1 */ + TRACE("%d items to be inserted at start of DPA 1\n", + nCount+1); + for (i=nCount; i>=0; i--) { + PVOID ptr; + + ptr = (pfnMerge)(3, *pWork2, NULL, lParam); + if (!ptr) + return FALSE; + DPA_InsertPtr (hdpa1, 0, ptr); + pWork2--; + } + } + break; + } + nResult = (pfnCompare)(*pWork1, *pWork2, lParam); + TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n", + nResult, nIndex, nCount); + + if (nResult == 0) + { + PVOID ptr; + + ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam); + if (!ptr) + return FALSE; + + nCount--; + pWork2--; + *pWork1 = ptr; + nIndex--; + pWork1--; + } + else if (nResult > 0) + { + /* item in DPA 1 missing from DPA 2 */ + if (dwFlags & DPAM_DELETE) + { + /* Now delete the extra item in DPA1 */ + PVOID ptr; + + ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1); + + (pfnMerge)(2, ptr, NULL, lParam); + } + nIndex--; + pWork1--; + } + else + { + /* new item in DPA 2 */ + if (dwFlags & DPAM_INSERT) + { + /* Now insert the new item in DPA 1 */ + PVOID ptr; + + ptr = (pfnMerge)(3, *pWork2, NULL, lParam); + if (!ptr) + return FALSE; + DPA_InsertPtr (hdpa1, nIndex+1, ptr); + } + nCount--; + pWork2--; + } + + } + while (nCount >= 0); + + return TRUE; +} + + +/************************************************************************** + * DPA_Destroy [COMCTL32.329] + * + * Destroys a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Destroy (const HDPA hdpa) +{ + TRACE("(%p)\n", hdpa); + + if (!hdpa) + return FALSE; + + if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) + return FALSE; + + return HeapFree (hdpa->hHeap, 0, hdpa); +} + + +/************************************************************************** + * DPA_Grow [COMCTL32.330] + * + * Sets the growth amount. + * + * PARAMS + * hdpa [I] handle (pointer) to the existing (source) pointer array + * nGrow [I] number of items by which the array grows when it's too small + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow) +{ + TRACE("(%p %d)\n", hdpa, nGrow); + + if (!hdpa) + return FALSE; + + hdpa->nGrow = max(8, nGrow); + + return TRUE; +} + + +/************************************************************************** + * DPA_Clone [COMCTL32.331] + * + * Copies a pointer array to an other one or creates a copy + * + * PARAMS + * hdpa [I] handle (pointer) to the existing (source) pointer array + * hdpaNew [O] handle (pointer) to the destination pointer array + * + * RETURNS + * Success: pointer to the destination pointer array. + * Failure: NULL + * + * NOTES + * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer + * array will be created and it's handle (pointer) is returned. + * - If 'hdpa' is a NULL-Pointer, the original implementation crashes, + * this implementation just returns NULL. + */ +HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew) +{ + INT nNewItems, nSize; + HDPA hdpaTemp; + + if (!hdpa) + return NULL; + + TRACE("(%p %p)\n", hdpa, hdpaNew); + + if (!hdpaNew) { + /* create a new DPA */ + hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + sizeof(*hdpaTemp)); + hdpaTemp->hHeap = hdpa->hHeap; + hdpaTemp->nGrow = hdpa->nGrow; + } + else + hdpaTemp = hdpaNew; + + if (hdpaTemp->ptrs) { + /* remove old pointer array */ + HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs); + hdpaTemp->ptrs = NULL; + hdpaTemp->nItemCount = 0; + hdpaTemp->nMaxCount = 0; + } + + /* create a new pointer array */ + nNewItems = hdpaTemp->nGrow * + ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1); + nSize = nNewItems * sizeof(LPVOID); + hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize); + hdpaTemp->nMaxCount = nNewItems; + + /* clone the pointer array */ + hdpaTemp->nItemCount = hdpa->nItemCount; + memmove (hdpaTemp->ptrs, hdpa->ptrs, + hdpaTemp->nItemCount * sizeof(LPVOID)); + + return hdpaTemp; +} + + +/************************************************************************** + * DPA_GetPtr [COMCTL32.332] + * + * Retrieves a pointer from a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * nIndex [I] array index of the desired pointer + * + * RETURNS + * Success: pointer + * Failure: NULL + */ +LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex) +{ + TRACE("(%p %d)\n", hdpa, nIndex); + + if (!hdpa) + return NULL; + if (!hdpa->ptrs) { + WARN("no pointer array.\n"); + return NULL; + } + if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) { + WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount); + return NULL; + } + + TRACE("-- %p\n", hdpa->ptrs[nIndex]); + + return hdpa->ptrs[nIndex]; +} + + +/************************************************************************** + * DPA_GetPtrIndex [COMCTL32.333] + * + * Retrieves the index of the specified pointer + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * p [I] pointer + * + * RETURNS + * Success: index of the specified pointer + * Failure: -1 + */ +INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p) +{ + INT i; + + if (!hdpa || !hdpa->ptrs) + return -1; + + for (i = 0; i < hdpa->nItemCount; i++) { + if (hdpa->ptrs[i] == p) + return i; + } + + return -1; +} + + +/************************************************************************** + * DPA_InsertPtr [COMCTL32.334] + * + * Inserts a pointer into a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the array + * i [I] array index + * p [I] pointer to insert + * + * RETURNS + * Success: index of the inserted pointer + * Failure: -1 + */ +INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p) +{ + TRACE("(%p %d %p)\n", hdpa, i, p); + + if (!hdpa || i < 0) return -1; + + if (i >= 0x7fff) + i = hdpa->nItemCount; + + if (i >= hdpa->nItemCount) + return DPA_SetPtr(hdpa, i, p) ? i : -1; + + /* create empty spot at the end */ + if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1; + memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID)); + hdpa->ptrs[i] = p; + return i; +} + + +/************************************************************************** + * DPA_SetPtr [COMCTL32.335] + * + * Sets a pointer in the pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * i [I] index of the pointer that will be set + * p [I] pointer to be set + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p) +{ + LPVOID *lpTemp; + + TRACE("(%p %d %p)\n", hdpa, i, p); + + if (!hdpa || i < 0 || i > 0x7fff) + return FALSE; + + if (hdpa->nItemCount <= i) { + /* within the old array */ + if (hdpa->nMaxCount <= i) { + /* resize the block of memory */ + INT nNewItems = + hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1); + INT nSize = nNewItems * sizeof(LPVOID); + + if (hdpa->ptrs) + lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize); + else + lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize); + + if (!lpTemp) + return FALSE; + + hdpa->nMaxCount = nNewItems; + hdpa->ptrs = lpTemp; + } + hdpa->nItemCount = i+1; + } + + /* put the new entry in */ + hdpa->ptrs[i] = p; + + return TRUE; +} + + +/************************************************************************** + * DPA_DeletePtr [COMCTL32.336] + * + * Removes a pointer from the pointer array. + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * i [I] index of the pointer that will be deleted + * + * RETURNS + * Success: deleted pointer + * Failure: NULL + */ +LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i) +{ + LPVOID *lpDest, *lpSrc, lpTemp = NULL; + INT nSize; + + TRACE("(%p %d)\n", hdpa, i); + + if ((!hdpa) || i < 0 || i >= hdpa->nItemCount) + return NULL; + + lpTemp = hdpa->ptrs[i]; + + /* do we need to move ?*/ + if (i < hdpa->nItemCount - 1) { + lpDest = hdpa->ptrs + i; + lpSrc = lpDest + 1; + nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID); + TRACE("-- move dest=%p src=%p size=%x\n", + lpDest, lpSrc, nSize); + memmove (lpDest, lpSrc, nSize); + } + + hdpa->nItemCount --; + + /* free memory ?*/ + if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) { + INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount); + nSize = nNewItems * sizeof(LPVOID); + lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->ptrs, nSize); + if (!lpDest) + return NULL; + + hdpa->nMaxCount = nNewItems; + hdpa->ptrs = (LPVOID*)lpDest; + } + + return lpTemp; +} + + +/************************************************************************** + * DPA_DeleteAllPtrs [COMCTL32.337] + * + * Removes all pointers and reinitializes the array. + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa) +{ + TRACE("(%p)\n", hdpa); + + if (!hdpa) + return FALSE; + + if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) + return FALSE; + + hdpa->nItemCount = 0; + hdpa->nMaxCount = hdpa->nGrow * 2; + hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->nMaxCount * sizeof(LPVOID)); + + return TRUE; +} + + +/************************************************************************** + * DPA_QuickSort [Internal] + * + * Ordinary quicksort (used by DPA_Sort). + * + * PARAMS + * lpPtrs [I] pointer to the pointer array + * l [I] index of the "left border" of the partition + * r [I] index of the "right border" of the partition + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter in compare function) + * + * RETURNS + * NONE + */ +static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r, + PFNDPACOMPARE pfnCompare, LPARAM lParam) +{ + INT m; + LPVOID t; + + TRACE("l=%i r=%i\n", l, r); + + if (l==r) /* one element is always sorted */ + return; + if (r0) + { + t = lpPtrs[m+1]; + memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l])); + lpPtrs[l] = t; + + m++; + } + l++; + } +} + + +/************************************************************************** + * DPA_Sort [COMCTL32.338] + * + * Sorts a pointer array using a user defined compare function + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter of compare function) + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam) +{ + if (!hdpa || !pfnCompare) + return FALSE; + + TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam); + + if ((hdpa->nItemCount > 1) && (hdpa->ptrs)) + DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1, + pfnCompare, lParam); + + return TRUE; +} + + +/************************************************************************** + * DPA_Search [COMCTL32.339] + * + * Searches a pointer array for a specified pointer + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * pFind [I] pointer to search for + * nStart [I] start index + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter of compare function) + * uOptions [I] search options + * + * RETURNS + * Success: index of the pointer in the array. + * Failure: -1 + * + * NOTES + * Binary search taken from R.Sedgewick "Algorithms in C"! + * Function is NOT tested! + * If something goes wrong, blame HIM not ME! (Eric Kohl) + */ +INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart, + PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions) +{ + if (!hdpa || !pfnCompare || !pFind) + return -1; + + TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n", + hdpa, pFind, nStart, pfnCompare, lParam, uOptions); + + if (uOptions & DPAS_SORTED) { + /* array is sorted --> use binary search */ + INT l, r, x, n; + LPVOID *lpPtr; + + TRACE("binary search\n"); + + l = (nStart == -1) ? 0 : nStart; + r = hdpa->nItemCount - 1; + lpPtr = hdpa->ptrs; + while (r >= l) { + x = (l + r) / 2; + n = (pfnCompare)(pFind, lpPtr[x], lParam); + if (n < 0) + r = x - 1; + else + l = x + 1; + if (n == 0) { + TRACE("-- ret=%d\n", n); + return n; + } + } + + if (uOptions & DPAS_INSERTBEFORE) { + if (r == -1) r = 0; + TRACE("-- ret=%d\n", r); + return r; + } + + if (uOptions & DPAS_INSERTAFTER) { + TRACE("-- ret=%d\n", l); + return l; + } + } + else { + /* array is not sorted --> use linear search */ + LPVOID *lpPtr; + INT nIndex; + + TRACE("linear search\n"); + + nIndex = (nStart == -1)? 0 : nStart; + lpPtr = hdpa->ptrs; + for (; nIndex < hdpa->nItemCount; nIndex++) { + if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) { + TRACE("-- ret=%d\n", nIndex); + return nIndex; + } + } + } + + TRACE("-- not found: ret=-1\n"); + return -1; +} + + +/************************************************************************** + * DPA_CreateEx [COMCTL32.340] + * + * Creates a dynamic pointer array using the specified size and heap. + * + * PARAMS + * nGrow [I] number of items by which the array grows when it is filled + * hHeap [I] handle to the heap where the array is stored + * + * RETURNS + * Success: handle (pointer) to the pointer array. + * Failure: NULL + * + * NOTES + * The DPA_ functions can be used to create and manipulate arrays of + * pointers. + */ +HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap) +{ + HDPA hdpa; + + TRACE("(%d %p)\n", nGrow, hHeap); + + if (hHeap) + hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa)); + else + hdpa = Alloc (sizeof(*hdpa)); + + if (hdpa) { + hdpa->nGrow = max(8, nGrow); + hdpa->hHeap = hHeap ? hHeap : GetProcessHeap(); + hdpa->nMaxCount = hdpa->nGrow * 2; + hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->nMaxCount * sizeof(LPVOID)); + } + + TRACE("-- %p\n", hdpa); + + return hdpa; +} + + +/************************************************************************** + * DPA_Create [COMCTL32.328] + * + * Creates a dynamic pointer array. + * + * PARAMS + * nGrow [I] number of items by which the array grows when it is filled + * + * RETURNS + * Success: handle (pointer) to the pointer array. + * Failure: NULL + * + * NOTES + * The DPA_ functions can be used to create and manipulate arrays of + * pointers. + */ +HDPA WINAPI DPA_Create (INT nGrow) +{ + return DPA_CreateEx( nGrow, 0 ); +} + + +/************************************************************************** + * DPA_EnumCallback [COMCTL32.385] + * + * Enumerates all items in a dynamic pointer array. + * + * PARAMS + * hdpa [I] handle to the dynamic pointer array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, + LPVOID lParam) +{ + INT i; + + TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); + + if (!hdpa) + return; + if (hdpa->nItemCount <= 0) + return; + + for (i = 0; i < hdpa->nItemCount; i++) { + if ((enumProc)(hdpa->ptrs[i], lParam) == 0) + return; + } + + return; +} + + +/************************************************************************** + * DPA_DestroyCallback [COMCTL32.386] + * + * Enumerates all items in a dynamic pointer array and destroys it. + * + * PARAMS + * hdpa [I] handle to the dynamic pointer array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, + LPVOID lParam) +{ + TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); + + DPA_EnumCallback (hdpa, enumProc, lParam); + DPA_Destroy (hdpa); +} diff --git a/dlls/comctl32/dsa.c b/dlls/comctl32/dsa.c new file mode 100644 index 00000000000..9b247b91366 --- /dev/null +++ b/dlls/comctl32/dsa.c @@ -0,0 +1,436 @@ +/* + * Dynamic structure array (DSA) implementation + * + * Copyright 1998 Eric Kohl + * 1998 Juergen Schmied + * 2000 Eric Kohl for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * These functions were involuntarily documented by Microsoft in 2002 as + * the outcome of an anti-trust suit brought by various U.S. governments. + * As a result the specifications on MSDN are inaccurate, incomplete + * and misleading. A much more complete (unofficial) documentation is + * available at: + * + * http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "commctrl.h" + +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsa); + +struct _DSA +{ + INT nItemCount; + LPVOID pData; + INT nMaxCount; + INT nItemSize; + INT nGrow; +}; + +/************************************************************************** + * DSA_Create [COMCTL32.320] + * + * Creates a dynamic storage array + * + * PARAMS + * nSize [I] size of the array elements + * nGrow [I] number of elements by which the array grows when it is filled + * + * RETURNS + * Success: pointer to an array control structure. Use this like a handle. + * Failure: NULL + * + * NOTES + * The DSA_ functions can be used to create and manipulate arrays of + * fixed-size memory blocks. These arrays can store any kind of data + * (e.g. strings and icons). + */ +HDSA WINAPI DSA_Create (INT nSize, INT nGrow) +{ + HDSA hdsa; + + TRACE("(size=%d grow=%d)\n", nSize, nGrow); + + hdsa = Alloc (sizeof(*hdsa)); + if (hdsa) + { + hdsa->nItemCount = 0; + hdsa->pData = NULL; + hdsa->nMaxCount = 0; + hdsa->nItemSize = nSize; + hdsa->nGrow = max(1, nGrow); + } + + return hdsa; +} + + +/************************************************************************** + * DSA_Destroy [COMCTL32.321] + * + * Destroys a dynamic storage array + * + * PARAMS + * hdsa [I] pointer to the array control structure + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_Destroy (const HDSA hdsa) +{ + TRACE("(%p)\n", hdsa); + + if (!hdsa) + return FALSE; + + if (hdsa->pData && (!Free (hdsa->pData))) + return FALSE; + + return Free (hdsa); +} + + +/************************************************************************** + * DSA_GetItem [COMCTL32.322] + * + * Copies the specified item into a caller-supplied buffer. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] number of the Item to get + * pDest [O] destination buffer. Has to be >= dwElementSize. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest) +{ + LPVOID pSrc; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); + + if (!hdsa) + return FALSE; + if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) + return FALSE; + + pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + memmove (pDest, pSrc, hdsa->nItemSize); + + return TRUE; +} + + +/************************************************************************** + * DSA_GetItemPtr [COMCTL32.323] + * + * Retrieves a pointer to the specified item. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index of the desired item + * + * RETURNS + * Success: pointer to an item + * Failure: NULL + */ +LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex) +{ + LPVOID pSrc; + + TRACE("(%p %d)\n", hdsa, nIndex); + + if (!hdsa) + return NULL; + if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) + return NULL; + + pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + + TRACE("-- ret=%p\n", pSrc); + + return pSrc; +} + + +/************************************************************************** + * DSA_SetItem [COMCTL32.325] + * + * Sets the contents of an item in the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the item + * pSrc [I] pointer to the new item data + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) +{ + INT nSize, nNewItems; + LPVOID pDest, lpTemp; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); + + if ((!hdsa) || nIndex < 0) + return FALSE; + + if (hdsa->nItemCount <= nIndex) { + /* within the old array */ + if (hdsa->nMaxCount > nIndex) { + /* within the allocated space, set a new boundary */ + hdsa->nItemCount = nIndex + 1; + } + else { + /* resize the block of memory */ + nNewItems = + hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1); + nSize = hdsa->nItemSize * nNewItems; + + lpTemp = ReAlloc (hdsa->pData, nSize); + if (!lpTemp) + return FALSE; + + hdsa->nMaxCount = nNewItems; + hdsa->nItemCount = nIndex + 1; + hdsa->pData = lpTemp; + } + } + + /* put the new entry in */ + pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + TRACE("-- move dest=%p src=%p size=%d\n", + pDest, pSrc, hdsa->nItemSize); + memmove (pDest, pSrc, hdsa->nItemSize); + + return TRUE; +} + + +/************************************************************************** + * DSA_InsertItem [COMCTL32.324] + * + * Inserts an item into the array at the specified index. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the new item + * pSrc [I] pointer to the element + * + * RETURNS + * Success: position of the new item + * Failure: -1 + */ +INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) +{ + INT nNewItems, nSize; + LPVOID lpTemp, lpDest; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); + + if ((!hdsa) || nIndex < 0) + return -1; + + /* when nIndex >= nItemCount then append */ + if (nIndex >= hdsa->nItemCount) + nIndex = hdsa->nItemCount; + + /* do we need to resize ? */ + if (hdsa->nItemCount >= hdsa->nMaxCount) { + nNewItems = hdsa->nMaxCount + hdsa->nGrow; + nSize = hdsa->nItemSize * nNewItems; + + lpTemp = ReAlloc (hdsa->pData, nSize); + if (!lpTemp) + return -1; + + hdsa->nMaxCount = nNewItems; + hdsa->pData = lpTemp; + } + + /* do we need to move elements ? */ + if (nIndex < hdsa->nItemCount) { + lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + lpDest = (char *) lpTemp + hdsa->nItemSize; + nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, lpTemp, nSize); + memmove (lpDest, lpTemp, nSize); + } + + /* ok, we can put the new Item in */ + hdsa->nItemCount++; + lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, pSrc, hdsa->nItemSize); + memmove (lpDest, pSrc, hdsa->nItemSize); + + return nIndex; +} + + +/************************************************************************** + * DSA_DeleteItem [COMCTL32.326] + * + * Deletes the specified item from the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the element to delete + * + * RETURNS + * Success: number of the deleted element + * Failure: -1 + */ +INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex) +{ + LPVOID lpDest,lpSrc; + INT nSize; + + TRACE("(%p %d)\n", hdsa, nIndex); + + if (!hdsa) + return -1; + if (nIndex < 0 || nIndex >= hdsa->nItemCount) + return -1; + + /* do we need to move ? */ + if (nIndex < hdsa->nItemCount - 1) { + lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + lpSrc = (char *) lpDest + hdsa->nItemSize; + nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, lpSrc, nSize); + memmove (lpDest, lpSrc, nSize); + } + + hdsa->nItemCount--; + + /* free memory ? */ + if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { + nSize = hdsa->nItemSize * hdsa->nItemCount; + + lpDest = ReAlloc (hdsa->pData, nSize); + if (!lpDest) + return -1; + + hdsa->nMaxCount = hdsa->nItemCount; + hdsa->pData = lpDest; + } + + return nIndex; +} + + +/************************************************************************** + * DSA_DeleteAllItems [COMCTL32.327] + * + * Removes all items and reinitializes the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa) +{ + TRACE("(%p)\n", hdsa); + + if (!hdsa) + return FALSE; + if (hdsa->pData && (!Free (hdsa->pData))) + return FALSE; + + hdsa->nItemCount = 0; + hdsa->pData = NULL; + hdsa->nMaxCount = 0; + + return TRUE; +} + + +/************************************************************************** + * DSA_EnumCallback [COMCTL32.387] + * + * Enumerates all items in a dynamic storage array. + * + * PARAMS + * hdsa [I] handle to the dynamic storage array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, + LPVOID lParam) +{ + INT i; + + TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); + + if (!hdsa) + return; + if (hdsa->nItemCount <= 0) + return; + + for (i = 0; i < hdsa->nItemCount; i++) { + LPVOID lpItem = DSA_GetItemPtr (hdsa, i); + if ((enumProc)(lpItem, lParam) == 0) + return; + } + + return; +} + + +/************************************************************************** + * DSA_DestroyCallback [COMCTL32.388] + * + * Enumerates all items in a dynamic storage array and destroys it. + * + * PARAMS + * hdsa [I] handle to the dynamic storage array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, + LPVOID lParam) +{ + TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); + + DSA_EnumCallback (hdsa, enumProc, lParam); + DSA_Destroy (hdsa); +}