source: trunk/src/comctl32/comctl32undoc.c@ 10367

Last change on this file since 10367 was 10260, checked in by sandervl, 22 years ago

PF: Fixed bug when calling function by pointer in MRU funcs

File size: 66.5 KB
Line 
1/*
2 * Undocumented functions from COMCTL32.DLL
3 *
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
7 *
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.
12 *
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.
17 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * NOTES
23 * All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
24 * Do NOT rely on names or contents of undocumented structures and types!!!
25 * These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
26 * COMCTL32.DLL (internally).
27 *
28 * TODO
29 * - Add more functions.
30 * - Write some documentation.
31 */
32#ifdef __WIN32OS2__
33#define WINE_LARGE_INTEGER
34#endif
35
36#include "config.h"
37#include "wine/port.h"
38
39#include <string.h>
40#include <stdlib.h> /* atoi */
41#include <ctype.h>
42#include <limits.h>
43
44#define NONAMELESSUNION
45#define NONAMELESSSTRUCT
46#include "commctrl.h"
47#include "objbase.h"
48#include "winbase.h"
49#include "winerror.h"
50#include "winreg.h"
51
52#include "wine/unicode.h"
53#include "comctl32.h"
54
55#include "wine/debug.h"
56
57WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
58
59
60extern HANDLE COMCTL32_hHeap; /* handle to the private heap */
61
62
63typedef struct _STREAMDATA
64{
65 DWORD dwSize;
66 DWORD dwData2;
67 DWORD dwItems;
68} STREAMDATA, *PSTREAMDATA;
69
70typedef struct _LOADDATA
71{
72 INT nCount;
73 PVOID ptr;
74} LOADDATA, *LPLOADDATA;
75
76#ifdef __WIN32OS2__
77typedef HRESULT (* CALLBACK DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
78#else
79typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
80#endif
81
82/**************************************************************************
83 * DPA_LoadStream [COMCTL32.9]
84 *
85 * Loads a dynamic pointer array from a stream
86 *
87 * PARAMS
88 * phDpa [O] pointer to a handle to a dynamic pointer array
89 * loadProc [I] pointer to a callback function
90 * pStream [I] pointer to a stream
91 * lParam [I] application specific value
92 *
93 * NOTES
94 * No more information available yet!
95 */
96
97HRESULT WINAPI
98DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
99{
100 HRESULT errCode;
101 LARGE_INTEGER position;
102 ULARGE_INTEGER newPosition;
103 STREAMDATA streamData;
104 LOADDATA loadData;
105 ULONG ulRead;
106 HDPA hDpa;
107 PVOID *ptr;
108
109 FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
110 phDpa, loadProc, pStream, lParam);
111
112 if (!phDpa || !loadProc || !pStream)
113 return E_INVALIDARG;
114
115 *phDpa = (HDPA)NULL;
116
117 position.s.LowPart = 0;
118 position.s.HighPart = 0;
119
120 /*
121 * Zero out our streamData
122 */
123 memset(&streamData,0,sizeof(STREAMDATA));
124
125 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
126 if (errCode != S_OK)
127 return errCode;
128
129 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
130 if (errCode != S_OK)
131 return errCode;
132
133 FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n",
134 streamData.dwSize, streamData.dwData2, streamData.dwItems);
135
136 if ( ulRead < sizeof(STREAMDATA) ||
137 lParam < sizeof(STREAMDATA) ||
138 streamData.dwSize < sizeof(STREAMDATA) ||
139 streamData.dwData2 < 1) {
140 errCode = E_FAIL;
141 }
142
143 if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
144 return E_OUTOFMEMORY;
145
146 /* create the dpa */
147 hDpa = DPA_Create (streamData.dwItems);
148 if (!hDpa)
149 return E_OUTOFMEMORY;
150
151 if (!DPA_Grow (hDpa, streamData.dwItems))
152 return E_OUTOFMEMORY;
153
154 /* load data from the stream into the dpa */
155 ptr = hDpa->ptrs;
156 for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
157 errCode = (loadProc)(&loadData, pStream, lParam);
158 if (errCode != S_OK) {
159 errCode = S_FALSE;
160 break;
161 }
162
163 *ptr = loadData.ptr;
164 ptr++;
165 }
166
167 /* set the number of items */
168 hDpa->nItemCount = loadData.nCount;
169
170 /* store the handle to the dpa */
171 *phDpa = hDpa;
172 FIXME ("new hDpa=%p\n", hDpa);
173
174 return errCode;
175}
176
177
178/**************************************************************************
179 * DPA_SaveStream [COMCTL32.10]
180 *
181 * Saves a dynamic pointer array to a stream
182 *
183 * PARAMS
184 * hDpa [I] handle to a dynamic pointer array
185 * loadProc [I] pointer to a callback function
186 * pStream [I] pointer to a stream
187 * lParam [I] application specific value
188 *
189 * NOTES
190 * No more information available yet!
191 */
192
193HRESULT WINAPI
194DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam)
195{
196
197 FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
198 hDpa, loadProc, pStream, lParam);
199
200 return E_FAIL;
201}
202
203
204/**************************************************************************
205 * DPA_Merge [COMCTL32.11]
206 *
207 * PARAMS
208 * hdpa1 [I] handle to a dynamic pointer array
209 * hdpa2 [I] handle to a dynamic pointer array
210 * dwFlags [I] flags
211 * pfnCompare [I] pointer to sort function
212 * pfnMerge [I] pointer to merge function
213 * lParam [I] application specific value
214 *
215 * NOTES
216 * No more information available yet!
217 */
218
219BOOL WINAPI
220DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
221 PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, LPARAM lParam)
222{
223 INT nCount;
224 LPVOID *pWork1, *pWork2;
225 INT nResult, i;
226 INT nIndex;
227
228 TRACE("%p %p %08lx %p %p %08lx)\n",
229 hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
230
231 if (IsBadWritePtr (hdpa1, sizeof(DPA)))
232 return FALSE;
233
234 if (IsBadWritePtr (hdpa2, sizeof(DPA)))
235 return FALSE;
236
237 if (IsBadCodePtr ((FARPROC)pfnCompare))
238 return FALSE;
239
240 if (IsBadCodePtr ((FARPROC)pfnMerge))
241 return FALSE;
242
243 if (!(dwFlags & DPAM_NOSORT)) {
244 TRACE("sorting dpa's!\n");
245 if (hdpa1->nItemCount > 0)
246 DPA_Sort (hdpa1, pfnCompare, lParam);
247 TRACE ("dpa 1 sorted!\n");
248 if (hdpa2->nItemCount > 0)
249 DPA_Sort (hdpa2, pfnCompare, lParam);
250 TRACE ("dpa 2 sorted!\n");
251 }
252
253 if (hdpa2->nItemCount < 1)
254 return TRUE;
255
256 TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
257 hdpa1->nItemCount, hdpa2->nItemCount);
258
259
260 /* working but untrusted implementation */
261
262 pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
263 pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
264
265 nIndex = hdpa1->nItemCount - 1;
266 nCount = hdpa2->nItemCount - 1;
267
268 do
269 {
270 if (nIndex < 0) {
271 if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) {
272 /* Now insert the remaining new items into DPA 1 */
273 TRACE("%d items to be inserted at start of DPA 1\n",
274 nCount+1);
275 for (i=nCount; i>=0; i--) {
276 PVOID ptr;
277
278 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
279 if (!ptr)
280 return FALSE;
281 DPA_InsertPtr (hdpa1, 0, ptr);
282 pWork2--;
283 }
284 }
285 break;
286 }
287 nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
288 TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
289 nResult, nIndex, nCount);
290
291 if (nResult == 0)
292 {
293 PVOID ptr;
294
295 ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam);
296 if (!ptr)
297 return FALSE;
298
299 nCount--;
300 pWork2--;
301 *pWork1 = ptr;
302 nIndex--;
303 pWork1--;
304 }
305 else if (nResult > 0)
306 {
307 /* item in DPA 1 missing from DPA 2 */
308 if (dwFlags & DPAM_DELETE)
309 {
310 /* Now delete the extra item in DPA1 */
311 PVOID ptr;
312
313 ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
314
315 (pfnMerge)(2, ptr, NULL, lParam);
316 }
317 nIndex--;
318 pWork1--;
319 }
320 else
321 {
322 /* new item in DPA 2 */
323 if (dwFlags & DPAM_INSERT)
324 {
325 /* Now insert the new item in DPA 1 */
326 PVOID ptr;
327
328 ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
329 if (!ptr)
330 return FALSE;
331 DPA_InsertPtr (hdpa1, nIndex+1, ptr);
332 }
333 nCount--;
334 pWork2--;
335 }
336
337 }
338 while (nCount >= 0);
339
340 return TRUE;
341}
342
343
344/**************************************************************************
345 * Alloc [COMCTL32.71]
346 *
347 * Allocates memory block from the dll's private heap
348 *
349 * PARAMS
350 * dwSize [I] size of the allocated memory block
351 *
352 * RETURNS
353 * Success: pointer to allocated memory block
354 * Failure: NULL
355 */
356
357LPVOID WINAPI
358COMCTL32_Alloc (DWORD dwSize)
359{
360 LPVOID lpPtr;
361
362 TRACE("(0x%lx)\n", dwSize);
363
364 lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
365
366 TRACE("-- ret=%p\n", lpPtr);
367
368 return lpPtr;
369}
370
371
372/**************************************************************************
373 * ReAlloc [COMCTL32.72]
374 *
375 * Changes the size of an allocated memory block or allocates a memory
376 * block using the dll's private heap.
377 *
378 * PARAMS
379 * lpSrc [I] pointer to memory block which will be resized
380 * dwSize [I] new size of the memory block.
381 *
382 * RETURNS
383 * Success: pointer to the resized memory block
384 * Failure: NULL
385 *
386 * NOTES
387 * If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
388 * block like COMCTL32_Alloc.
389 */
390
391LPVOID WINAPI
392COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
393{
394 LPVOID lpDest;
395
396 TRACE("(%p 0x%08lx)\n", lpSrc, dwSize);
397
398 if (lpSrc)
399 lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
400 else
401 lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);
402
403 TRACE("-- ret=%p\n", lpDest);
404
405 return lpDest;
406}
407
408
409/**************************************************************************
410 * Free [COMCTL32.73]
411 *
412 * Frees an allocated memory block from the dll's private heap.
413 *
414 * PARAMS
415 * lpMem [I] pointer to memory block which will be freed
416 *
417 * RETURNS
418 * Success: TRUE
419 * Failure: FALSE
420 */
421
422BOOL WINAPI
423COMCTL32_Free (LPVOID lpMem)
424{
425 TRACE("(%p)\n", lpMem);
426
427 return HeapFree (COMCTL32_hHeap, 0, lpMem);
428}
429
430
431/**************************************************************************
432 * GetSize [COMCTL32.74]
433 *
434 * Retrieves the size of the specified memory block from the dll's
435 * private heap.
436 *
437 * PARAMS
438 * lpMem [I] pointer to an allocated memory block
439 *
440 * RETURNS
441 * Success: size of the specified memory block
442 * Failure: 0
443 */
444
445DWORD WINAPI
446COMCTL32_GetSize (LPVOID lpMem)
447{
448 TRACE("(%p)\n", lpMem);
449
450 return HeapSize (COMCTL32_hHeap, 0, lpMem);
451}
452
453
454/**************************************************************************
455 * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
456 * lists.
457 *
458 * Stored in the reg. as a set of values under a single key. Each item in the
459 * list has a value name that is a single char. 'a' - 'z', '{', '|' or '}'.
460 * The order of the list is stored with value name 'MRUList' which is a string
461 * containing the value names (i.e. 'a', 'b', etc.) in the relevant order.
462 */
463
464typedef struct tagCREATEMRULISTA
465{
466 DWORD cbSize; /* size of struct */
467 DWORD nMaxItems; /* max no. of items in list */
468 DWORD dwFlags; /* see below */
469 HKEY hKey; /* root reg. key under which list is saved */
470 LPCSTR lpszSubKey; /* reg. subkey */
471 PROC lpfnCompare; /* item compare proc */
472} CREATEMRULISTA, *LPCREATEMRULISTA;
473
474typedef struct tagCREATEMRULISTW
475{
476 DWORD cbSize; /* size of struct */
477 DWORD nMaxItems; /* max no. of items in list */
478 DWORD dwFlags; /* see below */
479 HKEY hKey; /* root reg. key under which list is saved */
480 LPCWSTR lpszSubKey; /* reg. subkey */
481 PROC lpfnCompare; /* item compare proc */
482} CREATEMRULISTW, *LPCREATEMRULISTW;
483
484/* dwFlags */
485#define MRUF_STRING_LIST 0 /* list will contain strings */
486#define MRUF_BINARY_LIST 1 /* list will contain binary data */
487#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */
488
489/* If list is a string list lpfnCompare has the following prototype
490 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
491 * for binary lists the prototype is
492 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
493 * where cbData is the no. of bytes to compare.
494 * Need to check what return value means identical - 0?
495 */
496
497typedef struct tagWINEMRUITEM
498{
499 DWORD size; /* size of data stored */
500 DWORD itemFlag; /* flags */
501 BYTE datastart;
502} WINEMRUITEM, *LPWINEMRUITEM;
503
504/* itemFlag */
505#define WMRUIF_CHANGED 0x0001 /* this dataitem changed */
506
507typedef struct tagWINEMRULIST
508{
509 CREATEMRULISTW extview; /* original create information */
510 BOOL isUnicode; /* is compare fn Unicode */
511 DWORD wineFlags; /* internal flags */
512 DWORD cursize; /* current size of realMRU */
513 LPSTR realMRU; /* pointer to string of index names */
514 LPWINEMRUITEM *array; /* array of pointers to data */
515 /* in 'a' to 'z' order */
516} WINEMRULIST, *LPWINEMRULIST;
517
518/* wineFlags */
519#define WMRUF_CHANGED 0x0001 /* MRU list has changed */
520
521/**************************************************************************
522 * MRU_SaveChanged - Localize MRU saving code
523 *
524 */
525VOID MRU_SaveChanged( LPWINEMRULIST mp )
526{
527 UINT i, err;
528 HKEY newkey;
529 WCHAR realname[2];
530 LPWINEMRUITEM witem;
531 WCHAR emptyW[] = {'\0'};
532
533 /* or should we do the following instead of RegOpenKeyEx:
534 */
535
536 /* open the sub key */
537 if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
538 0, KEY_WRITE, &newkey))) {
539 /* not present - what to do ??? */
540 ERR("Can not open key, error=%d, attempting to create\n",
541 err);
542 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
543 0,
544 emptyW,
545 REG_OPTION_NON_VOLATILE,
546 KEY_READ | KEY_WRITE,
547 0,
548 &newkey,
549 0))) {
550 ERR("failed to create key /%s/, err=%d\n",
551 debugstr_w(mp->extview.lpszSubKey), err);
552 return;
553 }
554 }
555 if (mp->wineFlags & WMRUF_CHANGED) {
556 mp->wineFlags &= ~WMRUF_CHANGED;
557 err = RegSetValueExA(newkey, "MRUList", 0, REG_SZ,
558 mp->realMRU, strlen(mp->realMRU) + 1);
559 if (err) {
560 ERR("error saving MRUList, err=%d\n", err);
561 }
562 TRACE("saving MRUList=/%s/\n", mp->realMRU);
563 }
564 realname[1] = 0;
565 for(i=0; i<mp->cursize; i++) {
566 witem = mp->array[i];
567 if (witem->itemFlag & WMRUIF_CHANGED) {
568 witem->itemFlag &= ~WMRUIF_CHANGED;
569 realname[0] = 'a' + i;
570 err = RegSetValueExW(newkey, realname, 0,
571 (mp->extview.dwFlags & MRUF_BINARY_LIST) ?
572 REG_BINARY : REG_SZ,
573 &witem->datastart, witem->size);
574 if (err) {
575 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
576 }
577 TRACE("saving value for name /%s/ size=%ld\n",
578 debugstr_w(realname), witem->size);
579 }
580 }
581 RegCloseKey( newkey );
582}
583
584/**************************************************************************
585 * FreeMRUList [COMCTL32.152]
586 *
587 * PARAMS
588 * hMRUList [I] Handle to list.
589 *
590 */
591DWORD WINAPI
592FreeMRUList (HANDLE hMRUList)
593{
594 LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList;
595 UINT i;
596
597 TRACE("\n");
598 if (mp->wineFlags & WMRUF_CHANGED) {
599 /* need to open key and then save the info */
600 MRU_SaveChanged( mp );
601 }
602
603 for(i=0; i<mp->extview.nMaxItems; i++) {
604 if (mp->array[i])
605 COMCTL32_Free(mp->array[i]);
606 }
607 COMCTL32_Free(mp->realMRU);
608 COMCTL32_Free(mp->array);
609 COMCTL32_Free((LPWSTR)mp->extview.lpszSubKey);
610 return COMCTL32_Free(mp);
611}
612
613
614#ifdef __WIN32OS2__
615typedef int (* WIN32API lpComp1)(LPCSTR , LPCSTR );
616typedef int (* WIN32API lpComp2)(LPCVOID, LPCVOID, DWORD);
617#endif
618
619/**************************************************************************
620 * FindMRUData [COMCTL32.169]
621 *
622 * Searches binary list for item that matches lpData of length cbData.
623 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
624 * corresponding to item's reg. name will be stored in it ('a' -> 0).
625 *
626 * PARAMS
627 * hList [I] list handle
628 * lpData [I] data to find
629 * cbData [I] length of data
630 * lpRegNum [O] position in registry (maybe NULL)
631 *
632 * RETURNS
633 * Position in list 0 -> MRU. -1 if item not found.
634 */
635INT WINAPI
636FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum)
637{
638 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
639 UINT i, ret;
640 LPSTR dataA = NULL;
641
642 if (!mp->extview.lpfnCompare) {
643 ERR("MRU list not properly created. No compare procedure.\n");
644 return -1;
645 }
646
647 if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
648 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
649 NULL, 0, NULL, NULL);
650 dataA = COMCTL32_Alloc(len);
651 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
652 }
653
654 for(i=0; i<mp->cursize; i++) {
655 if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
656#ifdef __WIN32OS2__
657 if (!(lpComp2)mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
658#else
659 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
660#endif
661 cbData))
662 break;
663 }
664 else {
665 if(mp->isUnicode) {
666#ifdef __WIN32OS2__
667 if (!((lpComp1)(mp->extview.lpfnCompare))(lpData, &mp->array[i]->datastart))
668#else
669 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
670#endif
671 break;
672 } else {
673 DWORD len = WideCharToMultiByte(CP_ACP, 0,
674 (LPWSTR)&mp->array[i]->datastart, -1,
675 NULL, 0, NULL, NULL);
676 LPSTR itemA = COMCTL32_Alloc(len);
677 INT cmp;
678 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
679 itemA, len, NULL, NULL);
680
681#ifdef __WIN32OS2__
682 cmp = ((lpComp1)(mp->extview.lpfnCompare))(dataA, itemA);
683#else
684 cmp = mp->extview.lpfnCompare(dataA, itemA);
685#endif
686 COMCTL32_Free(itemA);
687 if(!cmp)
688 break;
689 }
690 }
691 }
692 if(dataA)
693 COMCTL32_Free(dataA);
694 if (i < mp->cursize)
695 ret = i;
696 else
697 ret = -1;
698 if (lpRegNum && (ret != -1))
699 *lpRegNum = 'a' + i;
700
701 TRACE("(%p, %p, %ld, %p) returning %d\n",
702 hList, lpData, cbData, lpRegNum, ret);
703
704 return ret;
705}
706
707
708/**************************************************************************
709 * AddMRUData [COMCTL32.167]
710 *
711 * Add item to MRU binary list. If item already exists in list then it is
712 * simply moved up to the top of the list and not added again. If list is
713 * full then the least recently used item is removed to make room.
714 *
715 * PARAMS
716 * hList [I] Handle to list.
717 * lpData [I] ptr to data to add.
718 * cbData [I] no. of bytes of data.
719 *
720 * RETURNS
721 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
722 * -1 on error.
723 */
724INT WINAPI
725AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
726{
727 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
728 LPWINEMRUITEM witem;
729 INT i, replace, ret;
730
731 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) < 0) {
732 /* either add a new entry or replace oldest */
733 if (mp->cursize < mp->extview.nMaxItems) {
734 /* Add in a new item */
735 replace = mp->cursize;
736 mp->cursize++;
737 }
738 else {
739 /* get the oldest entry and replace data */
740 replace = mp->realMRU[mp->cursize - 1] - 'a';
741 COMCTL32_Free(mp->array[replace]);
742 }
743 }
744 else {
745 /* free up the old data */
746 COMCTL32_Free(mp->array[replace]);
747 }
748
749 /* Allocate space for new item and move in the data */
750 mp->array[replace] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(cbData +
751 sizeof(WINEMRUITEM));
752 witem->itemFlag |= WMRUIF_CHANGED;
753 witem->size = cbData;
754 memcpy( &witem->datastart, lpData, cbData);
755
756 /* now rotate MRU list */
757 mp->wineFlags |= WMRUF_CHANGED;
758 for(i=mp->cursize-1; i>=1; i--) {
759 mp->realMRU[i] = mp->realMRU[i-1];
760 }
761 mp->realMRU[0] = replace + 'a';
762 TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n",
763 hList, lpData, cbData, replace+'a');
764 ret = replace;
765
766 if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
767 /* save changed stuff right now */
768 MRU_SaveChanged( mp );
769 }
770
771 return ret;
772}
773
774/**************************************************************************
775 * AddMRUStringW [COMCTL32.401]
776 *
777 * Add item to MRU string list. If item already exists in list them it is
778 * simply moved up to the top of the list and not added again. If list is
779 * full then the least recently used item is removed to make room.
780 *
781 * PARAMS
782 * hList [I] Handle to list.
783 * lpszString [I] ptr to string to add.
784 *
785 * RETURNS
786 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
787 * -1 on error.
788 */
789INT WINAPI
790AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
791{
792 FIXME("(%p, %s) empty stub!\n", hList, debugstr_w(lpszString));
793
794 return 0;
795}
796
797/**************************************************************************
798 * AddMRUStringA [COMCTL32.153]
799 */
800INT WINAPI
801AddMRUStringA(HANDLE hList, LPCSTR lpszString)
802{
803 FIXME("(%p, %s) empty stub!\n", hList, debugstr_a(lpszString));
804
805 return 0;
806}
807
808/**************************************************************************
809 * DelMRUString [COMCTL32.156]
810 *
811 * Removes item from either string or binary list (despite its name)
812 *
813 * PARAMS
814 * hList [I] list handle
815 * nItemPos [I] item position to remove 0 -> MRU
816 *
817 * RETURNS
818 * TRUE if successful, FALSE if nItemPos is out of range.
819 */
820BOOL WINAPI
821DelMRUString(HANDLE hList, INT nItemPos)
822{
823 FIXME("(%p, %d): stub\n", hList, nItemPos);
824 return TRUE;
825}
826
827/**************************************************************************
828 * FindMRUStringW [COMCTL32.402]
829 */
830INT WINAPI
831FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
832{
833 FIXME("stub\n");
834 return -1;
835}
836
837/**************************************************************************
838 * FindMRUStringA [COMCTL32.155]
839 *
840 * Searches string list for item that matches lpszString.
841 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
842 * corresponding to item's reg. name will be stored in it ('a' -> 0).
843 *
844 * PARAMS
845 * hList [I] list handle
846 * lpszString [I] string to find
847 * lpRegNum [O] position in registry (maybe NULL)
848 *
849 * RETURNS
850 * Position in list 0 -> MRU. -1 if item not found.
851 */
852INT WINAPI
853FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
854{
855 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
856 LPWSTR stringW = COMCTL32_Alloc(len * sizeof(WCHAR));
857 INT ret;
858
859 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
860 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
861 COMCTL32_Free(stringW);
862 return ret;
863}
864
865/*************************************************************************
866 * CreateMRUListLazy_common
867 */
868HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
869{
870 UINT i, err;
871 HKEY newkey;
872 DWORD datasize, dwdisp;
873 WCHAR realname[2];
874 LPWINEMRUITEM witem;
875 DWORD type;
876 WCHAR emptyW[] = {'\0'};
877
878 /* get space to save indices that will turn into names
879 * but in order of most to least recently used
880 */
881 mp->realMRU = (LPSTR) COMCTL32_Alloc(mp->extview.nMaxItems + 2);
882
883 /* get space to save pointers to actual data in order of
884 * 'a' to 'z' (0 to n).
885 */
886 mp->array = (LPVOID) COMCTL32_Alloc(mp->extview.nMaxItems *
887 sizeof(LPVOID));
888
889 /* open the sub key */
890 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
891 0,
892 emptyW,
893 REG_OPTION_NON_VOLATILE,
894 KEY_READ | KEY_WRITE,
895 0,
896 &newkey,
897 &dwdisp))) {
898 /* error - what to do ??? */
899 ERR("(%lu %lu %lx %lx \"%s\" %p): Can not open key, error=%d\n",
900 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
901 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
902 mp->extview.lpfnCompare, err);
903 return 0;
904 }
905
906 /* get values from key 'MRUList' */
907 if (newkey) {
908 datasize = mp->extview.nMaxItems + 1;
909 if((err=RegQueryValueExA( newkey, "MRUList", 0, &type, mp->realMRU,
910 &datasize))) {
911 /* not present - set size to 1 (will become 0 later) */
912 datasize = 1;
913 *mp->realMRU = 0;
914 }
915
916 TRACE("MRU list = %s\n", mp->realMRU);
917
918 mp->cursize = datasize - 1;
919 /* datasize now has number of items in the MRUList */
920
921 /* get actual values for each entry */
922 realname[1] = 0;
923 for(i=0; i<mp->cursize; i++) {
924 realname[0] = 'a' + i;
925 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
926 /* not present - what to do ??? */
927 ERR("Key %s not found 1\n", debugstr_w(realname));
928 }
929 mp->array[i] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(datasize +
930 sizeof(WINEMRUITEM));
931 witem->size = datasize;
932 if(RegQueryValueExW( newkey, realname, 0, &type,
933 &witem->datastart, &datasize)) {
934 /* not present - what to do ??? */
935 ERR("Key %s not found 2\n", debugstr_w(realname));
936 }
937 }
938 RegCloseKey( newkey );
939 }
940 else
941 mp->cursize = 0;
942
943 TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n",
944 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
945 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
946 mp->extview.lpfnCompare, mp->cursize);
947 return (HANDLE)mp;
948}
949
950/**************************************************************************
951 * CreateMRUListLazyW [COMCTL32.404]
952 */
953HANDLE WINAPI
954CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
955{
956 LPWINEMRULIST mp;
957
958 if (lpcml == NULL)
959 return 0;
960
961 if (lpcml->cbSize < sizeof(CREATEMRULISTW))
962 return 0;
963
964 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
965 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
966 mp->extview.lpszSubKey = COMCTL32_Alloc((strlenW(lpcml->lpszSubKey) + 1) *
967 sizeof(WCHAR));
968 strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
969 mp->isUnicode = TRUE;
970
971 return CreateMRUListLazy_common(mp);
972}
973
974/**************************************************************************
975 * CreateMRUListLazyA [COMCTL32.157]
976 */
977HANDLE WINAPI
978CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
979{
980 LPWINEMRULIST mp;
981 DWORD len;
982
983 if (lpcml == NULL)
984 return 0;
985
986 if (lpcml->cbSize < sizeof(CREATEMRULISTA))
987 return 0;
988
989 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
990 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
991 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
992 mp->extview.lpszSubKey = COMCTL32_Alloc(len * sizeof(WCHAR));
993 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
994 (LPWSTR)mp->extview.lpszSubKey, len);
995 mp->isUnicode = FALSE;
996 return CreateMRUListLazy_common(mp);
997}
998
999/**************************************************************************
1000 * CreateMRUListW [COMCTL32.400]
1001 *
1002 * PARAMS
1003 * lpcml [I] ptr to CREATEMRULIST structure.
1004 *
1005 * RETURNS
1006 * Handle to MRU list.
1007 */
1008HANDLE WINAPI
1009CreateMRUListW (LPCREATEMRULISTW lpcml)
1010{
1011 return CreateMRUListLazyW(lpcml, 0, 0, 0);
1012}
1013
1014/**************************************************************************
1015 * CreateMRUListA [COMCTL32.151]
1016 */
1017HANDLE WINAPI
1018CreateMRUListA (LPCREATEMRULISTA lpcml)
1019{
1020 return CreateMRUListLazyA (lpcml, 0, 0, 0);
1021}
1022
1023
1024/**************************************************************************
1025 * EnumMRUListW [COMCTL32.403]
1026 *
1027 * Enumerate item in a list
1028 *
1029 * PARAMS
1030 * hList [I] list handle
1031 * nItemPos [I] item position to enumerate
1032 * lpBuffer [O] buffer to receive item
1033 * nBufferSize [I] size of buffer
1034 *
1035 * RETURNS
1036 * For binary lists specifies how many bytes were copied to buffer, for
1037 * string lists specifies full length of string. Enumerating past the end
1038 * of list returns -1.
1039 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
1040 * the list.
1041 */
1042INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1043DWORD nBufferSize)
1044{
1045 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1046 LPWINEMRUITEM witem;
1047 INT desired, datasize;
1048
1049 if (nItemPos >= mp->cursize) return -1;
1050 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1051 desired = mp->realMRU[nItemPos];
1052 desired -= 'a';
1053 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1054 witem = mp->array[desired];
1055 datasize = min( witem->size, nBufferSize );
1056 memcpy( lpBuffer, &witem->datastart, datasize);
1057 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1058 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1059 return datasize;
1060}
1061
1062/**************************************************************************
1063 * EnumMRUListA [COMCTL32.154]
1064 *
1065 */
1066INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1067DWORD nBufferSize)
1068{
1069 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1070 LPWINEMRUITEM witem;
1071 INT desired, datasize;
1072 DWORD lenA;
1073
1074 if (nItemPos >= mp->cursize) return -1;
1075 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1076 desired = mp->realMRU[nItemPos];
1077 desired -= 'a';
1078 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1079 witem = mp->array[desired];
1080 if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
1081 datasize = min( witem->size, nBufferSize );
1082 memcpy( lpBuffer, &witem->datastart, datasize);
1083 } else {
1084 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1085 NULL, 0, NULL, NULL);
1086 datasize = min( witem->size, nBufferSize );
1087 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1088 lpBuffer, datasize, NULL, NULL);
1089 }
1090 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1091 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1092 return datasize;
1093}
1094
1095
1096/**************************************************************************
1097 * Str_GetPtrA [COMCTL32.233]
1098 *
1099 * PARAMS
1100 * lpSrc [I]
1101 * lpDest [O]
1102 * nMaxLen [I]
1103 *
1104 * RETURNS
1105 */
1106
1107INT WINAPI
1108Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1109{
1110 INT len;
1111
1112 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1113
1114 if (!lpDest && lpSrc)
1115 return strlen (lpSrc);
1116
1117 if (nMaxLen == 0)
1118 return 0;
1119
1120 if (lpSrc == NULL) {
1121 lpDest[0] = '\0';
1122 return 0;
1123 }
1124
1125 len = strlen (lpSrc);
1126 if (len >= nMaxLen)
1127 len = nMaxLen - 1;
1128
1129 RtlMoveMemory (lpDest, lpSrc, len);
1130 lpDest[len] = '\0';
1131
1132 return len;
1133}
1134
1135
1136/**************************************************************************
1137 * Str_SetPtrA [COMCTL32.234]
1138 *
1139 * PARAMS
1140 * lppDest [O]
1141 * lpSrc [I]
1142 *
1143 * RETURNS
1144 */
1145
1146BOOL WINAPI
1147Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
1148{
1149 TRACE("(%p %p)\n", lppDest, lpSrc);
1150
1151 if (lpSrc) {
1152 LPSTR ptr = COMCTL32_ReAlloc (*lppDest, strlen (lpSrc) + 1);
1153 if (!ptr)
1154 return FALSE;
1155 strcpy (ptr, lpSrc);
1156 *lppDest = ptr;
1157 }
1158 else {
1159 if (*lppDest) {
1160 COMCTL32_Free (*lppDest);
1161 *lppDest = NULL;
1162 }
1163 }
1164
1165 return TRUE;
1166}
1167
1168
1169/**************************************************************************
1170 * Str_GetPtrW [COMCTL32.235]
1171 *
1172 * PARAMS
1173 * lpSrc [I]
1174 * lpDest [O]
1175 * nMaxLen [I]
1176 *
1177 * RETURNS
1178 */
1179
1180INT WINAPI
1181Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
1182{
1183 INT len;
1184
1185 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1186
1187 if (!lpDest && lpSrc)
1188 return strlenW (lpSrc);
1189
1190 if (nMaxLen == 0)
1191 return 0;
1192
1193 if (lpSrc == NULL) {
1194 lpDest[0] = L'\0';
1195 return 0;
1196 }
1197
1198 len = strlenW (lpSrc);
1199 if (len >= nMaxLen)
1200 len = nMaxLen - 1;
1201
1202 RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
1203 lpDest[len] = L'\0';
1204
1205 return len;
1206}
1207
1208
1209/**************************************************************************
1210 * Str_SetPtrW [COMCTL32.236]
1211 *
1212 * PARAMS
1213 * lpDest [O]
1214 * lpSrc [I]
1215 *
1216 * RETURNS
1217 */
1218
1219BOOL WINAPI
1220Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
1221{
1222 TRACE("(%p %p)\n", lppDest, lpSrc);
1223
1224 if (lpSrc) {
1225 INT len = strlenW (lpSrc) + 1;
1226 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
1227 if (!ptr)
1228 return FALSE;
1229 strcpyW (ptr, lpSrc);
1230 *lppDest = ptr;
1231 }
1232 else {
1233 if (*lppDest) {
1234 COMCTL32_Free (*lppDest);
1235 *lppDest = NULL;
1236 }
1237 }
1238
1239 return TRUE;
1240}
1241
1242
1243/**************************************************************************
1244 * Str_GetPtrWtoA [internal]
1245 *
1246 * Converts a unicode string into a multi byte string
1247 *
1248 * PARAMS
1249 * lpSrc [I] Pointer to the unicode source string
1250 * lpDest [O] Pointer to caller supplied storage for the multi byte string
1251 * nMaxLen [I] Size, in bytes, of the destination buffer
1252 *
1253 * RETURNS
1254 * Length, in bytes, of the converted string.
1255 */
1256
1257INT
1258Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1259{
1260 INT len;
1261
1262 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
1263
1264 if (!lpDest && lpSrc)
1265 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1266
1267 if (nMaxLen == 0)
1268 return 0;
1269
1270 if (lpSrc == NULL) {
1271 lpDest[0] = '\0';
1272 return 0;
1273 }
1274
1275 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1276 if (len >= nMaxLen)
1277 len = nMaxLen - 1;
1278
1279 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
1280 lpDest[len] = '\0';
1281
1282 return len;
1283}
1284
1285
1286/**************************************************************************
1287 * Str_SetPtrAtoW [internal]
1288 *
1289 * Converts a multi byte string to a unicode string.
1290 * If the pointer to the destination buffer is NULL a buffer is allocated.
1291 * If the destination buffer is too small to keep the converted multi byte
1292 * string the destination buffer is reallocated. If the source pointer is
1293 * NULL, the destination buffer is freed.
1294 *
1295 * PARAMS
1296 * lppDest [I/O] pointer to a pointer to the destination buffer
1297 * lpSrc [I] pointer to a multi byte string
1298 *
1299 * RETURNS
1300 * TRUE: conversion successful
1301 * FALSE: error
1302 */
1303
1304BOOL
1305Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1306{
1307 TRACE("(%p %s)\n", lppDest, lpSrc);
1308
1309 if (lpSrc) {
1310 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1311 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len*sizeof(WCHAR));
1312
1313 if (!ptr)
1314 return FALSE;
1315 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
1316 *lppDest = ptr;
1317 }
1318 else {
1319 if (*lppDest) {
1320 COMCTL32_Free (*lppDest);
1321 *lppDest = NULL;
1322 }
1323 }
1324
1325 return TRUE;
1326}
1327
1328
1329/**************************************************************************
1330 * The DSA-API is a set of functions to create and manipulate arrays of
1331 * fixed-size memory blocks. These arrays can store any kind of data
1332 * (strings, icons...).
1333 */
1334
1335/**************************************************************************
1336 * DSA_Create [COMCTL32.320] Creates a dynamic storage array
1337 *
1338 * PARAMS
1339 * nSize [I] size of the array elements
1340 * nGrow [I] number of elements by which the array grows when it is filled
1341 *
1342 * RETURNS
1343 * Success: pointer to an array control structure. Use this like a handle.
1344 * Failure: NULL
1345 */
1346
1347HDSA WINAPI
1348DSA_Create (INT nSize, INT nGrow)
1349{
1350 HDSA hdsa;
1351
1352 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
1353
1354 hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
1355 if (hdsa)
1356 {
1357 hdsa->nItemCount = 0;
1358 hdsa->pData = NULL;
1359 hdsa->nMaxCount = 0;
1360 hdsa->nItemSize = nSize;
1361 hdsa->nGrow = max(1, nGrow);
1362 }
1363
1364 return hdsa;
1365}
1366
1367
1368/**************************************************************************
1369 * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
1370 *
1371 * PARAMS
1372 * hdsa [I] pointer to the array control structure
1373 *
1374 * RETURNS
1375 * Success: TRUE
1376 * Failure: FALSE
1377 */
1378
1379BOOL WINAPI
1380DSA_Destroy (const HDSA hdsa)
1381{
1382 TRACE("(%p)\n", hdsa);
1383
1384 if (!hdsa)
1385 return FALSE;
1386
1387 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1388 return FALSE;
1389
1390 return COMCTL32_Free (hdsa);
1391}
1392
1393
1394/**************************************************************************
1395 * DSA_GetItem [COMCTL32.322]
1396 *
1397 * PARAMS
1398 * hdsa [I] pointer to the array control structure
1399 * nIndex [I] number of the Item to get
1400 * pDest [O] destination buffer. Has to be >= dwElementSize.
1401 *
1402 * RETURNS
1403 * Success: TRUE
1404 * Failure: FALSE
1405 */
1406
1407BOOL WINAPI
1408DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
1409{
1410 LPVOID pSrc;
1411
1412 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
1413
1414 if (!hdsa)
1415 return FALSE;
1416 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1417 return FALSE;
1418
1419 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1420 memmove (pDest, pSrc, hdsa->nItemSize);
1421
1422 return TRUE;
1423}
1424
1425
1426/**************************************************************************
1427 * DSA_GetItemPtr [COMCTL32.323]
1428 *
1429 * Retrieves a pointer to the specified item.
1430 *
1431 * PARAMS
1432 * hdsa [I] pointer to the array control structure
1433 * nIndex [I] index of the desired item
1434 *
1435 * RETURNS
1436 * Success: pointer to an item
1437 * Failure: NULL
1438 */
1439
1440LPVOID WINAPI
1441DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1442{
1443 LPVOID pSrc;
1444
1445 TRACE("(%p %d)\n", hdsa, nIndex);
1446
1447 if (!hdsa)
1448 return NULL;
1449 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1450 return NULL;
1451
1452 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1453
1454 TRACE("-- ret=%p\n", pSrc);
1455
1456 return pSrc;
1457}
1458
1459
1460/**************************************************************************
1461 * DSA_SetItem [COMCTL32.325]
1462 *
1463 * Sets the contents of an item in the array.
1464 *
1465 * PARAMS
1466 * hdsa [I] pointer to the array control structure
1467 * nIndex [I] index for the item
1468 * pSrc [I] pointer to the new item data
1469 *
1470 * RETURNS
1471 * Success: TRUE
1472 * Failure: FALSE
1473 */
1474
1475BOOL WINAPI
1476DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1477{
1478 INT nSize, nNewItems;
1479 LPVOID pDest, lpTemp;
1480
1481 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1482
1483 if ((!hdsa) || nIndex < 0)
1484 return FALSE;
1485
1486 if (hdsa->nItemCount <= nIndex) {
1487 /* within the old array */
1488 if (hdsa->nMaxCount > nIndex) {
1489 /* within the allocated space, set a new boundary */
1490 hdsa->nItemCount = nIndex + 1;
1491 }
1492 else {
1493 /* resize the block of memory */
1494 nNewItems =
1495 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1496 nSize = hdsa->nItemSize * nNewItems;
1497
1498 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1499 if (!lpTemp)
1500 return FALSE;
1501
1502 hdsa->nMaxCount = nNewItems;
1503 hdsa->nItemCount = nIndex + 1;
1504 hdsa->pData = lpTemp;
1505 }
1506 }
1507
1508 /* put the new entry in */
1509 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1510 TRACE("-- move dest=%p src=%p size=%d\n",
1511 pDest, pSrc, hdsa->nItemSize);
1512 memmove (pDest, pSrc, hdsa->nItemSize);
1513
1514 return TRUE;
1515}
1516
1517
1518/**************************************************************************
1519 * DSA_InsertItem [COMCTL32.324]
1520 *
1521 * PARAMS
1522 * hdsa [I] pointer to the array control structure
1523 * nIndex [I] index for the new item
1524 * pSrc [I] pointer to the element
1525 *
1526 * RETURNS
1527 * Success: position of the new item
1528 * Failure: -1
1529 */
1530
1531INT WINAPI
1532DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1533{
1534 INT nNewItems, nSize;
1535 LPVOID lpTemp, lpDest;
1536
1537 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1538
1539 if ((!hdsa) || nIndex < 0)
1540 return -1;
1541
1542 /* when nIndex >= nItemCount then append */
1543 if (nIndex >= hdsa->nItemCount)
1544 nIndex = hdsa->nItemCount;
1545
1546 /* do we need to resize ? */
1547 if (hdsa->nItemCount >= hdsa->nMaxCount) {
1548 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1549 nSize = hdsa->nItemSize * nNewItems;
1550
1551 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1552 if (!lpTemp)
1553 return -1;
1554
1555 hdsa->nMaxCount = nNewItems;
1556 hdsa->pData = lpTemp;
1557 }
1558
1559 /* do we need to move elements ? */
1560 if (nIndex < hdsa->nItemCount) {
1561 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1562 lpDest = (char *) lpTemp + hdsa->nItemSize;
1563 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1564 TRACE("-- move dest=%p src=%p size=%d\n",
1565 lpDest, lpTemp, nSize);
1566 memmove (lpDest, lpTemp, nSize);
1567 }
1568
1569 /* ok, we can put the new Item in */
1570 hdsa->nItemCount++;
1571 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1572 TRACE("-- move dest=%p src=%p size=%d\n",
1573 lpDest, pSrc, hdsa->nItemSize);
1574 memmove (lpDest, pSrc, hdsa->nItemSize);
1575
1576 return nIndex;
1577}
1578
1579
1580/**************************************************************************
1581 * DSA_DeleteItem [COMCTL32.326]
1582 *
1583 * PARAMS
1584 * hdsa [I] pointer to the array control structure
1585 * nIndex [I] index for the element to delete
1586 *
1587 * RETURNS
1588 * Success: number of the deleted element
1589 * Failure: -1
1590 */
1591
1592INT WINAPI
1593DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1594{
1595 LPVOID lpDest,lpSrc;
1596 INT nSize;
1597
1598 TRACE("(%p %d)\n", hdsa, nIndex);
1599
1600 if (!hdsa)
1601 return -1;
1602 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1603 return -1;
1604
1605 /* do we need to move ? */
1606 if (nIndex < hdsa->nItemCount - 1) {
1607 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1608 lpSrc = (char *) lpDest + hdsa->nItemSize;
1609 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1610 TRACE("-- move dest=%p src=%p size=%d\n",
1611 lpDest, lpSrc, nSize);
1612 memmove (lpDest, lpSrc, nSize);
1613 }
1614
1615 hdsa->nItemCount--;
1616
1617 /* free memory ? */
1618 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1619 nSize = hdsa->nItemSize * hdsa->nItemCount;
1620
1621 lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1622 if (!lpDest)
1623 return -1;
1624
1625 hdsa->nMaxCount = hdsa->nItemCount;
1626 hdsa->pData = lpDest;
1627 }
1628
1629 return nIndex;
1630}
1631
1632
1633/**************************************************************************
1634 * DSA_DeleteAllItems [COMCTL32.327]
1635 *
1636 * Removes all items and reinitializes the array.
1637 *
1638 * PARAMS
1639 * hdsa [I] pointer to the array control structure
1640 *
1641 * RETURNS
1642 * Success: TRUE
1643 * Failure: FALSE
1644 */
1645
1646BOOL WINAPI
1647DSA_DeleteAllItems (const HDSA hdsa)
1648{
1649 TRACE("(%p)\n", hdsa);
1650
1651 if (!hdsa)
1652 return FALSE;
1653 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1654 return FALSE;
1655
1656 hdsa->nItemCount = 0;
1657 hdsa->pData = NULL;
1658 hdsa->nMaxCount = 0;
1659
1660 return TRUE;
1661}
1662
1663
1664/**************************************************************************
1665 * The DPA-API is a set of functions to create and manipulate arrays of
1666 * pointers.
1667 */
1668
1669/**************************************************************************
1670 * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1671 *
1672 * PARAMS
1673 * nGrow [I] number of items by which the array grows when it is filled
1674 *
1675 * RETURNS
1676 * Success: handle (pointer) to the pointer array.
1677 * Failure: NULL
1678 */
1679
1680HDPA WINAPI
1681DPA_Create (INT nGrow)
1682{
1683 HDPA hdpa;
1684
1685 TRACE("(%d)\n", nGrow);
1686
1687 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1688 if (hdpa) {
1689 hdpa->nGrow = max(8, nGrow);
1690 hdpa->hHeap = COMCTL32_hHeap;
1691 hdpa->nMaxCount = hdpa->nGrow * 2;
1692 hdpa->ptrs =
1693 (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1694 }
1695
1696 TRACE("-- %p\n", hdpa);
1697
1698 return hdpa;
1699}
1700
1701
1702/**************************************************************************
1703 * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1704 *
1705 * PARAMS
1706 * hdpa [I] handle (pointer) to the pointer array
1707 *
1708 * RETURNS
1709 * Success: TRUE
1710 * Failure: FALSE
1711 */
1712
1713BOOL WINAPI
1714DPA_Destroy (const HDPA hdpa)
1715{
1716 TRACE("(%p)\n", hdpa);
1717
1718 if (!hdpa)
1719 return FALSE;
1720
1721 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1722 return FALSE;
1723
1724 return HeapFree (hdpa->hHeap, 0, hdpa);
1725}
1726
1727
1728/**************************************************************************
1729 * DPA_Grow [COMCTL32.330]
1730 *
1731 * Sets the growth amount.
1732 *
1733 * PARAMS
1734 * hdpa [I] handle (pointer) to the existing (source) pointer array
1735 * nGrow [I] number of items by which the array grows when it's too small
1736 *
1737 * RETURNS
1738 * Success: TRUE
1739 * Failure: FALSE
1740 */
1741
1742BOOL WINAPI
1743DPA_Grow (const HDPA hdpa, INT nGrow)
1744{
1745 TRACE("(%p %d)\n", hdpa, nGrow);
1746
1747 if (!hdpa)
1748 return FALSE;
1749
1750 hdpa->nGrow = max(8, nGrow);
1751
1752 return TRUE;
1753}
1754
1755
1756/**************************************************************************
1757 * DPA_Clone [COMCTL32.331]
1758 *
1759 * Copies a pointer array to an other one or creates a copy
1760 *
1761 * PARAMS
1762 * hdpa [I] handle (pointer) to the existing (source) pointer array
1763 * hdpaNew [O] handle (pointer) to the destination pointer array
1764 *
1765 * RETURNS
1766 * Success: pointer to the destination pointer array.
1767 * Failure: NULL
1768 *
1769 * NOTES
1770 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1771 * array will be created and it's handle (pointer) is returned.
1772 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1773 * this implementation just returns NULL.
1774 */
1775
1776HDPA WINAPI
1777DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1778{
1779 INT nNewItems, nSize;
1780 HDPA hdpaTemp;
1781
1782 if (!hdpa)
1783 return NULL;
1784
1785 TRACE("(%p %p)\n", hdpa, hdpaNew);
1786
1787 if (!hdpaNew) {
1788 /* create a new DPA */
1789 hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1790 sizeof(DPA));
1791 hdpaTemp->hHeap = hdpa->hHeap;
1792 hdpaTemp->nGrow = hdpa->nGrow;
1793 }
1794 else
1795 hdpaTemp = hdpaNew;
1796
1797 if (hdpaTemp->ptrs) {
1798 /* remove old pointer array */
1799 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1800 hdpaTemp->ptrs = NULL;
1801 hdpaTemp->nItemCount = 0;
1802 hdpaTemp->nMaxCount = 0;
1803 }
1804
1805 /* create a new pointer array */
1806 nNewItems = hdpaTemp->nGrow *
1807 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1808 nSize = nNewItems * sizeof(LPVOID);
1809 hdpaTemp->ptrs =
1810 (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1811 hdpaTemp->nMaxCount = nNewItems;
1812
1813 /* clone the pointer array */
1814 hdpaTemp->nItemCount = hdpa->nItemCount;
1815 memmove (hdpaTemp->ptrs, hdpa->ptrs,
1816 hdpaTemp->nItemCount * sizeof(LPVOID));
1817
1818 return hdpaTemp;
1819}
1820
1821
1822/**************************************************************************
1823 * DPA_GetPtr [COMCTL32.332]
1824 *
1825 * Retrieves a pointer from a dynamic pointer array
1826 *
1827 * PARAMS
1828 * hdpa [I] handle (pointer) to the pointer array
1829 * nIndex [I] array index of the desired pointer
1830 *
1831 * RETURNS
1832 * Success: pointer
1833 * Failure: NULL
1834 */
1835
1836LPVOID WINAPI
1837DPA_GetPtr (const HDPA hdpa, INT nIndex)
1838{
1839 TRACE("(%p %d)\n", hdpa, nIndex);
1840
1841 if (!hdpa)
1842 return NULL;
1843 if (!hdpa->ptrs) {
1844 WARN("no pointer array.\n");
1845 return NULL;
1846 }
1847 if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
1848 WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
1849 return NULL;
1850 }
1851
1852 TRACE("-- %p\n", hdpa->ptrs[nIndex]);
1853
1854 return hdpa->ptrs[nIndex];
1855}
1856
1857
1858/**************************************************************************
1859 * DPA_GetPtrIndex [COMCTL32.333]
1860 *
1861 * Retrieves the index of the specified pointer
1862 *
1863 * PARAMS
1864 * hdpa [I] handle (pointer) to the pointer array
1865 * p [I] pointer
1866 *
1867 * RETURNS
1868 * Success: index of the specified pointer
1869 * Failure: -1
1870 */
1871
1872INT WINAPI
1873DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1874{
1875 INT i;
1876
1877 if (!hdpa || !hdpa->ptrs)
1878 return -1;
1879
1880 for (i = 0; i < hdpa->nItemCount; i++) {
1881 if (hdpa->ptrs[i] == p)
1882 return i;
1883 }
1884
1885 return -1;
1886}
1887
1888
1889/**************************************************************************
1890 * DPA_InsertPtr [COMCTL32.334]
1891 *
1892 * Inserts a pointer into a dynamic pointer array
1893 *
1894 * PARAMS
1895 * hdpa [I] handle (pointer) to the array
1896 * i [I] array index
1897 * p [I] pointer to insert
1898 *
1899 * RETURNS
1900 * Success: index of the inserted pointer
1901 * Failure: -1
1902 */
1903
1904INT WINAPI
1905DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1906{
1907 TRACE("(%p %d %p)\n", hdpa, i, p);
1908
1909 if (!hdpa || i < 0) return -1;
1910
1911 if (i >= 0x7fff)
1912 i = hdpa->nItemCount;
1913
1914 if (i >= hdpa->nItemCount)
1915 return DPA_SetPtr(hdpa, i, p) ? i : -1;
1916
1917 /* create empty spot at the end */
1918 if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
1919 memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
1920 hdpa->ptrs[i] = p;
1921 return i;
1922}
1923
1924/**************************************************************************
1925 * DPA_SetPtr [COMCTL32.335]
1926 *
1927 * Sets a pointer in the pointer array
1928 *
1929 * PARAMS
1930 * hdpa [I] handle (pointer) to the pointer array
1931 * i [I] index of the pointer that will be set
1932 * p [I] pointer to be set
1933 *
1934 * RETURNS
1935 * Success: TRUE
1936 * Failure: FALSE
1937 */
1938
1939BOOL WINAPI
1940DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1941{
1942 LPVOID *lpTemp;
1943
1944 TRACE("(%p %d %p)\n", hdpa, i, p);
1945
1946 if (!hdpa || i < 0 || i > 0x7fff)
1947 return FALSE;
1948
1949 if (hdpa->nItemCount <= i) {
1950 /* within the old array */
1951 if (hdpa->nMaxCount <= i) {
1952 /* resize the block of memory */
1953 INT nNewItems =
1954 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1955 INT nSize = nNewItems * sizeof(LPVOID);
1956
1957 if (hdpa->ptrs)
1958 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
1959 else
1960 lpTemp = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
1961
1962 if (!lpTemp)
1963 return FALSE;
1964
1965 hdpa->nMaxCount = nNewItems;
1966 hdpa->ptrs = lpTemp;
1967 }
1968 hdpa->nItemCount = i+1;
1969 }
1970
1971 /* put the new entry in */
1972 hdpa->ptrs[i] = p;
1973
1974 return TRUE;
1975}
1976
1977
1978/**************************************************************************
1979 * DPA_DeletePtr [COMCTL32.336]
1980 *
1981 * Removes a pointer from the pointer array.
1982 *
1983 * PARAMS
1984 * hdpa [I] handle (pointer) to the pointer array
1985 * i [I] index of the pointer that will be deleted
1986 *
1987 * RETURNS
1988 * Success: deleted pointer
1989 * Failure: NULL
1990 */
1991
1992LPVOID WINAPI
1993DPA_DeletePtr (const HDPA hdpa, INT i)
1994{
1995 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1996 INT nSize;
1997
1998 TRACE("(%p %d)\n", hdpa, i);
1999
2000 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
2001 return NULL;
2002
2003 lpTemp = hdpa->ptrs[i];
2004
2005 /* do we need to move ?*/
2006 if (i < hdpa->nItemCount - 1) {
2007 lpDest = hdpa->ptrs + i;
2008 lpSrc = lpDest + 1;
2009 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
2010 TRACE("-- move dest=%p src=%p size=%x\n",
2011 lpDest, lpSrc, nSize);
2012 memmove (lpDest, lpSrc, nSize);
2013 }
2014
2015 hdpa->nItemCount --;
2016
2017 /* free memory ?*/
2018 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
2019 INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
2020 nSize = nNewItems * sizeof(LPVOID);
2021 lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2022 hdpa->ptrs, nSize);
2023 if (!lpDest)
2024 return NULL;
2025
2026 hdpa->nMaxCount = nNewItems;
2027 hdpa->ptrs = (LPVOID*)lpDest;
2028 }
2029
2030 return lpTemp;
2031}
2032
2033
2034/**************************************************************************
2035 * DPA_DeleteAllPtrs [COMCTL32.337]
2036 *
2037 * Removes all pointers and reinitializes the array.
2038 *
2039 * PARAMS
2040 * hdpa [I] handle (pointer) to the pointer array
2041 *
2042 * RETURNS
2043 * Success: TRUE
2044 * Failure: FALSE
2045 */
2046
2047BOOL WINAPI
2048DPA_DeleteAllPtrs (const HDPA hdpa)
2049{
2050 TRACE("(%p)\n", hdpa);
2051
2052 if (!hdpa)
2053 return FALSE;
2054
2055 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2056 return FALSE;
2057
2058 hdpa->nItemCount = 0;
2059 hdpa->nMaxCount = hdpa->nGrow * 2;
2060 hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2061 hdpa->nMaxCount * sizeof(LPVOID));
2062
2063 return TRUE;
2064}
2065
2066
2067/**************************************************************************
2068 * DPA_QuickSort [Internal]
2069 *
2070 * Ordinary quicksort (used by DPA_Sort).
2071 *
2072 * PARAMS
2073 * lpPtrs [I] pointer to the pointer array
2074 * l [I] index of the "left border" of the partition
2075 * r [I] index of the "right border" of the partition
2076 * pfnCompare [I] pointer to the compare function
2077 * lParam [I] user defined value (3rd parameter in compare function)
2078 *
2079 * RETURNS
2080 * NONE
2081 */
2082
2083static VOID
2084DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2085 PFNDPACOMPARE pfnCompare, LPARAM lParam)
2086{
2087 INT m;
2088 LPVOID t;
2089
2090 TRACE("l=%i r=%i\n", l, r);
2091
2092 if (l==r) /* one element is always sorted */
2093 return;
2094 if (r<l) /* oops, got it in the wrong order */
2095 {
2096 DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2097 return;
2098 }
2099 m = (l+r)/2; /* divide by two */
2100 DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2101 DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2102
2103 /* join the two sides */
2104 while( (l<=m) && (m<r) )
2105 {
2106 if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2107 {
2108 t = lpPtrs[m+1];
2109 memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof lpPtrs[l]);
2110 lpPtrs[l] = t;
2111
2112 m++;
2113 }
2114 l++;
2115 }
2116}
2117
2118
2119/**************************************************************************
2120 * DPA_Sort [COMCTL32.338]
2121 *
2122 * Sorts a pointer array using a user defined compare function
2123 *
2124 * PARAMS
2125 * hdpa [I] handle (pointer) to the pointer array
2126 * pfnCompare [I] pointer to the compare function
2127 * lParam [I] user defined value (3rd parameter of compare function)
2128 *
2129 * RETURNS
2130 * Success: TRUE
2131 * Failure: FALSE
2132 */
2133
2134BOOL WINAPI
2135DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2136{
2137 if (!hdpa || !pfnCompare)
2138 return FALSE;
2139
2140 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2141
2142 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2143 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2144 pfnCompare, lParam);
2145
2146 return TRUE;
2147}
2148
2149
2150/**************************************************************************
2151 * DPA_Search [COMCTL32.339]
2152 *
2153 * Searches a pointer array for a specified pointer
2154 *
2155 * PARAMS
2156 * hdpa [I] handle (pointer) to the pointer array
2157 * pFind [I] pointer to search for
2158 * nStart [I] start index
2159 * pfnCompare [I] pointer to the compare function
2160 * lParam [I] user defined value (3rd parameter of compare function)
2161 * uOptions [I] search options
2162 *
2163 * RETURNS
2164 * Success: index of the pointer in the array.
2165 * Failure: -1
2166 *
2167 * NOTES
2168 * Binary search taken from R.Sedgewick "Algorithms in C"!
2169 * Function is NOT tested!
2170 * If something goes wrong, blame HIM not ME! (Eric Kohl)
2171 */
2172
2173INT WINAPI
2174DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2175 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2176{
2177 if (!hdpa || !pfnCompare || !pFind)
2178 return -1;
2179
2180 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2181 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2182
2183 if (uOptions & DPAS_SORTED) {
2184 /* array is sorted --> use binary search */
2185 INT l, r, x, n;
2186 LPVOID *lpPtr;
2187
2188 TRACE("binary search\n");
2189
2190 l = (nStart == -1) ? 0 : nStart;
2191 r = hdpa->nItemCount - 1;
2192 lpPtr = hdpa->ptrs;
2193 while (r >= l) {
2194 x = (l + r) / 2;
2195 n = (pfnCompare)(pFind, lpPtr[x], lParam);
2196 if (n < 0)
2197 r = x - 1;
2198 else
2199 l = x + 1;
2200 if (n == 0) {
2201 TRACE("-- ret=%d\n", n);
2202 return n;
2203 }
2204 }
2205
2206 if (uOptions & DPAS_INSERTBEFORE) {
2207 TRACE("-- ret=%d\n", r);
2208 return r;
2209 }
2210
2211 if (uOptions & DPAS_INSERTAFTER) {
2212 TRACE("-- ret=%d\n", l);
2213 return l;
2214 }
2215 }
2216 else {
2217 /* array is not sorted --> use linear search */
2218 LPVOID *lpPtr;
2219 INT nIndex;
2220
2221 TRACE("linear search\n");
2222
2223 nIndex = (nStart == -1)? 0 : nStart;
2224 lpPtr = hdpa->ptrs;
2225 for (; nIndex < hdpa->nItemCount; nIndex++) {
2226 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2227 TRACE("-- ret=%d\n", nIndex);
2228 return nIndex;
2229 }
2230 }
2231 }
2232
2233 TRACE("-- not found: ret=-1\n");
2234 return -1;
2235}
2236
2237
2238/**************************************************************************
2239 * DPA_CreateEx [COMCTL32.340]
2240 *
2241 * Creates a dynamic pointer array using the specified size and heap.
2242 *
2243 * PARAMS
2244 * nGrow [I] number of items by which the array grows when it is filled
2245 * hHeap [I] handle to the heap where the array is stored
2246 *
2247 * RETURNS
2248 * Success: handle (pointer) to the pointer array.
2249 * Failure: NULL
2250 */
2251
2252HDPA WINAPI
2253DPA_CreateEx (INT nGrow, HANDLE hHeap)
2254{
2255 HDPA hdpa;
2256
2257 TRACE("(%d %p)\n", nGrow, hHeap);
2258
2259 if (hHeap)
2260 hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
2261 else
2262 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
2263
2264 if (hdpa) {
2265 hdpa->nGrow = min(8, nGrow);
2266 hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
2267 hdpa->nMaxCount = hdpa->nGrow * 2;
2268 hdpa->ptrs =
2269 (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
2270 hdpa->nMaxCount * sizeof(LPVOID));
2271 }
2272
2273 TRACE("-- %p\n", hdpa);
2274
2275 return hdpa;
2276}
2277
2278
2279/**************************************************************************
2280 * Notification functions
2281 */
2282
2283typedef struct tagNOTIFYDATA
2284{
2285 HWND hwndFrom;
2286 HWND hwndTo;
2287 DWORD dwParam3;
2288 DWORD dwParam4;
2289 DWORD dwParam5;
2290 DWORD dwParam6;
2291} NOTIFYDATA, *LPNOTIFYDATA;
2292
2293
2294/**************************************************************************
2295 * DoNotify [Internal]
2296 */
2297
2298static LRESULT
2299DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2300{
2301 NMHDR nmhdr;
2302 LPNMHDR lpNmh = NULL;
2303 UINT idFrom = 0;
2304
2305 TRACE("(%p %p %d %p 0x%08lx)\n",
2306 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2307 lpNotify->dwParam5);
2308
2309 if (!lpNotify->hwndTo)
2310 return 0;
2311
2312 if (lpNotify->hwndFrom == (HWND)-1) {
2313 lpNmh = lpHdr;
2314 idFrom = lpHdr->idFrom;
2315 }
2316 else {
2317 if (lpNotify->hwndFrom) {
2318 HWND hwndParent = GetParent (lpNotify->hwndFrom);
2319 if (hwndParent) {
2320 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
2321 /* the following is done even if the return from above
2322 * is zero. GLA 12/2001 */
2323 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2324 }
2325 }
2326
2327 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2328
2329 lpNmh->hwndFrom = lpNotify->hwndFrom;
2330 lpNmh->idFrom = idFrom;
2331 lpNmh->code = uCode;
2332 }
2333
2334 return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2335}
2336
2337
2338/**************************************************************************
2339 * SendNotify [COMCTL32.341]
2340 *
2341 * PARAMS
2342 * hwndTo [I]
2343 * hwndFrom [I]
2344 * uCode [I]
2345 * lpHdr [I]
2346 *
2347 * RETURNS
2348 * Success: return value from notification
2349 * Failure: 0
2350 */
2351
2352LRESULT WINAPI
2353COMCTL32_SendNotify (HWND hwndTo, HWND hwndFrom,
2354 UINT uCode, LPNMHDR lpHdr)
2355{
2356 NOTIFYDATA notify;
2357
2358 TRACE("(%p %p %d %p)\n",
2359 hwndTo, hwndFrom, uCode, lpHdr);
2360
2361 notify.hwndFrom = hwndFrom;
2362 notify.hwndTo = hwndTo;
2363 notify.dwParam5 = 0;
2364 notify.dwParam6 = 0;
2365
2366 return DoNotify (&notify, uCode, lpHdr);
2367}
2368
2369
2370/**************************************************************************
2371 * SendNotifyEx [COMCTL32.342]
2372 *
2373 * PARAMS
2374 * hwndFrom [I]
2375 * hwndTo [I]
2376 * uCode [I]
2377 * lpHdr [I]
2378 * dwParam5 [I]
2379 *
2380 * RETURNS
2381 * Success: return value from notification
2382 * Failure: 0
2383 */
2384
2385LRESULT WINAPI
2386COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2387 LPNMHDR lpHdr, DWORD dwParam5)
2388{
2389 NOTIFYDATA notify;
2390 HWND hwndNotify;
2391
2392 TRACE("(%p %p %d %p 0x%08lx)\n",
2393 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2394
2395 hwndNotify = hwndTo;
2396 if (!hwndTo) {
2397 if (IsWindow (hwndFrom)) {
2398 hwndNotify = GetParent (hwndFrom);
2399 if (!hwndNotify)
2400 return 0;
2401 }
2402 }
2403
2404 notify.hwndFrom = hwndFrom;
2405 notify.hwndTo = hwndNotify;
2406 notify.dwParam5 = dwParam5;
2407 notify.dwParam6 = 0;
2408
2409 return DoNotify (&notify, uCode, lpHdr);
2410}
2411
2412
2413/**************************************************************************
2414 * StrChrA [COMCTL32.350]
2415 *
2416 */
2417
2418LPSTR WINAPI
2419COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
2420{
2421 return strchr (lpString, cChar);
2422}
2423
2424
2425/**************************************************************************
2426 * StrStrIA [COMCTL32.355]
2427 */
2428
2429LPSTR WINAPI
2430COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
2431{
2432 INT len1, len2, i;
2433 CHAR first;
2434
2435 if (*lpStr2 == 0)
2436 return ((LPSTR)lpStr1);
2437 len1 = 0;
2438 while (lpStr1[len1] != 0) ++len1;
2439 len2 = 0;
2440 while (lpStr2[len2] != 0) ++len2;
2441 if (len2 == 0)
2442 return ((LPSTR)(lpStr1 + len1));
2443 first = tolower (*lpStr2);
2444 while (len1 >= len2) {
2445 if (tolower(*lpStr1) == first) {
2446 for (i = 1; i < len2; ++i)
2447 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
2448 break;
2449 if (i >= len2)
2450 return ((LPSTR)lpStr1);
2451 }
2452 ++lpStr1; --len1;
2453 }
2454 return (NULL);
2455}
2456
2457/**************************************************************************
2458 * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
2459 */
2460
2461INT WINAPI
2462COMCTL32_StrToIntA (LPSTR lpString)
2463{
2464 return atoi(lpString);
2465}
2466
2467/**************************************************************************
2468 * StrStrIW [COMCTL32.363]
2469 */
2470
2471LPWSTR WINAPI
2472COMCTL32_StrStrIW (LPCWSTR lpStr1, LPCWSTR lpStr2)
2473{
2474 INT len1, len2, i;
2475 WCHAR first;
2476
2477 if (*lpStr2 == 0)
2478 return ((LPWSTR)lpStr1);
2479 len1 = 0;
2480 while (lpStr1[len1] != 0) ++len1;
2481 len2 = 0;
2482 while (lpStr2[len2] != 0) ++len2;
2483 if (len2 == 0)
2484 return ((LPWSTR)(lpStr1 + len1));
2485 first = tolowerW (*lpStr2);
2486 while (len1 >= len2) {
2487 if (tolowerW (*lpStr1) == first) {
2488 for (i = 1; i < len2; ++i)
2489 if (tolowerW (lpStr1[i]) != tolowerW(lpStr2[i]))
2490 break;
2491 if (i >= len2)
2492 return ((LPWSTR)lpStr1);
2493 }
2494 ++lpStr1; --len1;
2495 }
2496 return (NULL);
2497}
2498
2499/**************************************************************************
2500 * StrToIntW [COMCTL32.365] Converts a wide char string to a signed integer.
2501 */
2502
2503INT WINAPI
2504COMCTL32_StrToIntW (LPWSTR lpString)
2505{
2506 return atoiW(lpString);
2507}
2508
2509
2510/**************************************************************************
2511 * DPA_EnumCallback [COMCTL32.385]
2512 *
2513 * Enumerates all items in a dynamic pointer array.
2514 *
2515 * PARAMS
2516 * hdpa [I] handle to the dynamic pointer array
2517 * enumProc [I]
2518 * lParam [I]
2519 *
2520 * RETURNS
2521 * none
2522 */
2523
2524VOID WINAPI
2525DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2526{
2527 INT i;
2528
2529 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2530
2531 if (!hdpa)
2532 return;
2533 if (hdpa->nItemCount <= 0)
2534 return;
2535
2536 for (i = 0; i < hdpa->nItemCount; i++) {
2537 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2538 return;
2539 }
2540
2541 return;
2542}
2543
2544
2545/**************************************************************************
2546 * DPA_DestroyCallback [COMCTL32.386]
2547 *
2548 * Enumerates all items in a dynamic pointer array and destroys it.
2549 *
2550 * PARAMS
2551 * hdpa [I] handle to the dynamic pointer array
2552 * enumProc [I]
2553 * lParam [I]
2554 *
2555 * RETURNS
2556 * Success: TRUE
2557 * Failure: FALSE
2558 */
2559
2560BOOL WINAPI
2561DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2562{
2563 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2564
2565 DPA_EnumCallback (hdpa, enumProc, lParam);
2566
2567 return DPA_Destroy (hdpa);
2568}
2569
2570
2571/**************************************************************************
2572 * DSA_EnumCallback [COMCTL32.387]
2573 *
2574 * Enumerates all items in a dynamic storage array.
2575 *
2576 * PARAMS
2577 * hdsa [I] handle to the dynamic storage array
2578 * enumProc [I]
2579 * lParam [I]
2580 *
2581 * RETURNS
2582 * none
2583 */
2584
2585VOID WINAPI
2586DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2587{
2588 INT i;
2589
2590 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2591
2592 if (!hdsa)
2593 return;
2594 if (hdsa->nItemCount <= 0)
2595 return;
2596
2597 for (i = 0; i < hdsa->nItemCount; i++) {
2598 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2599 if ((enumProc)(lpItem, lParam) == 0)
2600 return;
2601 }
2602
2603 return;
2604}
2605
2606
2607/**************************************************************************
2608 * DSA_DestroyCallback [COMCTL32.388]
2609 *
2610 * Enumerates all items in a dynamic storage array and destroys it.
2611 *
2612 * PARAMS
2613 * hdsa [I] handle to the dynamic storage array
2614 * enumProc [I]
2615 * lParam [I]
2616 *
2617 * RETURNS
2618 * Success: TRUE
2619 * Failure: FALSE
2620 */
2621
2622BOOL WINAPI
2623DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2624{
2625 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2626
2627 DSA_EnumCallback (hdsa, enumProc, lParam);
2628
2629 return DSA_Destroy (hdsa);
2630}
2631
2632/**************************************************************************
2633 * StrCSpnA [COMCTL32.356]
2634 *
2635 */
2636INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2637 return strcspn(lpStr, lpSet);
2638}
2639
2640/**************************************************************************
2641 * StrChrW [COMCTL32.358]
2642 *
2643 */
2644LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2645 return strchrW(lpStart, wMatch);
2646}
2647
2648/**************************************************************************
2649 * StrCmpNA [COMCTL32.352]
2650 *
2651 */
2652INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2653 return strncmp(lpStr1, lpStr2, nChar);
2654}
2655
2656/**************************************************************************
2657 * StrCmpNIA [COMCTL32.353]
2658 *
2659 */
2660INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2661 return strncasecmp(lpStr1, lpStr2, nChar);
2662}
2663
2664/**************************************************************************
2665 * StrCmpNW [COMCTL32.360]
2666 *
2667 */
2668INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2669 return strncmpW(lpStr1, lpStr2, nChar);
2670}
2671
2672/**************************************************************************
2673 * StrCmpNIW [COMCTL32.361]
2674 *
2675 */
2676INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2677 FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2678 return 0;
2679}
2680
2681/**************************************************************************
2682 * StrRChrA [COMCTL32.351]
2683 *
2684 */
2685LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
2686{
2687 LPCSTR lpGotIt = NULL;
2688 BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
2689
2690 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2691
2692 if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
2693
2694 for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
2695 {
2696 if (*lpStart != LOBYTE(wMatch)) continue;
2697 if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
2698 lpGotIt = lpStart;
2699 }
2700 return (LPSTR)lpGotIt;
2701}
2702
2703
2704/**************************************************************************
2705 * StrRChrW [COMCTL32.359]
2706 *
2707 */
2708LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
2709{
2710 LPCWSTR lpGotIt = NULL;
2711
2712 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2713 if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
2714
2715 for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
2716 if (*lpStart == wMatch) lpGotIt = lpStart;
2717
2718 return (LPWSTR)lpGotIt;
2719}
2720
2721
2722/**************************************************************************
2723 * StrStrA [COMCTL32.354]
2724 *
2725 */
2726LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2727 return strstr(lpFirst, lpSrch);
2728}
2729
2730/**************************************************************************
2731 * StrStrW [COMCTL32.362]
2732 *
2733 */
2734LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2735 return strstrW(lpFirst, lpSrch);
2736}
2737
2738/**************************************************************************
2739 * StrSpnW [COMCTL32.364]
2740 *
2741 */
2742INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2743 LPWSTR lpLoop = lpStr;
2744
2745 /* validate ptr */
2746 if ((lpStr == 0) || (lpSet == 0)) return 0;
2747
2748/* while(*lpLoop) { if lpLoop++; } */
2749
2750 for(; (*lpLoop != 0); lpLoop++)
2751 if( strchrW(lpSet, *(WORD*)lpLoop))
2752 return (INT)(lpLoop-lpStr);
2753
2754 return (INT)(lpLoop-lpStr);
2755}
2756
2757/**************************************************************************
2758 * @ [COMCTL32.415]
2759 *
2760 * FIXME: What's this supposed to do?
2761 * Parameter 1 is an HWND, you're on your own for the rest.
2762 */
2763
2764BOOL WINAPI COMCTL32_415( HWND hwnd, DWORD b, DWORD c, DWORD d, DWORD e)
2765{
2766
2767 FIXME("(%p, %lx, %lx, %lx, %lx): stub!\n", hwnd, b, c, d, e);
2768
2769 return TRUE;
2770}
2771
2772/**************************************************************************
2773 * @ [COMCTL32.417]
2774 *
2775 */
2776BOOL WINAPI COMCTL32_417(HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
2777 LPCWSTR str, UINT count, const INT *lpDx)
2778{
2779 return ExtTextOutW(hdc, x, y, flags, lprect, str, count, lpDx);
2780}
2781
2782/**************************************************************************
2783 * @ [COMCTL32.419]
2784 *
2785 * FIXME: What's this supposed to do?
2786 */
2787
2788BOOL WINAPI COMCTL32_419( DWORD a, DWORD b, DWORD c, DWORD d)
2789{
2790
2791 FIXME("(%lx, %lx, %lx, %lx): stub!\n", a, b, c, d);
2792
2793 return TRUE;
2794}
Note: See TracBrowser for help on using the repository browser.