/*1* Dynamic pointer array (DPA) implementation2*3* Copyright 1998 Eric Kohl4* 1998 Juergen Schmied <[email protected]>5* 2000 Eric Kohl for CodeWeavers6*7* This library is free software; you can redistribute it and/or8* modify it under the terms of the GNU Lesser General Public9* License as published by the Free Software Foundation; either10* version 2.1 of the License, or (at your option) any later version.11*12* This library is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15* Lesser General Public License for more details.16*17* You should have received a copy of the GNU Lesser General Public18* License along with this library; if not, write to the Free Software19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA20*21* NOTES22* These functions were involuntarily documented by Microsoft in 2002 as23* the outcome of an anti-trust suit brought by various U.S. governments.24* As a result the specifications on MSDN are inaccurate, incomplete25* and misleading. A much more complete (unofficial) documentation is26* available at:27*28* http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl3229*/3031#define COBJMACROS3233#include <stdarg.h>34#include <limits.h>3536#include "windef.h"37#include "winbase.h"38#include "winuser.h"39#include "commctrl.h"40#include "objbase.h"4142#include "comctl32.h"43#include "wine/debug.h"4445WINE_DEFAULT_DEBUG_CHANNEL(dpa);4647typedef struct _DPA48{49INT nItemCount;50LPVOID *ptrs;51HANDLE hHeap;52INT nGrow;53INT nMaxCount;54} DPA;5556typedef struct _STREAMDATA57{58DWORD dwSize;59DWORD dwData2;60DWORD dwItems;61} STREAMDATA, *PSTREAMDATA;6263/**************************************************************************64* DPA_LoadStream [COMCTL32.9]65*66* Loads a dynamic pointer array from a stream67*68* PARAMS69* phDpa [O] pointer to a handle to a dynamic pointer array70* loadProc [I] pointer to a callback function71* pStream [I] pointer to a stream72* pData [I] pointer to callback data73*74* RETURNS75* Success: S_OK, S_FALSE - partial success76* Failure: HRESULT error code77*78* NOTES79* No more information available yet!80*/81HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, PFNDPASTREAM loadProc,82IStream *pStream, LPVOID pData)83{84HRESULT errCode;85LARGE_INTEGER position;86ULARGE_INTEGER initial_pos;87STREAMDATA streamData;88DPASTREAMINFO streamInfo;89ULONG ulRead;90HDPA hDpa;91PVOID *ptr;9293TRACE ("phDpa=%p loadProc=%p pStream=%p pData=%p\n",94phDpa, loadProc, pStream, pData);9596if (!phDpa || !loadProc || !pStream)97return E_INVALIDARG;9899*phDpa = NULL;100101position.QuadPart = 0;102103errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);104if (errCode != S_OK)105return errCode;106107memset(&streamData, 0, sizeof(STREAMDATA));108errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);109if (errCode != S_OK)110return errCode;111112TRACE ("dwSize=%lu dwData2=%lu dwItems=%lu\n",113streamData.dwSize, streamData.dwData2, streamData.dwItems);114115if (ulRead < sizeof(STREAMDATA) ||116streamData.dwSize < sizeof(STREAMDATA) || streamData.dwData2 != 1) {117/* back to initial position */118position.QuadPart = initial_pos.QuadPart;119IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);120return E_FAIL;121}122123if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */124return E_OUTOFMEMORY;125126/* create the dpa */127hDpa = DPA_Create (streamData.dwItems);128if (!hDpa)129return E_OUTOFMEMORY;130131if (!DPA_Grow (hDpa, streamData.dwItems)) {132DPA_Destroy (hDpa);133return E_OUTOFMEMORY;134}135136/* load data from the stream into the dpa */137ptr = hDpa->ptrs;138for (streamInfo.iPos = 0; streamInfo.iPos < streamData.dwItems; streamInfo.iPos++) {139errCode = (loadProc)(&streamInfo, pStream, pData);140if (errCode != S_OK) {141errCode = S_FALSE;142break;143}144145*ptr = streamInfo.pvItem;146ptr++;147}148149/* set the number of items */150hDpa->nItemCount = streamInfo.iPos;151152/* store the handle to the dpa */153*phDpa = hDpa;154TRACE ("new hDpa=%p, errorcode %lx\n", hDpa, errCode);155156return errCode;157}158159160/**************************************************************************161* DPA_SaveStream [COMCTL32.10]162*163* Saves a dynamic pointer array to a stream164*165* PARAMS166* hDpa [I] handle to a dynamic pointer array167* saveProc [I] pointer to a callback function168* pStream [I] pointer to a stream169* pData [I] pointer to callback data170*171* RETURNS172* Success: S_OK, S_FALSE - partial success173* Failure: HRESULT error code174*175* NOTES176* No more information available yet!177*/178HRESULT WINAPI DPA_SaveStream (HDPA hDpa, PFNDPASTREAM saveProc,179IStream *pStream, LPVOID pData)180{181LARGE_INTEGER position;182ULARGE_INTEGER initial_pos, curr_pos;183STREAMDATA streamData;184DPASTREAMINFO streamInfo;185HRESULT hr;186PVOID *ptr;187188TRACE ("hDpa=%p saveProc=%p pStream=%p pData=%p\n",189hDpa, saveProc, pStream, pData);190191if (!hDpa || !saveProc || !pStream) return E_INVALIDARG;192193/* save initial position to write header after completion */194position.QuadPart = 0;195hr = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);196if (hr != S_OK)197return hr;198199/* write empty header */200streamData.dwSize = sizeof(streamData);201streamData.dwData2 = 1;202streamData.dwItems = 0;203204hr = IStream_Write (pStream, &streamData, sizeof(streamData), NULL);205if (hr != S_OK) {206position.QuadPart = initial_pos.QuadPart;207IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);208return hr;209}210211/* no items - we're done */212if (hDpa->nItemCount == 0) return S_OK;213214ptr = hDpa->ptrs;215for (streamInfo.iPos = 0; streamInfo.iPos < hDpa->nItemCount; streamInfo.iPos++) {216streamInfo.pvItem = *ptr;217hr = (saveProc)(&streamInfo, pStream, pData);218if (hr != S_OK) {219hr = S_FALSE;220break;221}222ptr++;223}224225/* write updated header */226position.QuadPart = 0;227IStream_Seek (pStream, position, STREAM_SEEK_CUR, &curr_pos);228229streamData.dwSize = curr_pos.QuadPart - initial_pos.QuadPart;230streamData.dwData2 = 1;231streamData.dwItems = streamInfo.iPos;232233position.QuadPart = initial_pos.QuadPart;234IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);235IStream_Write (pStream, &streamData, sizeof(streamData), NULL);236237position.QuadPart = curr_pos.QuadPart;238IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);239240return hr;241}242243244/**************************************************************************245* DPA_Merge [COMCTL32.11]246*247* Merge two dynamic pointers arrays.248*249* PARAMS250* hdpa1 [I] handle to a dynamic pointer array251* hdpa2 [I] handle to a dynamic pointer array252* dwFlags [I] flags253* pfnCompare [I] pointer to sort function254* pfnMerge [I] pointer to merge function255* lParam [I] application specific value256*257* RETURNS258* Success: TRUE259* Failure: FALSE260*261* NOTES262* No more information available yet!263*/264BOOL WINAPI DPA_Merge (HDPA hdpa1, HDPA hdpa2, DWORD dwFlags,265PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge,266LPARAM lParam)267{268INT nCount;269LPVOID *pWork1, *pWork2;270INT nResult, i;271INT nIndex;272273TRACE("%p, %p, %#lx, %p, %p, %#Ix\n", hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);274275if (IsBadWritePtr (hdpa1, sizeof(*hdpa1)))276return FALSE;277278if (IsBadWritePtr (hdpa2, sizeof(*hdpa2)))279return FALSE;280281if (IsBadCodePtr ((FARPROC)pfnCompare))282return FALSE;283284if (IsBadCodePtr ((FARPROC)pfnMerge))285return FALSE;286287if (!(dwFlags & DPAM_SORTED)) {288TRACE("sorting dpa's.\n");289if (hdpa1->nItemCount > 0)290DPA_Sort (hdpa1, pfnCompare, lParam);291TRACE ("dpa 1 sorted.\n");292if (hdpa2->nItemCount > 0)293DPA_Sort (hdpa2, pfnCompare, lParam);294TRACE ("dpa 2 sorted.\n");295}296297if (hdpa2->nItemCount < 1)298return TRUE;299300TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",301hdpa1->nItemCount, hdpa2->nItemCount);302303304nIndex = hdpa1->nItemCount - 1;305nCount = hdpa2->nItemCount - 1;306307do308{309pWork1 = &hdpa1->ptrs[nIndex];310pWork2 = &hdpa2->ptrs[nCount];311312if (nIndex < 0) {313if ((nCount >= 0) && (dwFlags & DPAM_UNION)) {314/* Now insert the remaining new items into DPA 1 */315TRACE("%d items to be inserted at start of DPA 1\n",316nCount+1);317for (i=nCount; i>=0; i--) {318PVOID ptr;319320ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);321if (!ptr)322return FALSE;323DPA_InsertPtr (hdpa1, 0, ptr);324pWork2--;325}326}327break;328}329nResult = (pfnCompare)(*pWork1, *pWork2, lParam);330TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",331nResult, nIndex, nCount);332333if (nResult == 0)334{335PVOID ptr;336337ptr = (pfnMerge)(DPAMM_MERGE, *pWork1, *pWork2, lParam);338if (!ptr)339return FALSE;340341nCount--;342*pWork1 = ptr;343nIndex--;344}345else if (nResult > 0)346{347/* item in DPA 1 missing from DPA 2 */348if (dwFlags & DPAM_INTERSECT)349{350/* Now delete the extra item in DPA1 */351PVOID ptr;352353ptr = DPA_DeletePtr (hdpa1, nIndex);354355(pfnMerge)(DPAMM_DELETE, ptr, NULL, lParam);356}357nIndex--;358}359else360{361/* new item in DPA 2 */362if (dwFlags & DPAM_UNION)363{364/* Now insert the new item in DPA 1 */365PVOID ptr;366367ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);368if (!ptr)369return FALSE;370DPA_InsertPtr (hdpa1, nIndex+1, ptr);371}372nCount--;373}374375}376while (nCount >= 0);377378return TRUE;379}380381382/**************************************************************************383* DPA_Destroy [COMCTL32.329]384*385* Destroys a dynamic pointer array386*387* PARAMS388* hdpa [I] handle (pointer) to the pointer array389*390* RETURNS391* Success: TRUE392* Failure: FALSE393*/394BOOL WINAPI DPA_Destroy (HDPA hdpa)395{396TRACE("(%p)\n", hdpa);397398if (!hdpa)399return FALSE;400401if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))402return FALSE;403404return HeapFree (hdpa->hHeap, 0, hdpa);405}406407408/**************************************************************************409* DPA_Grow [COMCTL32.330]410*411* Sets the growth amount.412*413* PARAMS414* hdpa [I] handle (pointer) to the existing (source) pointer array415* nGrow [I] number of items by which the array grows when it's too small416*417* RETURNS418* Success: TRUE419* Failure: FALSE420*/421BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow)422{423INT items;424TRACE("(%p %d)\n", hdpa, nGrow);425426if (!hdpa)427return FALSE;428429nGrow = max( 8, nGrow );430items = nGrow * (((hdpa->nMaxCount - 1) / nGrow) + 1);431if (items > hdpa->nMaxCount)432{433void *ptr;434435if (hdpa->ptrs)436ptr = HeapReAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, items * sizeof(LPVOID) );437else438ptr = HeapAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, items * sizeof(LPVOID) );439if (!ptr) return FALSE;440hdpa->nMaxCount = items;441hdpa->ptrs = ptr;442}443hdpa->nGrow = nGrow;444445return TRUE;446}447448449/**************************************************************************450* DPA_Clone [COMCTL32.331]451*452* Copies a pointer array to another one or creates a copy453*454* PARAMS455* hdpa [I] handle (pointer) to the existing (source) pointer array456* hdpaNew [O] handle (pointer) to the destination pointer array457*458* RETURNS459* Success: pointer to the destination pointer array.460* Failure: NULL461*462* NOTES463* - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer464* array will be created and its handle (pointer) is returned.465* - If 'hdpa' is a NULL-Pointer, the original implementation crashes,466* this implementation just returns NULL.467*/468HDPA WINAPI DPA_Clone (const HDPA hdpa, HDPA hdpaNew)469{470INT nNewItems, nSize;471HDPA hdpaTemp;472473if (!hdpa)474return NULL;475476TRACE("(%p %p)\n", hdpa, hdpaNew);477478if (!hdpaNew) {479/* create a new DPA */480hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,481sizeof(*hdpaTemp));482hdpaTemp->hHeap = hdpa->hHeap;483hdpaTemp->nGrow = hdpa->nGrow;484}485else486hdpaTemp = hdpaNew;487488if (hdpaTemp->ptrs) {489/* remove old pointer array */490HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);491hdpaTemp->ptrs = NULL;492hdpaTemp->nItemCount = 0;493hdpaTemp->nMaxCount = 0;494}495496/* create a new pointer array */497nNewItems = hdpaTemp->nGrow *498(((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);499nSize = nNewItems * sizeof(LPVOID);500hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);501hdpaTemp->nMaxCount = nNewItems;502503/* clone the pointer array */504hdpaTemp->nItemCount = hdpa->nItemCount;505memmove (hdpaTemp->ptrs, hdpa->ptrs,506hdpaTemp->nItemCount * sizeof(LPVOID));507508return hdpaTemp;509}510511512/**************************************************************************513* DPA_GetPtr [COMCTL32.332]514*515* Retrieves a pointer from a dynamic pointer array516*517* PARAMS518* hdpa [I] handle (pointer) to the pointer array519* nIndex [I] array index of the desired pointer520*521* RETURNS522* Success: pointer523* Failure: NULL524*/525LPVOID WINAPI DPA_GetPtr (HDPA hdpa, INT_PTR nIndex)526{527TRACE("%p, %Id\n", hdpa, nIndex);528529if (!hdpa)530return NULL;531if (!hdpa->ptrs) {532WARN("no pointer array.\n");533return NULL;534}535if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {536WARN("not enough pointers in array (%Id vs %d).\n",nIndex,hdpa->nItemCount);537return NULL;538}539540TRACE("-- %p\n", hdpa->ptrs[nIndex]);541542return hdpa->ptrs[nIndex];543}544545546/**************************************************************************547* DPA_GetPtrIndex [COMCTL32.333]548*549* Retrieves the index of the specified pointer550*551* PARAMS552* hdpa [I] handle (pointer) to the pointer array553* p [I] pointer554*555* RETURNS556* Success: index of the specified pointer557* Failure: -1558*/559INT WINAPI DPA_GetPtrIndex (HDPA hdpa, LPCVOID p)560{561INT i;562563if (!hdpa || !hdpa->ptrs)564return -1;565566for (i = 0; i < hdpa->nItemCount; i++) {567if (hdpa->ptrs[i] == p)568return i;569}570571return -1;572}573574575/**************************************************************************576* DPA_InsertPtr [COMCTL32.334]577*578* Inserts a pointer into a dynamic pointer array579*580* PARAMS581* hdpa [I] handle (pointer) to the array582* i [I] array index583* p [I] pointer to insert584*585* RETURNS586* Success: index of the inserted pointer587* Failure: -1588*/589INT WINAPI DPA_InsertPtr (HDPA hdpa, INT i, LPVOID p)590{591TRACE("(%p %d %p)\n", hdpa, i, p);592593if (!hdpa || i < 0) return -1;594595/* append item if index is out of bounds */596i = min(hdpa->nItemCount, i);597598/* create empty spot at the end */599if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;600601if (i != hdpa->nItemCount - 1)602memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i,603(hdpa->nItemCount - i - 1) * sizeof(LPVOID));604605hdpa->ptrs[i] = p;606return i;607}608609610/**************************************************************************611* DPA_SetPtr [COMCTL32.335]612*613* Sets a pointer in the pointer array614*615* PARAMS616* hdpa [I] handle (pointer) to the pointer array617* i [I] index of the pointer that will be set618* p [I] pointer to be set619*620* RETURNS621* Success: TRUE622* Failure: FALSE623*/624BOOL WINAPI DPA_SetPtr (HDPA hdpa, INT i, LPVOID p)625{626LPVOID *lpTemp;627628TRACE("(%p %d %p)\n", hdpa, i, p);629630if (!hdpa || i < 0)631return FALSE;632633if (hdpa->nItemCount <= i) {634/* within the old array */635if (hdpa->nMaxCount <= i) {636/* resize the block of memory */637INT nNewItems =638hdpa->nGrow * ((((i+1) - 1) / hdpa->nGrow) + 1);639INT nSize = nNewItems * sizeof(LPVOID);640641if (hdpa->ptrs)642lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);643else644lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);645646if (!lpTemp)647return FALSE;648649hdpa->nMaxCount = nNewItems;650hdpa->ptrs = lpTemp;651}652hdpa->nItemCount = i+1;653}654655/* put the new entry in */656hdpa->ptrs[i] = p;657658return TRUE;659}660661662/**************************************************************************663* DPA_DeletePtr [COMCTL32.336]664*665* Removes a pointer from the pointer array.666*667* PARAMS668* hdpa [I] handle (pointer) to the pointer array669* i [I] index of the pointer that will be deleted670*671* RETURNS672* Success: deleted pointer673* Failure: NULL674*/675LPVOID WINAPI DPA_DeletePtr (HDPA hdpa, INT i)676{677LPVOID *lpDest, *lpSrc, lpTemp = NULL;678INT nSize;679680TRACE("(%p %d)\n", hdpa, i);681682if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)683return NULL;684685lpTemp = hdpa->ptrs[i];686687/* do we need to move ?*/688if (i < hdpa->nItemCount - 1) {689lpDest = hdpa->ptrs + i;690lpSrc = lpDest + 1;691nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);692TRACE("-- move dest=%p src=%p size=%x\n",693lpDest, lpSrc, nSize);694memmove (lpDest, lpSrc, nSize);695}696697hdpa->nItemCount --;698699/* free memory ?*/700if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {701INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);702nSize = nNewItems * sizeof(LPVOID);703lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,704hdpa->ptrs, nSize);705if (!lpDest)706return NULL;707708hdpa->nMaxCount = nNewItems;709hdpa->ptrs = lpDest;710}711712return lpTemp;713}714715716/**************************************************************************717* DPA_DeleteAllPtrs [COMCTL32.337]718*719* Removes all pointers and reinitializes the array.720*721* PARAMS722* hdpa [I] handle (pointer) to the pointer array723*724* RETURNS725* Success: TRUE726* Failure: FALSE727*/728BOOL WINAPI DPA_DeleteAllPtrs (HDPA hdpa)729{730TRACE("(%p)\n", hdpa);731732if (!hdpa)733return FALSE;734735if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))736return FALSE;737738hdpa->nItemCount = 0;739hdpa->nMaxCount = hdpa->nGrow * 2;740hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,741hdpa->nMaxCount * sizeof(LPVOID));742743return TRUE;744}745746747/**************************************************************************748* DPA_QuickSort [Internal]749*750* Ordinary quicksort (used by DPA_Sort).751*752* PARAMS753* lpPtrs [I] pointer to the pointer array754* l [I] index of the "left border" of the partition755* r [I] index of the "right border" of the partition756* pfnCompare [I] pointer to the compare function757* lParam [I] user defined value (3rd parameter in compare function)758*759* RETURNS760* NONE761*/762static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,763PFNDPACOMPARE pfnCompare, LPARAM lParam)764{765INT m;766LPVOID t;767768TRACE("l=%i r=%i\n", l, r);769770if (l==r) /* one element is always sorted */771return;772if (r<l) /* oops, got it in the wrong order */773{774DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);775return;776}777m = (l+r)/2; /* divide by two */778DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);779DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);780781/* join the two sides */782while( (l<=m) && (m<r) )783{784if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)785{786t = lpPtrs[m+1];787memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));788lpPtrs[l] = t;789790m++;791}792l++;793}794}795796797/**************************************************************************798* DPA_Sort [COMCTL32.338]799*800* Sorts a pointer array using a user defined compare function801*802* PARAMS803* hdpa [I] handle (pointer) to the pointer array804* pfnCompare [I] pointer to the compare function805* lParam [I] user defined value (3rd parameter of compare function)806*807* RETURNS808* Success: TRUE809* Failure: FALSE810*/811BOOL WINAPI DPA_Sort (HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)812{813if (!hdpa || !pfnCompare)814return FALSE;815816TRACE("%p, %p, %#Ix\n", hdpa, pfnCompare, lParam);817818if ((hdpa->nItemCount > 1) && (hdpa->ptrs))819DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,820pfnCompare, lParam);821822return TRUE;823}824825826/**************************************************************************827* DPA_Search [COMCTL32.339]828*829* Searches a pointer array for a specified pointer830*831* PARAMS832* hdpa [I] handle (pointer) to the pointer array833* pFind [I] pointer to search for834* nStart [I] start index835* pfnCompare [I] pointer to the compare function836* lParam [I] user defined value (3rd parameter of compare function)837* uOptions [I] search options838*839* RETURNS840* Success: index of the pointer in the array.841* Failure: -1842*/843INT WINAPI DPA_Search (HDPA hdpa, LPVOID pFind, INT nStart,844PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)845{846if (!hdpa || !pfnCompare || !pFind)847return -1;848849TRACE("%p, %p, %d, %p, %#Ix, %#x\n", hdpa, pFind, nStart, pfnCompare, lParam, uOptions);850851if (uOptions & DPAS_SORTED) {852/* array is sorted --> use binary search */853INT l, r, x, n;854LPVOID *lpPtr;855856/* for binary search ignore start index */857l = 0;858r = hdpa->nItemCount - 1;859lpPtr = hdpa->ptrs;860while (r >= l) {861x = l + (r - l) / 2;862n = (pfnCompare)(pFind, lpPtr[x], lParam);863if (n == 0)864return x;865else if (n < 0)866r = x - 1;867else /* (n > 0) */868l = x + 1;869}870if (uOptions & (DPAS_INSERTBEFORE|DPAS_INSERTAFTER)) return l;871}872else {873/* array is not sorted --> use linear search */874LPVOID *lpPtr;875INT nIndex;876877nIndex = (nStart == -1)? 0 : nStart;878lpPtr = hdpa->ptrs;879for (; nIndex < hdpa->nItemCount; nIndex++) {880if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0)881return nIndex;882}883}884885return -1;886}887888889/**************************************************************************890* DPA_CreateEx [COMCTL32.340]891*892* Creates a dynamic pointer array using the specified size and heap.893*894* PARAMS895* nGrow [I] number of items by which the array grows when it is filled896* hHeap [I] handle to the heap where the array is stored897*898* RETURNS899* Success: handle (pointer) to the pointer array.900* Failure: NULL901*902* NOTES903* The DPA_ functions can be used to create and manipulate arrays of904* pointers.905*/906HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)907{908HDPA hdpa;909910TRACE("(%d %p)\n", nGrow, hHeap);911912if (!hHeap) hHeap = GetProcessHeap();913hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));914915if (hdpa) {916hdpa->nGrow = max(8, nGrow);917hdpa->hHeap = hHeap;918hdpa->nMaxCount = hdpa->nGrow * 2;919hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,920hdpa->nMaxCount * sizeof(LPVOID));921}922923TRACE("-- %p\n", hdpa);924925return hdpa;926}927928929/**************************************************************************930* DPA_Create [COMCTL32.328]931*932* Creates a dynamic pointer array.933*934* PARAMS935* nGrow [I] number of items by which the array grows when it is filled936*937* RETURNS938* Success: handle (pointer) to the pointer array.939* Failure: NULL940*941* NOTES942* The DPA_ functions can be used to create and manipulate arrays of943* pointers.944*/945HDPA WINAPI DPA_Create (INT nGrow)946{947return DPA_CreateEx( nGrow, 0 );948}949950951/**************************************************************************952* DPA_EnumCallback [COMCTL32.385]953*954* Enumerates all items in a dynamic pointer array.955*956* PARAMS957* hdpa [I] handle to the dynamic pointer array958* enumProc [I]959* lParam [I]960*961* RETURNS962* none963*/964VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,965LPVOID lParam)966{967INT i;968969TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);970971if (!hdpa)972return;973if (hdpa->nItemCount <= 0)974return;975976for (i = 0; i < hdpa->nItemCount; i++) {977if ((enumProc)(hdpa->ptrs[i], lParam) == 0)978return;979}980981return;982}983984985/**************************************************************************986* DPA_DestroyCallback [COMCTL32.386]987*988* Enumerates all items in a dynamic pointer array and destroys it.989*990* PARAMS991* hdpa [I] handle to the dynamic pointer array992* enumProc [I]993* lParam [I]994*995* RETURNS996* none997*/998void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,999LPVOID lParam)1000{1001TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);10021003DPA_EnumCallback (hdpa, enumProc, lParam);1004DPA_Destroy (hdpa);1005}10061007/**************************************************************************1008* DPA_GetSize [COMCTL32.@]1009*1010* Returns all array allocated memory size1011*1012* PARAMS1013* hdpa [I] handle to the dynamic pointer array1014*1015* RETURNS1016* Size in bytes1017*/1018ULONGLONG WINAPI DPA_GetSize(HDPA hdpa)1019{1020TRACE("(%p)\n", hdpa);10211022if (!hdpa) return 0;10231024return sizeof(DPA) + hdpa->nMaxCount*sizeof(PVOID);1025}102610271028