Release 1.9.16.
[wine.git] / dlls / comctl32 / dpa.c
blobb5b7ff811270d66d891dc92903c9f78c4a6b34ca
1 /*
2 * Dynamic pointer array (DPA) implementation
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * NOTES
23 * These functions were involuntarily documented by Microsoft in 2002 as
24 * the outcome of an anti-trust suit brought by various U.S. governments.
25 * As a result the specifications on MSDN are inaccurate, incomplete
26 * and misleading. A much more complete (unofficial) documentation is
27 * available at:
29 * http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32
32 #define COBJMACROS
34 #include <stdarg.h>
35 #include <limits.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "commctrl.h"
41 #include "objbase.h"
43 #include "comctl32.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(dpa);
48 typedef struct _DPA
50 INT nItemCount;
51 LPVOID *ptrs;
52 HANDLE hHeap;
53 INT nGrow;
54 INT nMaxCount;
55 } DPA;
57 typedef struct _STREAMDATA
59 DWORD dwSize;
60 DWORD dwData2;
61 DWORD dwItems;
62 } STREAMDATA, *PSTREAMDATA;
64 /**************************************************************************
65 * DPA_LoadStream [COMCTL32.9]
67 * Loads a dynamic pointer array from a stream
69 * PARAMS
70 * phDpa [O] pointer to a handle to a dynamic pointer array
71 * loadProc [I] pointer to a callback function
72 * pStream [I] pointer to a stream
73 * pData [I] pointer to callback data
75 * RETURNS
76 * Success: S_OK, S_FALSE - partial success
77 * Failure: HRESULT error code
79 * NOTES
80 * No more information available yet!
82 HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, PFNDPASTREAM loadProc,
83 IStream *pStream, LPVOID pData)
85 HRESULT errCode;
86 LARGE_INTEGER position;
87 ULARGE_INTEGER initial_pos;
88 STREAMDATA streamData;
89 DPASTREAMINFO streamInfo;
90 ULONG ulRead;
91 HDPA hDpa;
92 PVOID *ptr;
94 TRACE ("phDpa=%p loadProc=%p pStream=%p pData=%p\n",
95 phDpa, loadProc, pStream, pData);
97 if (!phDpa || !loadProc || !pStream)
98 return E_INVALIDARG;
100 *phDpa = NULL;
102 position.QuadPart = 0;
104 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);
105 if (errCode != S_OK)
106 return errCode;
108 memset(&streamData, 0, sizeof(STREAMDATA));
109 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
110 if (errCode != S_OK)
111 return errCode;
113 TRACE ("dwSize=%u dwData2=%u dwItems=%u\n",
114 streamData.dwSize, streamData.dwData2, streamData.dwItems);
116 if (ulRead < sizeof(STREAMDATA) ||
117 streamData.dwSize < sizeof(STREAMDATA) || streamData.dwData2 != 1) {
118 /* back to initial position */
119 position.QuadPart = initial_pos.QuadPart;
120 IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
121 return E_FAIL;
124 if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
125 return E_OUTOFMEMORY;
127 /* create the dpa */
128 hDpa = DPA_Create (streamData.dwItems);
129 if (!hDpa)
130 return E_OUTOFMEMORY;
132 if (!DPA_Grow (hDpa, streamData.dwItems)) {
133 DPA_Destroy (hDpa);
134 return E_OUTOFMEMORY;
137 /* load data from the stream into the dpa */
138 ptr = hDpa->ptrs;
139 for (streamInfo.iPos = 0; streamInfo.iPos < streamData.dwItems; streamInfo.iPos++) {
140 errCode = (loadProc)(&streamInfo, pStream, pData);
141 if (errCode != S_OK) {
142 errCode = S_FALSE;
143 break;
146 *ptr = streamInfo.pvItem;
147 ptr++;
150 /* set the number of items */
151 hDpa->nItemCount = streamInfo.iPos;
153 /* store the handle to the dpa */
154 *phDpa = hDpa;
155 TRACE ("new hDpa=%p, errorcode=%x\n", hDpa, errCode);
157 return errCode;
161 /**************************************************************************
162 * DPA_SaveStream [COMCTL32.10]
164 * Saves a dynamic pointer array to a stream
166 * PARAMS
167 * hDpa [I] handle to a dynamic pointer array
168 * saveProc [I] pointer to a callback function
169 * pStream [I] pointer to a stream
170 * pData [I] pointer to callback data
172 * RETURNS
173 * Success: S_OK, S_FALSE - partial success
174 * Failure: HRESULT error code
176 * NOTES
177 * No more information available yet!
179 HRESULT WINAPI DPA_SaveStream (HDPA hDpa, PFNDPASTREAM saveProc,
180 IStream *pStream, LPVOID pData)
182 LARGE_INTEGER position;
183 ULARGE_INTEGER initial_pos, curr_pos;
184 STREAMDATA streamData;
185 DPASTREAMINFO streamInfo;
186 HRESULT hr;
187 PVOID *ptr;
189 TRACE ("hDpa=%p saveProc=%p pStream=%p pData=%p\n",
190 hDpa, saveProc, pStream, pData);
192 if (!hDpa || !saveProc || !pStream) return E_INVALIDARG;
194 /* save initial position to write header after completion */
195 position.QuadPart = 0;
196 hr = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);
197 if (hr != S_OK)
198 return hr;
200 /* write empty header */
201 streamData.dwSize = sizeof(streamData);
202 streamData.dwData2 = 1;
203 streamData.dwItems = 0;
205 hr = IStream_Write (pStream, &streamData, sizeof(streamData), NULL);
206 if (hr != S_OK) {
207 position.QuadPart = initial_pos.QuadPart;
208 IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
209 return hr;
212 /* no items - we're done */
213 if (hDpa->nItemCount == 0) return S_OK;
215 ptr = hDpa->ptrs;
216 for (streamInfo.iPos = 0; streamInfo.iPos < hDpa->nItemCount; streamInfo.iPos++) {
217 streamInfo.pvItem = *ptr;
218 hr = (saveProc)(&streamInfo, pStream, pData);
219 if (hr != S_OK) {
220 hr = S_FALSE;
221 break;
223 ptr++;
226 /* write updated header */
227 position.QuadPart = 0;
228 IStream_Seek (pStream, position, STREAM_SEEK_CUR, &curr_pos);
230 streamData.dwSize = curr_pos.QuadPart - initial_pos.QuadPart;
231 streamData.dwData2 = 1;
232 streamData.dwItems = streamInfo.iPos;
234 position.QuadPart = initial_pos.QuadPart;
235 IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
236 IStream_Write (pStream, &streamData, sizeof(streamData), NULL);
238 position.QuadPart = curr_pos.QuadPart;
239 IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
241 return hr;
245 /**************************************************************************
246 * DPA_Merge [COMCTL32.11]
248 * Merge two dynamic pointers arrays.
250 * PARAMS
251 * hdpa1 [I] handle to a dynamic pointer array
252 * hdpa2 [I] handle to a dynamic pointer array
253 * dwFlags [I] flags
254 * pfnCompare [I] pointer to sort function
255 * pfnMerge [I] pointer to merge function
256 * lParam [I] application specific value
258 * RETURNS
259 * Success: TRUE
260 * Failure: FALSE
262 * NOTES
263 * No more information available yet!
265 BOOL WINAPI DPA_Merge (HDPA hdpa1, HDPA hdpa2, DWORD dwFlags,
266 PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge,
267 LPARAM lParam)
269 INT nCount;
270 LPVOID *pWork1, *pWork2;
271 INT nResult, i;
272 INT nIndex;
274 TRACE("(%p %p %08x %p %p %08lx)\n",
275 hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
277 if (IsBadWritePtr (hdpa1, sizeof(*hdpa1)))
278 return FALSE;
280 if (IsBadWritePtr (hdpa2, sizeof(*hdpa2)))
281 return FALSE;
283 if (IsBadCodePtr ((FARPROC)pfnCompare))
284 return FALSE;
286 if (IsBadCodePtr ((FARPROC)pfnMerge))
287 return FALSE;
289 if (!(dwFlags & DPAM_SORTED)) {
290 TRACE("sorting dpa's!\n");
291 if (hdpa1->nItemCount > 0)
292 DPA_Sort (hdpa1, pfnCompare, lParam);
293 TRACE ("dpa 1 sorted!\n");
294 if (hdpa2->nItemCount > 0)
295 DPA_Sort (hdpa2, pfnCompare, lParam);
296 TRACE ("dpa 2 sorted!\n");
299 if (hdpa2->nItemCount < 1)
300 return TRUE;
302 TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
303 hdpa1->nItemCount, hdpa2->nItemCount);
306 nIndex = hdpa1->nItemCount - 1;
307 nCount = hdpa2->nItemCount - 1;
311 pWork1 = &hdpa1->ptrs[nIndex];
312 pWork2 = &hdpa2->ptrs[nCount];
314 if (nIndex < 0) {
315 if ((nCount >= 0) && (dwFlags & DPAM_UNION)) {
316 /* Now insert the remaining new items into DPA 1 */
317 TRACE("%d items to be inserted at start of DPA 1\n",
318 nCount+1);
319 for (i=nCount; i>=0; i--) {
320 PVOID ptr;
322 ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);
323 if (!ptr)
324 return FALSE;
325 DPA_InsertPtr (hdpa1, 0, ptr);
326 pWork2--;
329 break;
331 nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
332 TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
333 nResult, nIndex, nCount);
335 if (nResult == 0)
337 PVOID ptr;
339 ptr = (pfnMerge)(DPAMM_MERGE, *pWork1, *pWork2, lParam);
340 if (!ptr)
341 return FALSE;
343 nCount--;
344 *pWork1 = ptr;
345 nIndex--;
347 else if (nResult > 0)
349 /* item in DPA 1 missing from DPA 2 */
350 if (dwFlags & DPAM_INTERSECT)
352 /* Now delete the extra item in DPA1 */
353 PVOID ptr;
355 ptr = DPA_DeletePtr (hdpa1, nIndex);
357 (pfnMerge)(DPAMM_DELETE, ptr, NULL, lParam);
359 nIndex--;
361 else
363 /* new item in DPA 2 */
364 if (dwFlags & DPAM_UNION)
366 /* Now insert the new item in DPA 1 */
367 PVOID ptr;
369 ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);
370 if (!ptr)
371 return FALSE;
372 DPA_InsertPtr (hdpa1, nIndex+1, ptr);
374 nCount--;
378 while (nCount >= 0);
380 return TRUE;
384 /**************************************************************************
385 * DPA_Destroy [COMCTL32.329]
387 * Destroys a dynamic pointer array
389 * PARAMS
390 * hdpa [I] handle (pointer) to the pointer array
392 * RETURNS
393 * Success: TRUE
394 * Failure: FALSE
396 BOOL WINAPI DPA_Destroy (HDPA hdpa)
398 TRACE("(%p)\n", hdpa);
400 if (!hdpa)
401 return FALSE;
403 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
404 return FALSE;
406 return HeapFree (hdpa->hHeap, 0, hdpa);
410 /**************************************************************************
411 * DPA_Grow [COMCTL32.330]
413 * Sets the growth amount.
415 * PARAMS
416 * hdpa [I] handle (pointer) to the existing (source) pointer array
417 * nGrow [I] number of items by which the array grows when it's too small
419 * RETURNS
420 * Success: TRUE
421 * Failure: FALSE
423 BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow)
425 INT items;
426 TRACE("(%p %d)\n", hdpa, nGrow);
428 if (!hdpa)
429 return FALSE;
431 nGrow = max( 8, nGrow );
432 items = nGrow * (((hdpa->nMaxCount - 1) / nGrow) + 1);
433 if (items > hdpa->nMaxCount)
435 void *ptr;
437 if (hdpa->ptrs)
438 ptr = HeapReAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, items * sizeof(LPVOID) );
439 else
440 ptr = HeapAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, items * sizeof(LPVOID) );
441 if (!ptr) return FALSE;
442 hdpa->nMaxCount = items;
443 hdpa->ptrs = ptr;
445 hdpa->nGrow = nGrow;
447 return TRUE;
451 /**************************************************************************
452 * DPA_Clone [COMCTL32.331]
454 * Copies a pointer array to another one or creates a copy
456 * PARAMS
457 * hdpa [I] handle (pointer) to the existing (source) pointer array
458 * hdpaNew [O] handle (pointer) to the destination pointer array
460 * RETURNS
461 * Success: pointer to the destination pointer array.
462 * Failure: NULL
464 * NOTES
465 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
466 * array will be created and its handle (pointer) is returned.
467 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
468 * this implementation just returns NULL.
470 HDPA WINAPI DPA_Clone (const HDPA hdpa, HDPA hdpaNew)
472 INT nNewItems, nSize;
473 HDPA hdpaTemp;
475 if (!hdpa)
476 return NULL;
478 TRACE("(%p %p)\n", hdpa, hdpaNew);
480 if (!hdpaNew) {
481 /* create a new DPA */
482 hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
483 sizeof(*hdpaTemp));
484 hdpaTemp->hHeap = hdpa->hHeap;
485 hdpaTemp->nGrow = hdpa->nGrow;
487 else
488 hdpaTemp = hdpaNew;
490 if (hdpaTemp->ptrs) {
491 /* remove old pointer array */
492 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
493 hdpaTemp->ptrs = NULL;
494 hdpaTemp->nItemCount = 0;
495 hdpaTemp->nMaxCount = 0;
498 /* create a new pointer array */
499 nNewItems = hdpaTemp->nGrow *
500 (((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
501 nSize = nNewItems * sizeof(LPVOID);
502 hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
503 hdpaTemp->nMaxCount = nNewItems;
505 /* clone the pointer array */
506 hdpaTemp->nItemCount = hdpa->nItemCount;
507 memmove (hdpaTemp->ptrs, hdpa->ptrs,
508 hdpaTemp->nItemCount * sizeof(LPVOID));
510 return hdpaTemp;
514 /**************************************************************************
515 * DPA_GetPtr [COMCTL32.332]
517 * Retrieves a pointer from a dynamic pointer array
519 * PARAMS
520 * hdpa [I] handle (pointer) to the pointer array
521 * nIndex [I] array index of the desired pointer
523 * RETURNS
524 * Success: pointer
525 * Failure: NULL
527 LPVOID WINAPI DPA_GetPtr (HDPA hdpa, INT nIndex)
529 TRACE("(%p %d)\n", hdpa, nIndex);
531 if (!hdpa)
532 return NULL;
533 if (!hdpa->ptrs) {
534 WARN("no pointer array.\n");
535 return NULL;
537 if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
538 WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
539 return NULL;
542 TRACE("-- %p\n", hdpa->ptrs[nIndex]);
544 return hdpa->ptrs[nIndex];
548 /**************************************************************************
549 * DPA_GetPtrIndex [COMCTL32.333]
551 * Retrieves the index of the specified pointer
553 * PARAMS
554 * hdpa [I] handle (pointer) to the pointer array
555 * p [I] pointer
557 * RETURNS
558 * Success: index of the specified pointer
559 * Failure: -1
561 INT WINAPI DPA_GetPtrIndex (HDPA hdpa, LPCVOID p)
563 INT i;
565 if (!hdpa || !hdpa->ptrs)
566 return -1;
568 for (i = 0; i < hdpa->nItemCount; i++) {
569 if (hdpa->ptrs[i] == p)
570 return i;
573 return -1;
577 /**************************************************************************
578 * DPA_InsertPtr [COMCTL32.334]
580 * Inserts a pointer into a dynamic pointer array
582 * PARAMS
583 * hdpa [I] handle (pointer) to the array
584 * i [I] array index
585 * p [I] pointer to insert
587 * RETURNS
588 * Success: index of the inserted pointer
589 * Failure: -1
591 INT WINAPI DPA_InsertPtr (HDPA hdpa, INT i, LPVOID p)
593 TRACE("(%p %d %p)\n", hdpa, i, p);
595 if (!hdpa || i < 0) return -1;
597 /* append item if index is out of bounds */
598 i = min(hdpa->nItemCount, i);
600 /* create empty spot at the end */
601 if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
603 if (i != hdpa->nItemCount - 1)
604 memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i,
605 (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
607 hdpa->ptrs[i] = p;
608 return i;
612 /**************************************************************************
613 * DPA_SetPtr [COMCTL32.335]
615 * Sets a pointer in the pointer array
617 * PARAMS
618 * hdpa [I] handle (pointer) to the pointer array
619 * i [I] index of the pointer that will be set
620 * p [I] pointer to be set
622 * RETURNS
623 * Success: TRUE
624 * Failure: FALSE
626 BOOL WINAPI DPA_SetPtr (HDPA hdpa, INT i, LPVOID p)
628 LPVOID *lpTemp;
630 TRACE("(%p %d %p)\n", hdpa, i, p);
632 if (!hdpa || i < 0)
633 return FALSE;
635 if (hdpa->nItemCount <= i) {
636 /* within the old array */
637 if (hdpa->nMaxCount <= i) {
638 /* resize the block of memory */
639 INT nNewItems =
640 hdpa->nGrow * ((((i+1) - 1) / hdpa->nGrow) + 1);
641 INT nSize = nNewItems * sizeof(LPVOID);
643 if (hdpa->ptrs)
644 lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
645 else
646 lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
648 if (!lpTemp)
649 return FALSE;
651 hdpa->nMaxCount = nNewItems;
652 hdpa->ptrs = lpTemp;
654 hdpa->nItemCount = i+1;
657 /* put the new entry in */
658 hdpa->ptrs[i] = p;
660 return TRUE;
664 /**************************************************************************
665 * DPA_DeletePtr [COMCTL32.336]
667 * Removes a pointer from the pointer array.
669 * PARAMS
670 * hdpa [I] handle (pointer) to the pointer array
671 * i [I] index of the pointer that will be deleted
673 * RETURNS
674 * Success: deleted pointer
675 * Failure: NULL
677 LPVOID WINAPI DPA_DeletePtr (HDPA hdpa, INT i)
679 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
680 INT nSize;
682 TRACE("(%p %d)\n", hdpa, i);
684 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
685 return NULL;
687 lpTemp = hdpa->ptrs[i];
689 /* do we need to move ?*/
690 if (i < hdpa->nItemCount - 1) {
691 lpDest = hdpa->ptrs + i;
692 lpSrc = lpDest + 1;
693 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
694 TRACE("-- move dest=%p src=%p size=%x\n",
695 lpDest, lpSrc, nSize);
696 memmove (lpDest, lpSrc, nSize);
699 hdpa->nItemCount --;
701 /* free memory ?*/
702 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
703 INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
704 nSize = nNewItems * sizeof(LPVOID);
705 lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
706 hdpa->ptrs, nSize);
707 if (!lpDest)
708 return NULL;
710 hdpa->nMaxCount = nNewItems;
711 hdpa->ptrs = lpDest;
714 return lpTemp;
718 /**************************************************************************
719 * DPA_DeleteAllPtrs [COMCTL32.337]
721 * Removes all pointers and reinitializes the array.
723 * PARAMS
724 * hdpa [I] handle (pointer) to the pointer array
726 * RETURNS
727 * Success: TRUE
728 * Failure: FALSE
730 BOOL WINAPI DPA_DeleteAllPtrs (HDPA hdpa)
732 TRACE("(%p)\n", hdpa);
734 if (!hdpa)
735 return FALSE;
737 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
738 return FALSE;
740 hdpa->nItemCount = 0;
741 hdpa->nMaxCount = hdpa->nGrow * 2;
742 hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
743 hdpa->nMaxCount * sizeof(LPVOID));
745 return TRUE;
749 /**************************************************************************
750 * DPA_QuickSort [Internal]
752 * Ordinary quicksort (used by DPA_Sort).
754 * PARAMS
755 * lpPtrs [I] pointer to the pointer array
756 * l [I] index of the "left border" of the partition
757 * r [I] index of the "right border" of the partition
758 * pfnCompare [I] pointer to the compare function
759 * lParam [I] user defined value (3rd parameter in compare function)
761 * RETURNS
762 * NONE
764 static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
765 PFNDPACOMPARE pfnCompare, LPARAM lParam)
767 INT m;
768 LPVOID t;
770 TRACE("l=%i r=%i\n", l, r);
772 if (l==r) /* one element is always sorted */
773 return;
774 if (r<l) /* oops, got it in the wrong order */
776 DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
777 return;
779 m = (l+r)/2; /* divide by two */
780 DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
781 DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
783 /* join the two sides */
784 while( (l<=m) && (m<r) )
786 if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
788 t = lpPtrs[m+1];
789 memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
790 lpPtrs[l] = t;
792 m++;
794 l++;
799 /**************************************************************************
800 * DPA_Sort [COMCTL32.338]
802 * Sorts a pointer array using a user defined compare function
804 * PARAMS
805 * hdpa [I] handle (pointer) to the pointer array
806 * pfnCompare [I] pointer to the compare function
807 * lParam [I] user defined value (3rd parameter of compare function)
809 * RETURNS
810 * Success: TRUE
811 * Failure: FALSE
813 BOOL WINAPI DPA_Sort (HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
815 if (!hdpa || !pfnCompare)
816 return FALSE;
818 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
820 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
821 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
822 pfnCompare, lParam);
824 return TRUE;
828 /**************************************************************************
829 * DPA_Search [COMCTL32.339]
831 * Searches a pointer array for a specified pointer
833 * PARAMS
834 * hdpa [I] handle (pointer) to the pointer array
835 * pFind [I] pointer to search for
836 * nStart [I] start index
837 * pfnCompare [I] pointer to the compare function
838 * lParam [I] user defined value (3rd parameter of compare function)
839 * uOptions [I] search options
841 * RETURNS
842 * Success: index of the pointer in the array.
843 * Failure: -1
845 INT WINAPI DPA_Search (HDPA hdpa, LPVOID pFind, INT nStart,
846 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
848 if (!hdpa || !pfnCompare || !pFind)
849 return -1;
851 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
852 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
854 if (uOptions & DPAS_SORTED) {
855 /* array is sorted --> use binary search */
856 INT l, r, x, n;
857 LPVOID *lpPtr;
859 /* for binary search ignore start index */
860 l = 0;
861 r = hdpa->nItemCount - 1;
862 lpPtr = hdpa->ptrs;
863 while (r >= l) {
864 x = (l + r) / 2;
865 n = (pfnCompare)(pFind, lpPtr[x], lParam);
866 if (n == 0)
867 return x;
868 else if (n < 0)
869 r = x - 1;
870 else /* (n > 0) */
871 l = x + 1;
873 if (uOptions & (DPAS_INSERTBEFORE|DPAS_INSERTAFTER)) return l;
875 else {
876 /* array is not sorted --> use linear search */
877 LPVOID *lpPtr;
878 INT nIndex;
880 nIndex = (nStart == -1)? 0 : nStart;
881 lpPtr = hdpa->ptrs;
882 for (; nIndex < hdpa->nItemCount; nIndex++) {
883 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0)
884 return nIndex;
888 return -1;
892 /**************************************************************************
893 * DPA_CreateEx [COMCTL32.340]
895 * Creates a dynamic pointer array using the specified size and heap.
897 * PARAMS
898 * nGrow [I] number of items by which the array grows when it is filled
899 * hHeap [I] handle to the heap where the array is stored
901 * RETURNS
902 * Success: handle (pointer) to the pointer array.
903 * Failure: NULL
905 * NOTES
906 * The DPA_ functions can be used to create and manipulate arrays of
907 * pointers.
909 HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)
911 HDPA hdpa;
913 TRACE("(%d %p)\n", nGrow, hHeap);
915 if (hHeap)
916 hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
917 else
918 hdpa = Alloc (sizeof(*hdpa));
920 if (hdpa) {
921 hdpa->nGrow = max(8, nGrow);
922 hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
923 hdpa->nMaxCount = hdpa->nGrow * 2;
924 hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
925 hdpa->nMaxCount * sizeof(LPVOID));
928 TRACE("-- %p\n", hdpa);
930 return hdpa;
934 /**************************************************************************
935 * DPA_Create [COMCTL32.328]
937 * Creates a dynamic pointer array.
939 * PARAMS
940 * nGrow [I] number of items by which the array grows when it is filled
942 * RETURNS
943 * Success: handle (pointer) to the pointer array.
944 * Failure: NULL
946 * NOTES
947 * The DPA_ functions can be used to create and manipulate arrays of
948 * pointers.
950 HDPA WINAPI DPA_Create (INT nGrow)
952 return DPA_CreateEx( nGrow, 0 );
956 /**************************************************************************
957 * DPA_EnumCallback [COMCTL32.385]
959 * Enumerates all items in a dynamic pointer array.
961 * PARAMS
962 * hdpa [I] handle to the dynamic pointer array
963 * enumProc [I]
964 * lParam [I]
966 * RETURNS
967 * none
969 VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
970 LPVOID lParam)
972 INT i;
974 TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
976 if (!hdpa)
977 return;
978 if (hdpa->nItemCount <= 0)
979 return;
981 for (i = 0; i < hdpa->nItemCount; i++) {
982 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
983 return;
986 return;
990 /**************************************************************************
991 * DPA_DestroyCallback [COMCTL32.386]
993 * Enumerates all items in a dynamic pointer array and destroys it.
995 * PARAMS
996 * hdpa [I] handle to the dynamic pointer array
997 * enumProc [I]
998 * lParam [I]
1000 * RETURNS
1001 * none
1003 void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
1004 LPVOID lParam)
1006 TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
1008 DPA_EnumCallback (hdpa, enumProc, lParam);
1009 DPA_Destroy (hdpa);
1012 /**************************************************************************
1013 * DPA_GetSize [COMCTL32.@]
1015 * Returns all array allocated memory size
1017 * PARAMS
1018 * hdpa [I] handle to the dynamic pointer array
1020 * RETURNS
1021 * Size in bytes
1023 ULONGLONG WINAPI DPA_GetSize(HDPA hdpa)
1025 TRACE("(%p)\n", hdpa);
1027 if (!hdpa) return 0;
1029 return sizeof(DPA) + hdpa->nMaxCount*sizeof(PVOID);