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

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

Wine resync

File size: 66.1 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/**************************************************************************
615 * FindMRUData [COMCTL32.169]
616 *
617 * Searches binary list for item that matches lpData of length cbData.
618 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
619 * corresponding to item's reg. name will be stored in it ('a' -> 0).
620 *
621 * PARAMS
622 * hList [I] list handle
623 * lpData [I] data to find
624 * cbData [I] length of data
625 * lpRegNum [O] position in registry (maybe NULL)
626 *
627 * RETURNS
628 * Position in list 0 -> MRU. -1 if item not found.
629 */
630INT WINAPI
631FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum)
632{
633 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
634 UINT i, ret;
635 LPSTR dataA = NULL;
636
637 if (!mp->extview.lpfnCompare) {
638 ERR("MRU list not properly created. No compare procedure.\n");
639 return -1;
640 }
641
642 if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
643 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
644 NULL, 0, NULL, NULL);
645 dataA = COMCTL32_Alloc(len);
646 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
647 }
648
649 for(i=0; i<mp->cursize; i++) {
650 if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
651 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
652 cbData))
653 break;
654 }
655 else {
656 if(mp->isUnicode) {
657 if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
658 break;
659 } else {
660 DWORD len = WideCharToMultiByte(CP_ACP, 0,
661 (LPWSTR)&mp->array[i]->datastart, -1,
662 NULL, 0, NULL, NULL);
663 LPSTR itemA = COMCTL32_Alloc(len);
664 INT cmp;
665 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
666 itemA, len, NULL, NULL);
667
668 cmp = mp->extview.lpfnCompare(dataA, itemA);
669 COMCTL32_Free(itemA);
670 if(!cmp)
671 break;
672 }
673 }
674 }
675 if(dataA)
676 COMCTL32_Free(dataA);
677 if (i < mp->cursize)
678 ret = i;
679 else
680 ret = -1;
681 if (lpRegNum && (ret != -1))
682 *lpRegNum = 'a' + i;
683
684 TRACE("(%p, %p, %ld, %p) returning %d\n",
685 hList, lpData, cbData, lpRegNum, ret);
686
687 return ret;
688}
689
690
691/**************************************************************************
692 * AddMRUData [COMCTL32.167]
693 *
694 * Add item to MRU binary list. If item already exists in list then it is
695 * simply moved up to the top of the list and not added again. If list is
696 * full then the least recently used item is removed to make room.
697 *
698 * PARAMS
699 * hList [I] Handle to list.
700 * lpData [I] ptr to data to add.
701 * cbData [I] no. of bytes of data.
702 *
703 * RETURNS
704 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
705 * -1 on error.
706 */
707INT WINAPI
708AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
709{
710 LPWINEMRULIST mp = (LPWINEMRULIST)hList;
711 LPWINEMRUITEM witem;
712 INT i, replace, ret;
713
714 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) < 0) {
715 /* either add a new entry or replace oldest */
716 if (mp->cursize < mp->extview.nMaxItems) {
717 /* Add in a new item */
718 replace = mp->cursize;
719 mp->cursize++;
720 }
721 else {
722 /* get the oldest entry and replace data */
723 replace = mp->realMRU[mp->cursize - 1] - 'a';
724 COMCTL32_Free(mp->array[replace]);
725 }
726 }
727 else {
728 /* free up the old data */
729 COMCTL32_Free(mp->array[replace]);
730 }
731
732 /* Allocate space for new item and move in the data */
733 mp->array[replace] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(cbData +
734 sizeof(WINEMRUITEM));
735 witem->itemFlag |= WMRUIF_CHANGED;
736 witem->size = cbData;
737 memcpy( &witem->datastart, lpData, cbData);
738
739 /* now rotate MRU list */
740 mp->wineFlags |= WMRUF_CHANGED;
741 for(i=mp->cursize-1; i>=1; i--) {
742 mp->realMRU[i] = mp->realMRU[i-1];
743 }
744 mp->realMRU[0] = replace + 'a';
745 TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n",
746 hList, lpData, cbData, replace+'a');
747 ret = replace;
748
749 if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
750 /* save changed stuff right now */
751 MRU_SaveChanged( mp );
752 }
753
754 return ret;
755}
756
757/**************************************************************************
758 * AddMRUStringW [COMCTL32.401]
759 *
760 * Add item to MRU string list. If item already exists in list them it is
761 * simply moved up to the top of the list and not added again. If list is
762 * full then the least recently used item is removed to make room.
763 *
764 * PARAMS
765 * hList [I] Handle to list.
766 * lpszString [I] ptr to string to add.
767 *
768 * RETURNS
769 * No. corresponding to registry name where value is stored 'a' -> 0 etc.
770 * -1 on error.
771 */
772INT WINAPI
773AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
774{
775 FIXME("(%p, %s) empty stub!\n", hList, debugstr_w(lpszString));
776
777 return 0;
778}
779
780/**************************************************************************
781 * AddMRUStringA [COMCTL32.153]
782 */
783INT WINAPI
784AddMRUStringA(HANDLE hList, LPCSTR lpszString)
785{
786 FIXME("(%p, %s) empty stub!\n", hList, debugstr_a(lpszString));
787
788 return 0;
789}
790
791/**************************************************************************
792 * DelMRUString [COMCTL32.156]
793 *
794 * Removes item from either string or binary list (despite its name)
795 *
796 * PARAMS
797 * hList [I] list handle
798 * nItemPos [I] item position to remove 0 -> MRU
799 *
800 * RETURNS
801 * TRUE if successful, FALSE if nItemPos is out of range.
802 */
803BOOL WINAPI
804DelMRUString(HANDLE hList, INT nItemPos)
805{
806 FIXME("(%p, %d): stub\n", hList, nItemPos);
807 return TRUE;
808}
809
810/**************************************************************************
811 * FindMRUStringW [COMCTL32.402]
812 */
813INT WINAPI
814FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
815{
816 FIXME("stub\n");
817 return -1;
818}
819
820/**************************************************************************
821 * FindMRUStringA [COMCTL32.155]
822 *
823 * Searches string list for item that matches lpszString.
824 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
825 * corresponding to item's reg. name will be stored in it ('a' -> 0).
826 *
827 * PARAMS
828 * hList [I] list handle
829 * lpszString [I] string to find
830 * lpRegNum [O] position in registry (maybe NULL)
831 *
832 * RETURNS
833 * Position in list 0 -> MRU. -1 if item not found.
834 */
835INT WINAPI
836FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
837{
838 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
839 LPWSTR stringW = COMCTL32_Alloc(len * sizeof(WCHAR));
840 INT ret;
841
842 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
843 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
844 COMCTL32_Free(stringW);
845 return ret;
846}
847
848/*************************************************************************
849 * CreateMRUListLazy_common
850 */
851HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
852{
853 UINT i, err;
854 HKEY newkey;
855 DWORD datasize, dwdisp;
856 WCHAR realname[2];
857 LPWINEMRUITEM witem;
858 DWORD type;
859 WCHAR emptyW[] = {'\0'};
860
861 /* get space to save indices that will turn into names
862 * but in order of most to least recently used
863 */
864 mp->realMRU = (LPSTR) COMCTL32_Alloc(mp->extview.nMaxItems + 2);
865
866 /* get space to save pointers to actual data in order of
867 * 'a' to 'z' (0 to n).
868 */
869 mp->array = (LPVOID) COMCTL32_Alloc(mp->extview.nMaxItems *
870 sizeof(LPVOID));
871
872 /* open the sub key */
873 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
874 0,
875 emptyW,
876 REG_OPTION_NON_VOLATILE,
877 KEY_READ | KEY_WRITE,
878 0,
879 &newkey,
880 &dwdisp))) {
881 /* error - what to do ??? */
882 ERR("(%lu %lu %lx %lx \"%s\" %p): Can not open key, error=%d\n",
883 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
884 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
885 mp->extview.lpfnCompare, err);
886 return 0;
887 }
888
889 /* get values from key 'MRUList' */
890 if (newkey) {
891 datasize = mp->extview.nMaxItems + 1;
892 if((err=RegQueryValueExA( newkey, "MRUList", 0, &type, mp->realMRU,
893 &datasize))) {
894 /* not present - set size to 1 (will become 0 later) */
895 datasize = 1;
896 *mp->realMRU = 0;
897 }
898
899 TRACE("MRU list = %s\n", mp->realMRU);
900
901 mp->cursize = datasize - 1;
902 /* datasize now has number of items in the MRUList */
903
904 /* get actual values for each entry */
905 realname[1] = 0;
906 for(i=0; i<mp->cursize; i++) {
907 realname[0] = 'a' + i;
908 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
909 /* not present - what to do ??? */
910 ERR("Key %s not found 1\n", debugstr_w(realname));
911 }
912 mp->array[i] = witem = (LPWINEMRUITEM)COMCTL32_Alloc(datasize +
913 sizeof(WINEMRUITEM));
914 witem->size = datasize;
915 if(RegQueryValueExW( newkey, realname, 0, &type,
916 &witem->datastart, &datasize)) {
917 /* not present - what to do ??? */
918 ERR("Key %s not found 2\n", debugstr_w(realname));
919 }
920 }
921 RegCloseKey( newkey );
922 }
923 else
924 mp->cursize = 0;
925
926 TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n",
927 mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
928 (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
929 mp->extview.lpfnCompare, mp->cursize);
930 return (HANDLE)mp;
931}
932
933/**************************************************************************
934 * CreateMRUListLazyW [COMCTL32.404]
935 */
936HANDLE WINAPI
937CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
938{
939 LPWINEMRULIST mp;
940
941 if (lpcml == NULL)
942 return 0;
943
944 if (lpcml->cbSize < sizeof(CREATEMRULISTW))
945 return 0;
946
947 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
948 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
949 mp->extview.lpszSubKey = COMCTL32_Alloc((strlenW(lpcml->lpszSubKey) + 1) *
950 sizeof(WCHAR));
951 strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
952 mp->isUnicode = TRUE;
953
954 return CreateMRUListLazy_common(mp);
955}
956
957/**************************************************************************
958 * CreateMRUListLazyA [COMCTL32.157]
959 */
960HANDLE WINAPI
961CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
962{
963 LPWINEMRULIST mp;
964 DWORD len;
965
966 if (lpcml == NULL)
967 return 0;
968
969 if (lpcml->cbSize < sizeof(CREATEMRULISTA))
970 return 0;
971
972 mp = (LPWINEMRULIST) COMCTL32_Alloc(sizeof(WINEMRULIST));
973 memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
974 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
975 mp->extview.lpszSubKey = COMCTL32_Alloc(len * sizeof(WCHAR));
976 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
977 (LPWSTR)mp->extview.lpszSubKey, len);
978 mp->isUnicode = FALSE;
979 return CreateMRUListLazy_common(mp);
980}
981
982/**************************************************************************
983 * CreateMRUListW [COMCTL32.400]
984 *
985 * PARAMS
986 * lpcml [I] ptr to CREATEMRULIST structure.
987 *
988 * RETURNS
989 * Handle to MRU list.
990 */
991HANDLE WINAPI
992CreateMRUListW (LPCREATEMRULISTW lpcml)
993{
994 return CreateMRUListLazyW(lpcml, 0, 0, 0);
995}
996
997/**************************************************************************
998 * CreateMRUListA [COMCTL32.151]
999 */
1000HANDLE WINAPI
1001CreateMRUListA (LPCREATEMRULISTA lpcml)
1002{
1003 return CreateMRUListLazyA (lpcml, 0, 0, 0);
1004}
1005
1006
1007/**************************************************************************
1008 * EnumMRUListW [COMCTL32.403]
1009 *
1010 * Enumerate item in a list
1011 *
1012 * PARAMS
1013 * hList [I] list handle
1014 * nItemPos [I] item position to enumerate
1015 * lpBuffer [O] buffer to receive item
1016 * nBufferSize [I] size of buffer
1017 *
1018 * RETURNS
1019 * For binary lists specifies how many bytes were copied to buffer, for
1020 * string lists specifies full length of string. Enumerating past the end
1021 * of list returns -1.
1022 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
1023 * the list.
1024 */
1025INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1026DWORD nBufferSize)
1027{
1028 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1029 LPWINEMRUITEM witem;
1030 INT desired, datasize;
1031
1032 if (nItemPos >= mp->cursize) return -1;
1033 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1034 desired = mp->realMRU[nItemPos];
1035 desired -= 'a';
1036 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1037 witem = mp->array[desired];
1038 datasize = min( witem->size, nBufferSize );
1039 memcpy( lpBuffer, &witem->datastart, datasize);
1040 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1041 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1042 return datasize;
1043}
1044
1045/**************************************************************************
1046 * EnumMRUListA [COMCTL32.154]
1047 *
1048 */
1049INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer,
1050DWORD nBufferSize)
1051{
1052 LPWINEMRULIST mp = (LPWINEMRULIST) hList;
1053 LPWINEMRUITEM witem;
1054 INT desired, datasize;
1055 DWORD lenA;
1056
1057 if (nItemPos >= mp->cursize) return -1;
1058 if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
1059 desired = mp->realMRU[nItemPos];
1060 desired -= 'a';
1061 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
1062 witem = mp->array[desired];
1063 if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
1064 datasize = min( witem->size, nBufferSize );
1065 memcpy( lpBuffer, &witem->datastart, datasize);
1066 } else {
1067 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1068 NULL, 0, NULL, NULL);
1069 datasize = min( witem->size, nBufferSize );
1070 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
1071 lpBuffer, datasize, NULL, NULL);
1072 }
1073 TRACE("(%p, %d, %p, %ld): returning len=%d\n",
1074 hList, nItemPos, lpBuffer, nBufferSize, datasize);
1075 return datasize;
1076}
1077
1078
1079/**************************************************************************
1080 * Str_GetPtrA [COMCTL32.233]
1081 *
1082 * PARAMS
1083 * lpSrc [I]
1084 * lpDest [O]
1085 * nMaxLen [I]
1086 *
1087 * RETURNS
1088 */
1089
1090INT WINAPI
1091Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1092{
1093 INT len;
1094
1095 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1096
1097 if (!lpDest && lpSrc)
1098 return strlen (lpSrc);
1099
1100 if (nMaxLen == 0)
1101 return 0;
1102
1103 if (lpSrc == NULL) {
1104 lpDest[0] = '\0';
1105 return 0;
1106 }
1107
1108 len = strlen (lpSrc);
1109 if (len >= nMaxLen)
1110 len = nMaxLen - 1;
1111
1112 RtlMoveMemory (lpDest, lpSrc, len);
1113 lpDest[len] = '\0';
1114
1115 return len;
1116}
1117
1118
1119/**************************************************************************
1120 * Str_SetPtrA [COMCTL32.234]
1121 *
1122 * PARAMS
1123 * lppDest [O]
1124 * lpSrc [I]
1125 *
1126 * RETURNS
1127 */
1128
1129BOOL WINAPI
1130Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
1131{
1132 TRACE("(%p %p)\n", lppDest, lpSrc);
1133
1134 if (lpSrc) {
1135 LPSTR ptr = COMCTL32_ReAlloc (*lppDest, strlen (lpSrc) + 1);
1136 if (!ptr)
1137 return FALSE;
1138 strcpy (ptr, lpSrc);
1139 *lppDest = ptr;
1140 }
1141 else {
1142 if (*lppDest) {
1143 COMCTL32_Free (*lppDest);
1144 *lppDest = NULL;
1145 }
1146 }
1147
1148 return TRUE;
1149}
1150
1151
1152/**************************************************************************
1153 * Str_GetPtrW [COMCTL32.235]
1154 *
1155 * PARAMS
1156 * lpSrc [I]
1157 * lpDest [O]
1158 * nMaxLen [I]
1159 *
1160 * RETURNS
1161 */
1162
1163INT WINAPI
1164Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
1165{
1166 INT len;
1167
1168 TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
1169
1170 if (!lpDest && lpSrc)
1171 return strlenW (lpSrc);
1172
1173 if (nMaxLen == 0)
1174 return 0;
1175
1176 if (lpSrc == NULL) {
1177 lpDest[0] = L'\0';
1178 return 0;
1179 }
1180
1181 len = strlenW (lpSrc);
1182 if (len >= nMaxLen)
1183 len = nMaxLen - 1;
1184
1185 RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
1186 lpDest[len] = L'\0';
1187
1188 return len;
1189}
1190
1191
1192/**************************************************************************
1193 * Str_SetPtrW [COMCTL32.236]
1194 *
1195 * PARAMS
1196 * lpDest [O]
1197 * lpSrc [I]
1198 *
1199 * RETURNS
1200 */
1201
1202BOOL WINAPI
1203Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
1204{
1205 TRACE("(%p %p)\n", lppDest, lpSrc);
1206
1207 if (lpSrc) {
1208 INT len = strlenW (lpSrc) + 1;
1209 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len * sizeof(WCHAR));
1210 if (!ptr)
1211 return FALSE;
1212 strcpyW (ptr, lpSrc);
1213 *lppDest = ptr;
1214 }
1215 else {
1216 if (*lppDest) {
1217 COMCTL32_Free (*lppDest);
1218 *lppDest = NULL;
1219 }
1220 }
1221
1222 return TRUE;
1223}
1224
1225
1226/**************************************************************************
1227 * Str_GetPtrWtoA [internal]
1228 *
1229 * Converts a unicode string into a multi byte string
1230 *
1231 * PARAMS
1232 * lpSrc [I] Pointer to the unicode source string
1233 * lpDest [O] Pointer to caller supplied storage for the multi byte string
1234 * nMaxLen [I] Size, in bytes, of the destination buffer
1235 *
1236 * RETURNS
1237 * Length, in bytes, of the converted string.
1238 */
1239
1240INT
1241Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1242{
1243 INT len;
1244
1245 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);
1246
1247 if (!lpDest && lpSrc)
1248 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1249
1250 if (nMaxLen == 0)
1251 return 0;
1252
1253 if (lpSrc == NULL) {
1254 lpDest[0] = '\0';
1255 return 0;
1256 }
1257
1258 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
1259 if (len >= nMaxLen)
1260 len = nMaxLen - 1;
1261
1262 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
1263 lpDest[len] = '\0';
1264
1265 return len;
1266}
1267
1268
1269/**************************************************************************
1270 * Str_SetPtrAtoW [internal]
1271 *
1272 * Converts a multi byte string to a unicode string.
1273 * If the pointer to the destination buffer is NULL a buffer is allocated.
1274 * If the destination buffer is too small to keep the converted multi byte
1275 * string the destination buffer is reallocated. If the source pointer is
1276 * NULL, the destination buffer is freed.
1277 *
1278 * PARAMS
1279 * lppDest [I/O] pointer to a pointer to the destination buffer
1280 * lpSrc [I] pointer to a multi byte string
1281 *
1282 * RETURNS
1283 * TRUE: conversion successful
1284 * FALSE: error
1285 */
1286
1287BOOL
1288Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1289{
1290 TRACE("(%p %s)\n", lppDest, lpSrc);
1291
1292 if (lpSrc) {
1293 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1294 LPWSTR ptr = COMCTL32_ReAlloc (*lppDest, len*sizeof(WCHAR));
1295
1296 if (!ptr)
1297 return FALSE;
1298 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
1299 *lppDest = ptr;
1300 }
1301 else {
1302 if (*lppDest) {
1303 COMCTL32_Free (*lppDest);
1304 *lppDest = NULL;
1305 }
1306 }
1307
1308 return TRUE;
1309}
1310
1311
1312/**************************************************************************
1313 * The DSA-API is a set of functions to create and manipulate arrays of
1314 * fixed-size memory blocks. These arrays can store any kind of data
1315 * (strings, icons...).
1316 */
1317
1318/**************************************************************************
1319 * DSA_Create [COMCTL32.320] Creates a dynamic storage array
1320 *
1321 * PARAMS
1322 * nSize [I] size of the array elements
1323 * nGrow [I] number of elements by which the array grows when it is filled
1324 *
1325 * RETURNS
1326 * Success: pointer to an array control structure. Use this like a handle.
1327 * Failure: NULL
1328 */
1329
1330HDSA WINAPI
1331DSA_Create (INT nSize, INT nGrow)
1332{
1333 HDSA hdsa;
1334
1335 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
1336
1337 hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
1338 if (hdsa)
1339 {
1340 hdsa->nItemCount = 0;
1341 hdsa->pData = NULL;
1342 hdsa->nMaxCount = 0;
1343 hdsa->nItemSize = nSize;
1344 hdsa->nGrow = max(1, nGrow);
1345 }
1346
1347 return hdsa;
1348}
1349
1350
1351/**************************************************************************
1352 * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
1353 *
1354 * PARAMS
1355 * hdsa [I] pointer to the array control structure
1356 *
1357 * RETURNS
1358 * Success: TRUE
1359 * Failure: FALSE
1360 */
1361
1362BOOL WINAPI
1363DSA_Destroy (const HDSA hdsa)
1364{
1365 TRACE("(%p)\n", hdsa);
1366
1367 if (!hdsa)
1368 return FALSE;
1369
1370 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1371 return FALSE;
1372
1373 return COMCTL32_Free (hdsa);
1374}
1375
1376
1377/**************************************************************************
1378 * DSA_GetItem [COMCTL32.322]
1379 *
1380 * PARAMS
1381 * hdsa [I] pointer to the array control structure
1382 * nIndex [I] number of the Item to get
1383 * pDest [O] destination buffer. Has to be >= dwElementSize.
1384 *
1385 * RETURNS
1386 * Success: TRUE
1387 * Failure: FALSE
1388 */
1389
1390BOOL WINAPI
1391DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
1392{
1393 LPVOID pSrc;
1394
1395 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
1396
1397 if (!hdsa)
1398 return FALSE;
1399 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1400 return FALSE;
1401
1402 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1403 memmove (pDest, pSrc, hdsa->nItemSize);
1404
1405 return TRUE;
1406}
1407
1408
1409/**************************************************************************
1410 * DSA_GetItemPtr [COMCTL32.323]
1411 *
1412 * Retrieves a pointer to the specified item.
1413 *
1414 * PARAMS
1415 * hdsa [I] pointer to the array control structure
1416 * nIndex [I] index of the desired item
1417 *
1418 * RETURNS
1419 * Success: pointer to an item
1420 * Failure: NULL
1421 */
1422
1423LPVOID WINAPI
1424DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
1425{
1426 LPVOID pSrc;
1427
1428 TRACE("(%p %d)\n", hdsa, nIndex);
1429
1430 if (!hdsa)
1431 return NULL;
1432 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
1433 return NULL;
1434
1435 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1436
1437 TRACE("-- ret=%p\n", pSrc);
1438
1439 return pSrc;
1440}
1441
1442
1443/**************************************************************************
1444 * DSA_SetItem [COMCTL32.325]
1445 *
1446 * Sets the contents of an item in the array.
1447 *
1448 * PARAMS
1449 * hdsa [I] pointer to the array control structure
1450 * nIndex [I] index for the item
1451 * pSrc [I] pointer to the new item data
1452 *
1453 * RETURNS
1454 * Success: TRUE
1455 * Failure: FALSE
1456 */
1457
1458BOOL WINAPI
1459DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1460{
1461 INT nSize, nNewItems;
1462 LPVOID pDest, lpTemp;
1463
1464 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1465
1466 if ((!hdsa) || nIndex < 0)
1467 return FALSE;
1468
1469 if (hdsa->nItemCount <= nIndex) {
1470 /* within the old array */
1471 if (hdsa->nMaxCount > nIndex) {
1472 /* within the allocated space, set a new boundary */
1473 hdsa->nItemCount = nIndex + 1;
1474 }
1475 else {
1476 /* resize the block of memory */
1477 nNewItems =
1478 hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
1479 nSize = hdsa->nItemSize * nNewItems;
1480
1481 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1482 if (!lpTemp)
1483 return FALSE;
1484
1485 hdsa->nMaxCount = nNewItems;
1486 hdsa->nItemCount = nIndex + 1;
1487 hdsa->pData = lpTemp;
1488 }
1489 }
1490
1491 /* put the new entry in */
1492 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1493 TRACE("-- move dest=%p src=%p size=%d\n",
1494 pDest, pSrc, hdsa->nItemSize);
1495 memmove (pDest, pSrc, hdsa->nItemSize);
1496
1497 return TRUE;
1498}
1499
1500
1501/**************************************************************************
1502 * DSA_InsertItem [COMCTL32.324]
1503 *
1504 * PARAMS
1505 * hdsa [I] pointer to the array control structure
1506 * nIndex [I] index for the new item
1507 * pSrc [I] pointer to the element
1508 *
1509 * RETURNS
1510 * Success: position of the new item
1511 * Failure: -1
1512 */
1513
1514INT WINAPI
1515DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
1516{
1517 INT nNewItems, nSize;
1518 LPVOID lpTemp, lpDest;
1519
1520 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
1521
1522 if ((!hdsa) || nIndex < 0)
1523 return -1;
1524
1525 /* when nIndex >= nItemCount then append */
1526 if (nIndex >= hdsa->nItemCount)
1527 nIndex = hdsa->nItemCount;
1528
1529 /* do we need to resize ? */
1530 if (hdsa->nItemCount >= hdsa->nMaxCount) {
1531 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
1532 nSize = hdsa->nItemSize * nNewItems;
1533
1534 lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1535 if (!lpTemp)
1536 return -1;
1537
1538 hdsa->nMaxCount = nNewItems;
1539 hdsa->pData = lpTemp;
1540 }
1541
1542 /* do we need to move elements ? */
1543 if (nIndex < hdsa->nItemCount) {
1544 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1545 lpDest = (char *) lpTemp + hdsa->nItemSize;
1546 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
1547 TRACE("-- move dest=%p src=%p size=%d\n",
1548 lpDest, lpTemp, nSize);
1549 memmove (lpDest, lpTemp, nSize);
1550 }
1551
1552 /* ok, we can put the new Item in */
1553 hdsa->nItemCount++;
1554 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1555 TRACE("-- move dest=%p src=%p size=%d\n",
1556 lpDest, pSrc, hdsa->nItemSize);
1557 memmove (lpDest, pSrc, hdsa->nItemSize);
1558
1559 return nIndex;
1560}
1561
1562
1563/**************************************************************************
1564 * DSA_DeleteItem [COMCTL32.326]
1565 *
1566 * PARAMS
1567 * hdsa [I] pointer to the array control structure
1568 * nIndex [I] index for the element to delete
1569 *
1570 * RETURNS
1571 * Success: number of the deleted element
1572 * Failure: -1
1573 */
1574
1575INT WINAPI
1576DSA_DeleteItem (const HDSA hdsa, INT nIndex)
1577{
1578 LPVOID lpDest,lpSrc;
1579 INT nSize;
1580
1581 TRACE("(%p %d)\n", hdsa, nIndex);
1582
1583 if (!hdsa)
1584 return -1;
1585 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
1586 return -1;
1587
1588 /* do we need to move ? */
1589 if (nIndex < hdsa->nItemCount - 1) {
1590 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
1591 lpSrc = (char *) lpDest + hdsa->nItemSize;
1592 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
1593 TRACE("-- move dest=%p src=%p size=%d\n",
1594 lpDest, lpSrc, nSize);
1595 memmove (lpDest, lpSrc, nSize);
1596 }
1597
1598 hdsa->nItemCount--;
1599
1600 /* free memory ? */
1601 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
1602 nSize = hdsa->nItemSize * hdsa->nItemCount;
1603
1604 lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
1605 if (!lpDest)
1606 return -1;
1607
1608 hdsa->nMaxCount = hdsa->nItemCount;
1609 hdsa->pData = lpDest;
1610 }
1611
1612 return nIndex;
1613}
1614
1615
1616/**************************************************************************
1617 * DSA_DeleteAllItems [COMCTL32.327]
1618 *
1619 * Removes all items and reinitializes the array.
1620 *
1621 * PARAMS
1622 * hdsa [I] pointer to the array control structure
1623 *
1624 * RETURNS
1625 * Success: TRUE
1626 * Failure: FALSE
1627 */
1628
1629BOOL WINAPI
1630DSA_DeleteAllItems (const HDSA hdsa)
1631{
1632 TRACE("(%p)\n", hdsa);
1633
1634 if (!hdsa)
1635 return FALSE;
1636 if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
1637 return FALSE;
1638
1639 hdsa->nItemCount = 0;
1640 hdsa->pData = NULL;
1641 hdsa->nMaxCount = 0;
1642
1643 return TRUE;
1644}
1645
1646
1647/**************************************************************************
1648 * The DPA-API is a set of functions to create and manipulate arrays of
1649 * pointers.
1650 */
1651
1652/**************************************************************************
1653 * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
1654 *
1655 * PARAMS
1656 * nGrow [I] number of items by which the array grows when it is filled
1657 *
1658 * RETURNS
1659 * Success: handle (pointer) to the pointer array.
1660 * Failure: NULL
1661 */
1662
1663HDPA WINAPI
1664DPA_Create (INT nGrow)
1665{
1666 HDPA hdpa;
1667
1668 TRACE("(%d)\n", nGrow);
1669
1670 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
1671 if (hdpa) {
1672 hdpa->nGrow = max(8, nGrow);
1673 hdpa->hHeap = COMCTL32_hHeap;
1674 hdpa->nMaxCount = hdpa->nGrow * 2;
1675 hdpa->ptrs =
1676 (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
1677 }
1678
1679 TRACE("-- %p\n", hdpa);
1680
1681 return hdpa;
1682}
1683
1684
1685/**************************************************************************
1686 * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
1687 *
1688 * PARAMS
1689 * hdpa [I] handle (pointer) to the pointer array
1690 *
1691 * RETURNS
1692 * Success: TRUE
1693 * Failure: FALSE
1694 */
1695
1696BOOL WINAPI
1697DPA_Destroy (const HDPA hdpa)
1698{
1699 TRACE("(%p)\n", hdpa);
1700
1701 if (!hdpa)
1702 return FALSE;
1703
1704 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
1705 return FALSE;
1706
1707 return HeapFree (hdpa->hHeap, 0, hdpa);
1708}
1709
1710
1711/**************************************************************************
1712 * DPA_Grow [COMCTL32.330]
1713 *
1714 * Sets the growth amount.
1715 *
1716 * PARAMS
1717 * hdpa [I] handle (pointer) to the existing (source) pointer array
1718 * nGrow [I] number of items by which the array grows when it's too small
1719 *
1720 * RETURNS
1721 * Success: TRUE
1722 * Failure: FALSE
1723 */
1724
1725BOOL WINAPI
1726DPA_Grow (const HDPA hdpa, INT nGrow)
1727{
1728 TRACE("(%p %d)\n", hdpa, nGrow);
1729
1730 if (!hdpa)
1731 return FALSE;
1732
1733 hdpa->nGrow = max(8, nGrow);
1734
1735 return TRUE;
1736}
1737
1738
1739/**************************************************************************
1740 * DPA_Clone [COMCTL32.331]
1741 *
1742 * Copies a pointer array to an other one or creates a copy
1743 *
1744 * PARAMS
1745 * hdpa [I] handle (pointer) to the existing (source) pointer array
1746 * hdpaNew [O] handle (pointer) to the destination pointer array
1747 *
1748 * RETURNS
1749 * Success: pointer to the destination pointer array.
1750 * Failure: NULL
1751 *
1752 * NOTES
1753 * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
1754 * array will be created and it's handle (pointer) is returned.
1755 * - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
1756 * this implementation just returns NULL.
1757 */
1758
1759HDPA WINAPI
1760DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
1761{
1762 INT nNewItems, nSize;
1763 HDPA hdpaTemp;
1764
1765 if (!hdpa)
1766 return NULL;
1767
1768 TRACE("(%p %p)\n", hdpa, hdpaNew);
1769
1770 if (!hdpaNew) {
1771 /* create a new DPA */
1772 hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
1773 sizeof(DPA));
1774 hdpaTemp->hHeap = hdpa->hHeap;
1775 hdpaTemp->nGrow = hdpa->nGrow;
1776 }
1777 else
1778 hdpaTemp = hdpaNew;
1779
1780 if (hdpaTemp->ptrs) {
1781 /* remove old pointer array */
1782 HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
1783 hdpaTemp->ptrs = NULL;
1784 hdpaTemp->nItemCount = 0;
1785 hdpaTemp->nMaxCount = 0;
1786 }
1787
1788 /* create a new pointer array */
1789 nNewItems = hdpaTemp->nGrow *
1790 ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
1791 nSize = nNewItems * sizeof(LPVOID);
1792 hdpaTemp->ptrs =
1793 (LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
1794 hdpaTemp->nMaxCount = nNewItems;
1795
1796 /* clone the pointer array */
1797 hdpaTemp->nItemCount = hdpa->nItemCount;
1798 memmove (hdpaTemp->ptrs, hdpa->ptrs,
1799 hdpaTemp->nItemCount * sizeof(LPVOID));
1800
1801 return hdpaTemp;
1802}
1803
1804
1805/**************************************************************************
1806 * DPA_GetPtr [COMCTL32.332]
1807 *
1808 * Retrieves a pointer from a dynamic pointer array
1809 *
1810 * PARAMS
1811 * hdpa [I] handle (pointer) to the pointer array
1812 * nIndex [I] array index of the desired pointer
1813 *
1814 * RETURNS
1815 * Success: pointer
1816 * Failure: NULL
1817 */
1818
1819LPVOID WINAPI
1820DPA_GetPtr (const HDPA hdpa, INT nIndex)
1821{
1822 TRACE("(%p %d)\n", hdpa, nIndex);
1823
1824 if (!hdpa)
1825 return NULL;
1826 if (!hdpa->ptrs) {
1827 WARN("no pointer array.\n");
1828 return NULL;
1829 }
1830 if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
1831 WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
1832 return NULL;
1833 }
1834
1835 TRACE("-- %p\n", hdpa->ptrs[nIndex]);
1836
1837 return hdpa->ptrs[nIndex];
1838}
1839
1840
1841/**************************************************************************
1842 * DPA_GetPtrIndex [COMCTL32.333]
1843 *
1844 * Retrieves the index of the specified pointer
1845 *
1846 * PARAMS
1847 * hdpa [I] handle (pointer) to the pointer array
1848 * p [I] pointer
1849 *
1850 * RETURNS
1851 * Success: index of the specified pointer
1852 * Failure: -1
1853 */
1854
1855INT WINAPI
1856DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
1857{
1858 INT i;
1859
1860 if (!hdpa || !hdpa->ptrs)
1861 return -1;
1862
1863 for (i = 0; i < hdpa->nItemCount; i++) {
1864 if (hdpa->ptrs[i] == p)
1865 return i;
1866 }
1867
1868 return -1;
1869}
1870
1871
1872/**************************************************************************
1873 * DPA_InsertPtr [COMCTL32.334]
1874 *
1875 * Inserts a pointer into a dynamic pointer array
1876 *
1877 * PARAMS
1878 * hdpa [I] handle (pointer) to the array
1879 * i [I] array index
1880 * p [I] pointer to insert
1881 *
1882 * RETURNS
1883 * Success: index of the inserted pointer
1884 * Failure: -1
1885 */
1886
1887INT WINAPI
1888DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
1889{
1890 TRACE("(%p %d %p)\n", hdpa, i, p);
1891
1892 if (!hdpa || i < 0) return -1;
1893
1894 if (i >= 0x7fff)
1895 i = hdpa->nItemCount;
1896
1897 if (i >= hdpa->nItemCount)
1898 return DPA_SetPtr(hdpa, i, p) ? i : -1;
1899
1900 /* create empty spot at the end */
1901 if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
1902 memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
1903 hdpa->ptrs[i] = p;
1904 return i;
1905}
1906
1907/**************************************************************************
1908 * DPA_SetPtr [COMCTL32.335]
1909 *
1910 * Sets a pointer in the pointer array
1911 *
1912 * PARAMS
1913 * hdpa [I] handle (pointer) to the pointer array
1914 * i [I] index of the pointer that will be set
1915 * p [I] pointer to be set
1916 *
1917 * RETURNS
1918 * Success: TRUE
1919 * Failure: FALSE
1920 */
1921
1922BOOL WINAPI
1923DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
1924{
1925 LPVOID *lpTemp;
1926
1927 TRACE("(%p %d %p)\n", hdpa, i, p);
1928
1929 if (!hdpa || i < 0 || i > 0x7fff)
1930 return FALSE;
1931
1932 if (hdpa->nItemCount <= i) {
1933 /* within the old array */
1934 if (hdpa->nMaxCount <= i) {
1935 /* resize the block of memory */
1936 INT nNewItems =
1937 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
1938 INT nSize = nNewItems * sizeof(LPVOID);
1939
1940 if (hdpa->ptrs)
1941 lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
1942 else
1943 lpTemp = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
1944
1945 if (!lpTemp)
1946 return FALSE;
1947
1948 hdpa->nMaxCount = nNewItems;
1949 hdpa->ptrs = lpTemp;
1950 }
1951 hdpa->nItemCount = i+1;
1952 }
1953
1954 /* put the new entry in */
1955 hdpa->ptrs[i] = p;
1956
1957 return TRUE;
1958}
1959
1960
1961/**************************************************************************
1962 * DPA_DeletePtr [COMCTL32.336]
1963 *
1964 * Removes a pointer from the pointer array.
1965 *
1966 * PARAMS
1967 * hdpa [I] handle (pointer) to the pointer array
1968 * i [I] index of the pointer that will be deleted
1969 *
1970 * RETURNS
1971 * Success: deleted pointer
1972 * Failure: NULL
1973 */
1974
1975LPVOID WINAPI
1976DPA_DeletePtr (const HDPA hdpa, INT i)
1977{
1978 LPVOID *lpDest, *lpSrc, lpTemp = NULL;
1979 INT nSize;
1980
1981 TRACE("(%p %d)\n", hdpa, i);
1982
1983 if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
1984 return NULL;
1985
1986 lpTemp = hdpa->ptrs[i];
1987
1988 /* do we need to move ?*/
1989 if (i < hdpa->nItemCount - 1) {
1990 lpDest = hdpa->ptrs + i;
1991 lpSrc = lpDest + 1;
1992 nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
1993 TRACE("-- move dest=%p src=%p size=%x\n",
1994 lpDest, lpSrc, nSize);
1995 memmove (lpDest, lpSrc, nSize);
1996 }
1997
1998 hdpa->nItemCount --;
1999
2000 /* free memory ?*/
2001 if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
2002 INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
2003 nSize = nNewItems * sizeof(LPVOID);
2004 lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2005 hdpa->ptrs, nSize);
2006 if (!lpDest)
2007 return NULL;
2008
2009 hdpa->nMaxCount = nNewItems;
2010 hdpa->ptrs = (LPVOID*)lpDest;
2011 }
2012
2013 return lpTemp;
2014}
2015
2016
2017/**************************************************************************
2018 * DPA_DeleteAllPtrs [COMCTL32.337]
2019 *
2020 * Removes all pointers and reinitializes the array.
2021 *
2022 * PARAMS
2023 * hdpa [I] handle (pointer) to the pointer array
2024 *
2025 * RETURNS
2026 * Success: TRUE
2027 * Failure: FALSE
2028 */
2029
2030BOOL WINAPI
2031DPA_DeleteAllPtrs (const HDPA hdpa)
2032{
2033 TRACE("(%p)\n", hdpa);
2034
2035 if (!hdpa)
2036 return FALSE;
2037
2038 if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
2039 return FALSE;
2040
2041 hdpa->nItemCount = 0;
2042 hdpa->nMaxCount = hdpa->nGrow * 2;
2043 hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
2044 hdpa->nMaxCount * sizeof(LPVOID));
2045
2046 return TRUE;
2047}
2048
2049
2050/**************************************************************************
2051 * DPA_QuickSort [Internal]
2052 *
2053 * Ordinary quicksort (used by DPA_Sort).
2054 *
2055 * PARAMS
2056 * lpPtrs [I] pointer to the pointer array
2057 * l [I] index of the "left border" of the partition
2058 * r [I] index of the "right border" of the partition
2059 * pfnCompare [I] pointer to the compare function
2060 * lParam [I] user defined value (3rd parameter in compare function)
2061 *
2062 * RETURNS
2063 * NONE
2064 */
2065
2066static VOID
2067DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
2068 PFNDPACOMPARE pfnCompare, LPARAM lParam)
2069{
2070 INT m;
2071 LPVOID t;
2072
2073 TRACE("l=%i r=%i\n", l, r);
2074
2075 if (l==r) /* one element is always sorted */
2076 return;
2077 if (r<l) /* oops, got it in the wrong order */
2078 {
2079 DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
2080 return;
2081 }
2082 m = (l+r)/2; /* divide by two */
2083 DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
2084 DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
2085
2086 /* join the two sides */
2087 while( (l<=m) && (m<r) )
2088 {
2089 if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
2090 {
2091 t = lpPtrs[m+1];
2092 memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof lpPtrs[l]);
2093 lpPtrs[l] = t;
2094
2095 m++;
2096 }
2097 l++;
2098 }
2099}
2100
2101
2102/**************************************************************************
2103 * DPA_Sort [COMCTL32.338]
2104 *
2105 * Sorts a pointer array using a user defined compare function
2106 *
2107 * PARAMS
2108 * hdpa [I] handle (pointer) to the pointer array
2109 * pfnCompare [I] pointer to the compare function
2110 * lParam [I] user defined value (3rd parameter of compare function)
2111 *
2112 * RETURNS
2113 * Success: TRUE
2114 * Failure: FALSE
2115 */
2116
2117BOOL WINAPI
2118DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
2119{
2120 if (!hdpa || !pfnCompare)
2121 return FALSE;
2122
2123 TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
2124
2125 if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
2126 DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
2127 pfnCompare, lParam);
2128
2129 return TRUE;
2130}
2131
2132
2133/**************************************************************************
2134 * DPA_Search [COMCTL32.339]
2135 *
2136 * Searches a pointer array for a specified pointer
2137 *
2138 * PARAMS
2139 * hdpa [I] handle (pointer) to the pointer array
2140 * pFind [I] pointer to search for
2141 * nStart [I] start index
2142 * pfnCompare [I] pointer to the compare function
2143 * lParam [I] user defined value (3rd parameter of compare function)
2144 * uOptions [I] search options
2145 *
2146 * RETURNS
2147 * Success: index of the pointer in the array.
2148 * Failure: -1
2149 *
2150 * NOTES
2151 * Binary search taken from R.Sedgewick "Algorithms in C"!
2152 * Function is NOT tested!
2153 * If something goes wrong, blame HIM not ME! (Eric Kohl)
2154 */
2155
2156INT WINAPI
2157DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
2158 PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
2159{
2160 if (!hdpa || !pfnCompare || !pFind)
2161 return -1;
2162
2163 TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
2164 hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
2165
2166 if (uOptions & DPAS_SORTED) {
2167 /* array is sorted --> use binary search */
2168 INT l, r, x, n;
2169 LPVOID *lpPtr;
2170
2171 TRACE("binary search\n");
2172
2173 l = (nStart == -1) ? 0 : nStart;
2174 r = hdpa->nItemCount - 1;
2175 lpPtr = hdpa->ptrs;
2176 while (r >= l) {
2177 x = (l + r) / 2;
2178 n = (pfnCompare)(pFind, lpPtr[x], lParam);
2179 if (n < 0)
2180 r = x - 1;
2181 else
2182 l = x + 1;
2183 if (n == 0) {
2184 TRACE("-- ret=%d\n", n);
2185 return n;
2186 }
2187 }
2188
2189 if (uOptions & DPAS_INSERTBEFORE) {
2190 TRACE("-- ret=%d\n", r);
2191 return r;
2192 }
2193
2194 if (uOptions & DPAS_INSERTAFTER) {
2195 TRACE("-- ret=%d\n", l);
2196 return l;
2197 }
2198 }
2199 else {
2200 /* array is not sorted --> use linear search */
2201 LPVOID *lpPtr;
2202 INT nIndex;
2203
2204 TRACE("linear search\n");
2205
2206 nIndex = (nStart == -1)? 0 : nStart;
2207 lpPtr = hdpa->ptrs;
2208 for (; nIndex < hdpa->nItemCount; nIndex++) {
2209 if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
2210 TRACE("-- ret=%d\n", nIndex);
2211 return nIndex;
2212 }
2213 }
2214 }
2215
2216 TRACE("-- not found: ret=-1\n");
2217 return -1;
2218}
2219
2220
2221/**************************************************************************
2222 * DPA_CreateEx [COMCTL32.340]
2223 *
2224 * Creates a dynamic pointer array using the specified size and heap.
2225 *
2226 * PARAMS
2227 * nGrow [I] number of items by which the array grows when it is filled
2228 * hHeap [I] handle to the heap where the array is stored
2229 *
2230 * RETURNS
2231 * Success: handle (pointer) to the pointer array.
2232 * Failure: NULL
2233 */
2234
2235HDPA WINAPI
2236DPA_CreateEx (INT nGrow, HANDLE hHeap)
2237{
2238 HDPA hdpa;
2239
2240 TRACE("(%d %p)\n", nGrow, hHeap);
2241
2242 if (hHeap)
2243 hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
2244 else
2245 hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
2246
2247 if (hdpa) {
2248 hdpa->nGrow = min(8, nGrow);
2249 hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
2250 hdpa->nMaxCount = hdpa->nGrow * 2;
2251 hdpa->ptrs =
2252 (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
2253 hdpa->nMaxCount * sizeof(LPVOID));
2254 }
2255
2256 TRACE("-- %p\n", hdpa);
2257
2258 return hdpa;
2259}
2260
2261
2262/**************************************************************************
2263 * Notification functions
2264 */
2265
2266typedef struct tagNOTIFYDATA
2267{
2268 HWND hwndFrom;
2269 HWND hwndTo;
2270 DWORD dwParam3;
2271 DWORD dwParam4;
2272 DWORD dwParam5;
2273 DWORD dwParam6;
2274} NOTIFYDATA, *LPNOTIFYDATA;
2275
2276
2277/**************************************************************************
2278 * DoNotify [Internal]
2279 */
2280
2281static LRESULT
2282DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
2283{
2284 NMHDR nmhdr;
2285 LPNMHDR lpNmh = NULL;
2286 UINT idFrom = 0;
2287
2288 TRACE("(%p %p %d %p 0x%08lx)\n",
2289 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
2290 lpNotify->dwParam5);
2291
2292 if (!lpNotify->hwndTo)
2293 return 0;
2294
2295 if (lpNotify->hwndFrom == (HWND)-1) {
2296 lpNmh = lpHdr;
2297 idFrom = lpHdr->idFrom;
2298 }
2299 else {
2300 if (lpNotify->hwndFrom) {
2301 HWND hwndParent = GetParent (lpNotify->hwndFrom);
2302 if (hwndParent) {
2303 hwndParent = GetWindow (lpNotify->hwndFrom, GW_OWNER);
2304 /* the following is done even if the return from above
2305 * is zero. GLA 12/2001 */
2306 idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
2307 }
2308 }
2309
2310 lpNmh = (lpHdr) ? lpHdr : &nmhdr;
2311
2312 lpNmh->hwndFrom = lpNotify->hwndFrom;
2313 lpNmh->idFrom = idFrom;
2314 lpNmh->code = uCode;
2315 }
2316
2317 return SendMessageA (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
2318}
2319
2320
2321/**************************************************************************
2322 * SendNotify [COMCTL32.341]
2323 *
2324 * PARAMS
2325 * hwndTo [I]
2326 * hwndFrom [I]
2327 * uCode [I]
2328 * lpHdr [I]
2329 *
2330 * RETURNS
2331 * Success: return value from notification
2332 * Failure: 0
2333 */
2334
2335LRESULT WINAPI
2336COMCTL32_SendNotify (HWND hwndTo, HWND hwndFrom,
2337 UINT uCode, LPNMHDR lpHdr)
2338{
2339 NOTIFYDATA notify;
2340
2341 TRACE("(%p %p %d %p)\n",
2342 hwndTo, hwndFrom, uCode, lpHdr);
2343
2344 notify.hwndFrom = hwndFrom;
2345 notify.hwndTo = hwndTo;
2346 notify.dwParam5 = 0;
2347 notify.dwParam6 = 0;
2348
2349 return DoNotify (&notify, uCode, lpHdr);
2350}
2351
2352
2353/**************************************************************************
2354 * SendNotifyEx [COMCTL32.342]
2355 *
2356 * PARAMS
2357 * hwndFrom [I]
2358 * hwndTo [I]
2359 * uCode [I]
2360 * lpHdr [I]
2361 * dwParam5 [I]
2362 *
2363 * RETURNS
2364 * Success: return value from notification
2365 * Failure: 0
2366 */
2367
2368LRESULT WINAPI
2369COMCTL32_SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
2370 LPNMHDR lpHdr, DWORD dwParam5)
2371{
2372 NOTIFYDATA notify;
2373 HWND hwndNotify;
2374
2375 TRACE("(%p %p %d %p 0x%08lx)\n",
2376 hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
2377
2378 hwndNotify = hwndTo;
2379 if (!hwndTo) {
2380 if (IsWindow (hwndFrom)) {
2381 hwndNotify = GetParent (hwndFrom);
2382 if (!hwndNotify)
2383 return 0;
2384 }
2385 }
2386
2387 notify.hwndFrom = hwndFrom;
2388 notify.hwndTo = hwndNotify;
2389 notify.dwParam5 = dwParam5;
2390 notify.dwParam6 = 0;
2391
2392 return DoNotify (&notify, uCode, lpHdr);
2393}
2394
2395
2396/**************************************************************************
2397 * StrChrA [COMCTL32.350]
2398 *
2399 */
2400
2401LPSTR WINAPI
2402COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
2403{
2404 return strchr (lpString, cChar);
2405}
2406
2407
2408/**************************************************************************
2409 * StrStrIA [COMCTL32.355]
2410 */
2411
2412LPSTR WINAPI
2413COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
2414{
2415 INT len1, len2, i;
2416 CHAR first;
2417
2418 if (*lpStr2 == 0)
2419 return ((LPSTR)lpStr1);
2420 len1 = 0;
2421 while (lpStr1[len1] != 0) ++len1;
2422 len2 = 0;
2423 while (lpStr2[len2] != 0) ++len2;
2424 if (len2 == 0)
2425 return ((LPSTR)(lpStr1 + len1));
2426 first = tolower (*lpStr2);
2427 while (len1 >= len2) {
2428 if (tolower(*lpStr1) == first) {
2429 for (i = 1; i < len2; ++i)
2430 if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
2431 break;
2432 if (i >= len2)
2433 return ((LPSTR)lpStr1);
2434 }
2435 ++lpStr1; --len1;
2436 }
2437 return (NULL);
2438}
2439
2440/**************************************************************************
2441 * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
2442 */
2443
2444INT WINAPI
2445COMCTL32_StrToIntA (LPSTR lpString)
2446{
2447 return atoi(lpString);
2448}
2449
2450/**************************************************************************
2451 * StrStrIW [COMCTL32.363]
2452 */
2453
2454LPWSTR WINAPI
2455COMCTL32_StrStrIW (LPCWSTR lpStr1, LPCWSTR lpStr2)
2456{
2457 INT len1, len2, i;
2458 WCHAR first;
2459
2460 if (*lpStr2 == 0)
2461 return ((LPWSTR)lpStr1);
2462 len1 = 0;
2463 while (lpStr1[len1] != 0) ++len1;
2464 len2 = 0;
2465 while (lpStr2[len2] != 0) ++len2;
2466 if (len2 == 0)
2467 return ((LPWSTR)(lpStr1 + len1));
2468 first = tolowerW (*lpStr2);
2469 while (len1 >= len2) {
2470 if (tolowerW (*lpStr1) == first) {
2471 for (i = 1; i < len2; ++i)
2472 if (tolowerW (lpStr1[i]) != tolowerW(lpStr2[i]))
2473 break;
2474 if (i >= len2)
2475 return ((LPWSTR)lpStr1);
2476 }
2477 ++lpStr1; --len1;
2478 }
2479 return (NULL);
2480}
2481
2482/**************************************************************************
2483 * StrToIntW [COMCTL32.365] Converts a wide char string to a signed integer.
2484 */
2485
2486INT WINAPI
2487COMCTL32_StrToIntW (LPWSTR lpString)
2488{
2489 return atoiW(lpString);
2490}
2491
2492
2493/**************************************************************************
2494 * DPA_EnumCallback [COMCTL32.385]
2495 *
2496 * Enumerates all items in a dynamic pointer array.
2497 *
2498 * PARAMS
2499 * hdpa [I] handle to the dynamic pointer array
2500 * enumProc [I]
2501 * lParam [I]
2502 *
2503 * RETURNS
2504 * none
2505 */
2506
2507VOID WINAPI
2508DPA_EnumCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2509{
2510 INT i;
2511
2512 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2513
2514 if (!hdpa)
2515 return;
2516 if (hdpa->nItemCount <= 0)
2517 return;
2518
2519 for (i = 0; i < hdpa->nItemCount; i++) {
2520 if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
2521 return;
2522 }
2523
2524 return;
2525}
2526
2527
2528/**************************************************************************
2529 * DPA_DestroyCallback [COMCTL32.386]
2530 *
2531 * Enumerates all items in a dynamic pointer array and destroys it.
2532 *
2533 * PARAMS
2534 * hdpa [I] handle to the dynamic pointer array
2535 * enumProc [I]
2536 * lParam [I]
2537 *
2538 * RETURNS
2539 * Success: TRUE
2540 * Failure: FALSE
2541 */
2542
2543BOOL WINAPI
2544DPA_DestroyCallback (const HDPA hdpa, DPAENUMPROC enumProc, LPARAM lParam)
2545{
2546 TRACE("(%p %p %08lx)\n", hdpa, enumProc, lParam);
2547
2548 DPA_EnumCallback (hdpa, enumProc, lParam);
2549
2550 return DPA_Destroy (hdpa);
2551}
2552
2553
2554/**************************************************************************
2555 * DSA_EnumCallback [COMCTL32.387]
2556 *
2557 * Enumerates all items in a dynamic storage array.
2558 *
2559 * PARAMS
2560 * hdsa [I] handle to the dynamic storage array
2561 * enumProc [I]
2562 * lParam [I]
2563 *
2564 * RETURNS
2565 * none
2566 */
2567
2568VOID WINAPI
2569DSA_EnumCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2570{
2571 INT i;
2572
2573 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2574
2575 if (!hdsa)
2576 return;
2577 if (hdsa->nItemCount <= 0)
2578 return;
2579
2580 for (i = 0; i < hdsa->nItemCount; i++) {
2581 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
2582 if ((enumProc)(lpItem, lParam) == 0)
2583 return;
2584 }
2585
2586 return;
2587}
2588
2589
2590/**************************************************************************
2591 * DSA_DestroyCallback [COMCTL32.388]
2592 *
2593 * Enumerates all items in a dynamic storage array and destroys it.
2594 *
2595 * PARAMS
2596 * hdsa [I] handle to the dynamic storage array
2597 * enumProc [I]
2598 * lParam [I]
2599 *
2600 * RETURNS
2601 * Success: TRUE
2602 * Failure: FALSE
2603 */
2604
2605BOOL WINAPI
2606DSA_DestroyCallback (const HDSA hdsa, DSAENUMPROC enumProc, LPARAM lParam)
2607{
2608 TRACE("(%p %p %08lx)\n", hdsa, enumProc, lParam);
2609
2610 DSA_EnumCallback (hdsa, enumProc, lParam);
2611
2612 return DSA_Destroy (hdsa);
2613}
2614
2615/**************************************************************************
2616 * StrCSpnA [COMCTL32.356]
2617 *
2618 */
2619INT WINAPI COMCTL32_StrCSpnA( LPCSTR lpStr, LPCSTR lpSet) {
2620 return strcspn(lpStr, lpSet);
2621}
2622
2623/**************************************************************************
2624 * StrChrW [COMCTL32.358]
2625 *
2626 */
2627LPWSTR WINAPI COMCTL32_StrChrW( LPCWSTR lpStart, WORD wMatch) {
2628 return strchrW(lpStart, wMatch);
2629}
2630
2631/**************************************************************************
2632 * StrCmpNA [COMCTL32.352]
2633 *
2634 */
2635INT WINAPI COMCTL32_StrCmpNA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2636 return strncmp(lpStr1, lpStr2, nChar);
2637}
2638
2639/**************************************************************************
2640 * StrCmpNIA [COMCTL32.353]
2641 *
2642 */
2643INT WINAPI COMCTL32_StrCmpNIA( LPCSTR lpStr1, LPCSTR lpStr2, int nChar) {
2644 return strncasecmp(lpStr1, lpStr2, nChar);
2645}
2646
2647/**************************************************************************
2648 * StrCmpNW [COMCTL32.360]
2649 *
2650 */
2651INT WINAPI COMCTL32_StrCmpNW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2652 return strncmpW(lpStr1, lpStr2, nChar);
2653}
2654
2655/**************************************************************************
2656 * StrCmpNIW [COMCTL32.361]
2657 *
2658 */
2659INT WINAPI COMCTL32_StrCmpNIW( LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar) {
2660 FIXME("(%s, %s, %i): stub\n", debugstr_w(lpStr1), debugstr_w(lpStr2), nChar);
2661 return 0;
2662}
2663
2664/**************************************************************************
2665 * StrRChrA [COMCTL32.351]
2666 *
2667 */
2668LPSTR WINAPI COMCTL32_StrRChrA( LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch )
2669{
2670 LPCSTR lpGotIt = NULL;
2671 BOOL dbcs = IsDBCSLeadByte( LOBYTE(wMatch) );
2672
2673 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2674
2675 if (!lpEnd) lpEnd = lpStart + strlen(lpStart);
2676
2677 for(; lpStart < lpEnd; lpStart = CharNextA(lpStart))
2678 {
2679 if (*lpStart != LOBYTE(wMatch)) continue;
2680 if (dbcs && lpStart[1] != HIBYTE(wMatch)) continue;
2681 lpGotIt = lpStart;
2682 }
2683 return (LPSTR)lpGotIt;
2684}
2685
2686
2687/**************************************************************************
2688 * StrRChrW [COMCTL32.359]
2689 *
2690 */
2691LPWSTR WINAPI COMCTL32_StrRChrW( LPCWSTR lpStart, LPCWSTR lpEnd, WORD wMatch)
2692{
2693 LPCWSTR lpGotIt = NULL;
2694
2695 TRACE("(%p, %p, %x)\n", lpStart, lpEnd, wMatch);
2696 if (!lpEnd) lpEnd = lpStart + strlenW(lpStart);
2697
2698 for(; lpStart < lpEnd; lpStart = CharNextW(lpStart))
2699 if (*lpStart == wMatch) lpGotIt = lpStart;
2700
2701 return (LPWSTR)lpGotIt;
2702}
2703
2704
2705/**************************************************************************
2706 * StrStrA [COMCTL32.354]
2707 *
2708 */
2709LPSTR WINAPI COMCTL32_StrStrA( LPCSTR lpFirst, LPCSTR lpSrch) {
2710 return strstr(lpFirst, lpSrch);
2711}
2712
2713/**************************************************************************
2714 * StrStrW [COMCTL32.362]
2715 *
2716 */
2717LPWSTR WINAPI COMCTL32_StrStrW( LPCWSTR lpFirst, LPCWSTR lpSrch) {
2718 return strstrW(lpFirst, lpSrch);
2719}
2720
2721/**************************************************************************
2722 * StrSpnW [COMCTL32.364]
2723 *
2724 */
2725INT WINAPI COMCTL32_StrSpnW( LPWSTR lpStr, LPWSTR lpSet) {
2726 LPWSTR lpLoop = lpStr;
2727
2728 /* validate ptr */
2729 if ((lpStr == 0) || (lpSet == 0)) return 0;
2730
2731/* while(*lpLoop) { if lpLoop++; } */
2732
2733 for(; (*lpLoop != 0); lpLoop++)
2734 if( strchrW(lpSet, *(WORD*)lpLoop))
2735 return (INT)(lpLoop-lpStr);
2736
2737 return (INT)(lpLoop-lpStr);
2738}
2739
2740/**************************************************************************
2741 * @ [COMCTL32.415]
2742 *
2743 * FIXME: What's this supposed to do?
2744 * Parameter 1 is an HWND, you're on your own for the rest.
2745 */
2746
2747BOOL WINAPI COMCTL32_415( HWND hwnd, DWORD b, DWORD c, DWORD d, DWORD e)
2748{
2749
2750 FIXME("(%p, %lx, %lx, %lx, %lx): stub!\n", hwnd, b, c, d, e);
2751
2752 return TRUE;
2753}
2754
2755/**************************************************************************
2756 * @ [COMCTL32.417]
2757 *
2758 */
2759BOOL WINAPI COMCTL32_417(HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
2760 LPCWSTR str, UINT count, const INT *lpDx)
2761{
2762 return ExtTextOutW(hdc, x, y, flags, lprect, str, count, lpDx);
2763}
2764
2765/**************************************************************************
2766 * @ [COMCTL32.419]
2767 *
2768 * FIXME: What's this supposed to do?
2769 */
2770
2771BOOL WINAPI COMCTL32_419( DWORD a, DWORD b, DWORD c, DWORD d)
2772{
2773
2774 FIXME("(%lx, %lx, %lx, %lx): stub!\n", a, b, c, d);
2775
2776 return TRUE;
2777}
Note: See TracBrowser for help on using the repository browser.