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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 */ 29 30 #include <stdarg.h> 31 #include <string.h> 32 #include <ctype.h> 33 #include <limits.h> 34 35 #define COBJMACROS 36 #define NONAMELESSUNION 37 38 #include "windef.h" 39 #include "winbase.h" 40 #include "wingdi.h" 41 #include "winuser.h" 42 #include "winnls.h" 43 #include "winreg.h" 44 #include "commctrl.h" 45 #include "objbase.h" 46 #include "winerror.h" 47 48 #include "comctl32.h" 49 50 #include "wine/debug.h" 51 52 WINE_DEFAULT_DEBUG_CHANNEL(commctrl); 53 54 static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 }; 55 56 /************************************************************************** 57 * Alloc [COMCTL32.71] 58 * 59 * Allocates memory block from the dll's private heap 60 * 61 * PARAMS 62 * dwSize [I] size of the allocated memory block 63 * 64 * RETURNS 65 * Success: pointer to allocated memory block 66 * Failure: NULL 67 */ 68 LPVOID WINAPI Alloc (DWORD dwSize) 69 { 70 return LocalAlloc( LMEM_ZEROINIT, dwSize ); 71 } 72 73 74 /************************************************************************** 75 * ReAlloc [COMCTL32.72] 76 * 77 * Changes the size of an allocated memory block or allocates a memory 78 * block using the dll's private heap. 79 * 80 * PARAMS 81 * lpSrc [I] pointer to memory block which will be resized 82 * dwSize [I] new size of the memory block. 83 * 84 * RETURNS 85 * Success: pointer to the resized memory block 86 * Failure: NULL 87 * 88 * NOTES 89 * If lpSrc is a NULL-pointer, then ReAlloc allocates a memory 90 * block like Alloc. 91 */ 92 LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize) 93 { 94 if (lpSrc) 95 return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT | LMEM_MOVEABLE ); 96 else 97 return LocalAlloc( LMEM_ZEROINIT, dwSize); 98 } 99 100 101 /************************************************************************** 102 * Free [COMCTL32.73] 103 * 104 * Frees an allocated memory block from the dll's private heap. 105 * 106 * PARAMS 107 * lpMem [I] pointer to memory block which will be freed 108 * 109 * RETURNS 110 * Success: TRUE 111 * Failure: FALSE 112 */ 113 BOOL WINAPI Free (LPVOID lpMem) 114 { 115 return !LocalFree( lpMem ); 116 } 117 118 119 /************************************************************************** 120 * GetSize [COMCTL32.74] 121 * 122 * Retrieves the size of the specified memory block from the dll's 123 * private heap. 124 * 125 * PARAMS 126 * lpMem [I] pointer to an allocated memory block 127 * 128 * RETURNS 129 * Success: size of the specified memory block 130 * Failure: 0 131 */ 132 DWORD WINAPI GetSize (LPVOID lpMem) 133 { 134 return LocalSize( lpMem ); 135 } 136 137 138 /************************************************************************** 139 * MRU-Functions {COMCTL32} 140 * 141 * NOTES 142 * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently 143 * Used) items. It is an undocumented API that is used (at least) by the shell 144 * and explorer to implement their recent documents feature. 145 * 146 * Since these functions are undocumented, they are unsupported by MS and 147 * may change at any time. 148 * 149 * Internally, the list is implemented as a last in, last out list of items 150 * persisted into the system registry under a caller chosen key. Each list 151 * item is given a one character identifier in the Ascii range from 'a' to 152 * '}'. A list of the identifiers in order from newest to oldest is stored 153 * under the same key in a value named "MRUList". 154 * 155 * Items are re-ordered by changing the order of the values in the MRUList 156 * value. When a new item is added, it becomes the new value of the oldest 157 * identifier, and that identifier is moved to the front of the MRUList value. 158 * 159 * Wine stores MRU-lists in the same registry format as Windows, so when 160 * switching between the builtin and native comctl32.dll no problems or 161 * incompatibilities should occur. 162 * 163 * The following undocumented structure is used to create an MRU-list: 164 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs); 165 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); 166 *| 167 *|typedef struct tagMRUINFO 168 *|{ 169 *| DWORD cbSize; 170 *| UINT uMax; 171 *| UINT fFlags; 172 *| HKEY hKey; 173 *| LPTSTR lpszSubKey; 174 *| PROC lpfnCompare; 175 *|} MRUINFO, *LPMRUINFO; 176 * 177 * MEMBERS 178 * cbSize [I] The size of the MRUINFO structure. This must be set 179 * to sizeof(MRUINFO) by the caller. 180 * uMax [I] The maximum number of items allowed in the list. Because 181 * of the limited number of identifiers, this should be set to 182 * a value from 1 to 30 by the caller. 183 * fFlags [I] If bit 0 is set, the list will be used to store binary 184 * data, otherwise it is assumed to store strings. If bit 1 185 * is set, every change made to the list will be reflected in 186 * the registry immediately, otherwise changes will only be 187 * written when the list is closed. 188 * hKey [I] The registry key that the list should be written under. 189 * This must be supplied by the caller. 190 * lpszSubKey [I] A caller supplied name of a subkey under hKey to write 191 * the list to. This may not be blank. 192 * lpfnCompare [I] A caller supplied comparison function, which may be either 193 * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a 194 * MRUBinaryCmpFn otherwise. 195 * 196 * FUNCTIONS 197 * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy(). 198 * - Add items to an MRU-list with AddMRUString() or AddMRUData(). 199 * - Remove items from an MRU-list with DelMRUString(). 200 * - Find data in an MRU-list with FindMRUString() or FindMRUData(). 201 * - Iterate through an MRU-list with EnumMRUList(). 202 * - Free an MRU-list with FreeMRUList(). 203 */ 204 205 typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs); 206 typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs); 207 typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); 208 209 typedef struct tagMRUINFOA 210 { 211 DWORD cbSize; 212 UINT uMax; 213 UINT fFlags; 214 HKEY hKey; 215 LPSTR lpszSubKey; 216 union 217 { 218 MRUStringCmpFnA string_cmpfn; 219 MRUBinaryCmpFn binary_cmpfn; 220 } u; 221 } MRUINFOA, *LPMRUINFOA; 222 223 typedef struct tagMRUINFOW 224 { 225 DWORD cbSize; 226 UINT uMax; 227 UINT fFlags; 228 HKEY hKey; 229 LPWSTR lpszSubKey; 230 union 231 { 232 MRUStringCmpFnW string_cmpfn; 233 MRUBinaryCmpFn binary_cmpfn; 234 } u; 235 } MRUINFOW, *LPMRUINFOW; 236 237 /* MRUINFO.fFlags */ 238 #define MRU_STRING 0 /* list will contain strings */ 239 #define MRU_BINARY 1 /* list will contain binary data */ 240 #define MRU_CACHEWRITE 2 /* only save list order to reg. is FreeMRUList */ 241 242 /* If list is a string list lpfnCompare has the following prototype 243 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) 244 * for binary lists the prototype is 245 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) 246 * where cbData is the no. of bytes to compare. 247 * Need to check what return value means identical - 0? 248 */ 249 250 typedef struct tagWINEMRUITEM 251 { 252 DWORD size; /* size of data stored */ 253 DWORD itemFlag; /* flags */ 254 BYTE datastart; 255 } WINEMRUITEM, *LPWINEMRUITEM; 256 257 /* itemFlag */ 258 #define WMRUIF_CHANGED 0x0001 /* this dataitem changed */ 259 260 typedef struct tagWINEMRULIST 261 { 262 MRUINFOW extview; /* original create information */ 263 BOOL isUnicode; /* is compare fn Unicode */ 264 DWORD wineFlags; /* internal flags */ 265 DWORD cursize; /* current size of realMRU */ 266 LPWSTR realMRU; /* pointer to string of index names */ 267 LPWINEMRUITEM *array; /* array of pointers to data */ 268 /* in 'a' to 'z' order */ 269 } WINEMRULIST, *LPWINEMRULIST; 270 271 /* wineFlags */ 272 #define WMRUF_CHANGED 0x0001 /* MRU list has changed */ 273 274 /************************************************************************** 275 * MRU_SaveChanged (internal) 276 * 277 * Local MRU saving code 278 */ 279 static void MRU_SaveChanged ( LPWINEMRULIST mp ) 280 { 281 UINT i, err; 282 HKEY newkey; 283 WCHAR realname[2]; 284 LPWINEMRUITEM witem; 285 286 /* or should we do the following instead of RegOpenKeyEx: 287 */ 288 289 /* open the sub key */ 290 if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 291 0, KEY_WRITE, &newkey))) { 292 /* not present - what to do ??? */ 293 ERR("Could not open key, error=%d, attempting to create\n", 294 err); 295 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 296 0, 297 NULL, 298 REG_OPTION_NON_VOLATILE, 299 KEY_READ | KEY_WRITE, 300 0, 301 &newkey, 302 0))) { 303 ERR("failed to create key /%s/, err=%d\n", 304 debugstr_w(mp->extview.lpszSubKey), err); 305 return; 306 } 307 } 308 if (mp->wineFlags & WMRUF_CHANGED) { 309 mp->wineFlags &= ~WMRUF_CHANGED; 310 err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU, 311 (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR)); 312 if (err) { 313 ERR("error saving MRUList, err=%d\n", err); 314 } 315 TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU)); 316 } 317 realname[1] = 0; 318 for(i=0; i<mp->cursize; i++) { 319 witem = mp->array[i]; 320 if (witem->itemFlag & WMRUIF_CHANGED) { 321 witem->itemFlag &= ~WMRUIF_CHANGED; 322 realname[0] = 'a' + i; 323 err = RegSetValueExW(newkey, realname, 0, 324 (mp->extview.fFlags & MRU_BINARY) ? 325 REG_BINARY : REG_SZ, 326 &witem->datastart, witem->size); 327 if (err) { 328 ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err); 329 } 330 TRACE("saving value for name /%s/ size=%d\n", 331 debugstr_w(realname), witem->size); 332 } 333 } 334 RegCloseKey( newkey ); 335 } 336 337 /************************************************************************** 338 * FreeMRUList [COMCTL32.152] 339 * 340 * Frees a most-recently-used items list. 341 * 342 * PARAMS 343 * hMRUList [I] Handle to list. 344 * 345 * RETURNS 346 * Nothing. 347 */ 348 void WINAPI FreeMRUList (HANDLE hMRUList) 349 { 350 LPWINEMRULIST mp = hMRUList; 351 UINT i; 352 353 TRACE("(%p)\n", hMRUList); 354 if (!hMRUList) 355 return; 356 357 if (mp->wineFlags & WMRUF_CHANGED) { 358 /* need to open key and then save the info */ 359 MRU_SaveChanged( mp ); 360 } 361 362 for(i=0; i<mp->extview.uMax; i++) 363 Free(mp->array[i]); 364 365 Free(mp->realMRU); 366 Free(mp->array); 367 Free(mp->extview.lpszSubKey); 368 Free(mp); 369 } 370 371 372 /************************************************************************** 373 * FindMRUData [COMCTL32.169] 374 * 375 * Searches binary list for item that matches lpData of length cbData. 376 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value 377 * corresponding to item's reg. name will be stored in it ('a' -> 0). 378 * 379 * PARAMS 380 * hList [I] list handle 381 * lpData [I] data to find 382 * cbData [I] length of data 383 * lpRegNum [O] position in registry (maybe NULL) 384 * 385 * RETURNS 386 * Position in list 0 -> MRU. -1 if item not found. 387 */ 388 INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, 389 LPINT lpRegNum) 390 { 391 const WINEMRULIST *mp = hList; 392 INT ret; 393 UINT i; 394 LPSTR dataA = NULL; 395 396 if (!mp || !mp->extview.u.string_cmpfn) 397 return -1; 398 399 if(!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode) { 400 DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1, 401 NULL, 0, NULL, NULL); 402 dataA = Alloc(len); 403 WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL); 404 } 405 406 for(i=0; i<mp->cursize; i++) { 407 if (mp->extview.fFlags & MRU_BINARY) { 408 if (!mp->extview.u.binary_cmpfn(lpData, &mp->array[i]->datastart, cbData)) 409 break; 410 } 411 else { 412 if(mp->isUnicode) { 413 if (!mp->extview.u.string_cmpfn(lpData, (LPWSTR)&mp->array[i]->datastart)) 414 break; 415 } else { 416 DWORD len = WideCharToMultiByte(CP_ACP, 0, 417 (LPWSTR)&mp->array[i]->datastart, -1, 418 NULL, 0, NULL, NULL); 419 LPSTR itemA = Alloc(len); 420 INT cmp; 421 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, 422 itemA, len, NULL, NULL); 423 424 cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA); 425 Free(itemA); 426 if(!cmp) 427 break; 428 } 429 } 430 } 431 Free(dataA); 432 if (i < mp->cursize) 433 ret = i; 434 else 435 ret = -1; 436 if (lpRegNum && (ret != -1)) 437 *lpRegNum = 'a' + i; 438 439 TRACE("(%p, %p, %d, %p) returning %d\n", 440 hList, lpData, cbData, lpRegNum, ret); 441 442 return ret; 443 } 444 445 446 /************************************************************************** 447 * AddMRUData [COMCTL32.167] 448 * 449 * Add item to MRU binary list. If item already exists in list then it is 450 * simply moved up to the top of the list and not added again. If list is 451 * full then the least recently used item is removed to make room. 452 * 453 * PARAMS 454 * hList [I] Handle to list. 455 * lpData [I] ptr to data to add. 456 * cbData [I] no. of bytes of data. 457 * 458 * RETURNS 459 * No. corresponding to registry name where value is stored 'a' -> 0 etc. 460 * -1 on error. 461 */ 462 INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData) 463 { 464 LPWINEMRULIST mp = hList; 465 LPWINEMRUITEM witem; 466 INT i, replace; 467 468 if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) { 469 /* Item exists, just move it to the front */ 470 LPWSTR pos = wcschr(mp->realMRU, replace + 'a'); 471 while (pos > mp->realMRU) 472 { 473 pos[0] = pos[-1]; 474 pos--; 475 } 476 } 477 else { 478 /* either add a new entry or replace oldest */ 479 if (mp->cursize < mp->extview.uMax) { 480 /* Add in a new item */ 481 replace = mp->cursize; 482 mp->cursize++; 483 } 484 else { 485 /* get the oldest entry and replace data */ 486 replace = mp->realMRU[mp->cursize - 1] - 'a'; 487 Free(mp->array[replace]); 488 } 489 490 /* Allocate space for new item and move in the data */ 491 mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM)); 492 witem->itemFlag |= WMRUIF_CHANGED; 493 witem->size = cbData; 494 memcpy( &witem->datastart, lpData, cbData); 495 496 /* now rotate MRU list */ 497 for(i=mp->cursize-1; i>=1; i--) 498 mp->realMRU[i] = mp->realMRU[i-1]; 499 } 500 501 /* The new item gets the front spot */ 502 mp->wineFlags |= WMRUF_CHANGED; 503 mp->realMRU[0] = replace + 'a'; 504 505 TRACE("(%p, %p, %d) adding data, /%c/ now most current\n", 506 hList, lpData, cbData, replace+'a'); 507 508 if (!(mp->extview.fFlags & MRU_CACHEWRITE)) { 509 /* save changed stuff right now */ 510 MRU_SaveChanged( mp ); 511 } 512 513 return replace; 514 } 515 516 /************************************************************************** 517 * AddMRUStringW [COMCTL32.401] 518 * 519 * Add an item to an MRU string list. 520 * 521 * PARAMS 522 * hList [I] Handle to list. 523 * lpszString [I] The string to add. 524 * 525 * RETURNS 526 * Success: The number corresponding to the registry name where the string 527 * has been stored (0 maps to 'a', 1 to 'b' and so on). 528 * Failure: -1, if hList is NULL or memory allocation fails. If lpszString 529 * is invalid, the function returns 0, and GetLastError() returns 530 * ERROR_INVALID_PARAMETER. The last error value is set only in 531 * this case. 532 * 533 * NOTES 534 * -If lpszString exists in the list already, it is moved to the top of the 535 * MRU list (it is not duplicated). 536 * -If the list is full the least recently used list entry is replaced with 537 * lpszString. 538 * -If this function returns 0 you should check the last error value to 539 * ensure the call really succeeded. 540 */ 541 INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString) 542 { 543 TRACE("(%p,%s)\n", hList, debugstr_w(lpszString)); 544 545 if (!hList) 546 return -1; 547 548 if (!lpszString || IsBadStringPtrW(lpszString, -1)) 549 { 550 SetLastError(ERROR_INVALID_PARAMETER); 551 return 0; 552 } 553 554 return AddMRUData(hList, lpszString, 555 (lstrlenW(lpszString) + 1) * sizeof(WCHAR)); 556 } 557 558 /************************************************************************** 559 * AddMRUStringA [COMCTL32.153] 560 * 561 * See AddMRUStringW. 562 */ 563 INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString) 564 { 565 DWORD len; 566 LPWSTR stringW; 567 INT ret; 568 569 TRACE("(%p,%s)\n", hList, debugstr_a(lpszString)); 570 571 if (!hList) 572 return -1; 573 574 if (IsBadStringPtrA(lpszString, -1)) 575 { 576 SetLastError(ERROR_INVALID_PARAMETER); 577 return 0; 578 } 579 580 len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR); 581 stringW = Alloc(len); 582 if (!stringW) 583 return -1; 584 585 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len/sizeof(WCHAR)); 586 ret = AddMRUData(hList, stringW, len); 587 Free(stringW); 588 return ret; 589 } 590 591 /************************************************************************** 592 * DelMRUString [COMCTL32.156] 593 * 594 * Removes item from either string or binary list (despite its name) 595 * 596 * PARAMS 597 * hList [I] list handle 598 * nItemPos [I] item position to remove 0 -> MRU 599 * 600 * RETURNS 601 * TRUE if successful, FALSE if nItemPos is out of range. 602 */ 603 BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos) 604 { 605 FIXME("(%p, %d): stub\n", hList, nItemPos); 606 return TRUE; 607 } 608 609 /************************************************************************** 610 * FindMRUStringW [COMCTL32.402] 611 * 612 * See FindMRUStringA. 613 */ 614 INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum) 615 { 616 return FindMRUData(hList, lpszString, 617 (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum); 618 } 619 620 /************************************************************************** 621 * FindMRUStringA [COMCTL32.155] 622 * 623 * Searches string list for item that matches lpszString. 624 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value 625 * corresponding to item's reg. name will be stored in it ('a' -> 0). 626 * 627 * PARAMS 628 * hList [I] list handle 629 * lpszString [I] string to find 630 * lpRegNum [O] position in registry (maybe NULL) 631 * 632 * RETURNS 633 * Position in list 0 -> MRU. -1 if item not found. 634 */ 635 INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum) 636 { 637 DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0); 638 LPWSTR stringW = Alloc(len * sizeof(WCHAR)); 639 INT ret; 640 641 MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len); 642 ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum); 643 Free(stringW); 644 return ret; 645 } 646 647 /************************************************************************* 648 * create_mru_list (internal) 649 */ 650 static HANDLE create_mru_list(LPWINEMRULIST mp) 651 { 652 UINT i, err; 653 HKEY newkey; 654 DWORD datasize, dwdisp; 655 WCHAR realname[2]; 656 LPWINEMRUITEM witem; 657 DWORD type; 658 659 /* get space to save indices that will turn into names 660 * but in order of most to least recently used 661 */ 662 mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR)); 663 664 /* get space to save pointers to actual data in order of 665 * 'a' to 'z' (0 to n). 666 */ 667 mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID)); 668 669 /* open the sub key */ 670 if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 671 0, 672 NULL, 673 REG_OPTION_NON_VOLATILE, 674 KEY_READ | KEY_WRITE, 675 0, 676 &newkey, 677 &dwdisp))) { 678 /* error - what to do ??? */ 679 ERR("(%u %u %x %p %s %p): Could not open key, error=%d\n", 680 mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags, 681 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), 682 mp->extview.u.string_cmpfn, err); 683 return 0; 684 } 685 686 /* get values from key 'MRUList' */ 687 if (newkey) { 688 datasize = (mp->extview.uMax + 1) * sizeof(WCHAR); 689 if (RegQueryValueExW( newkey, strMRUList, 0, &type, 690 (LPBYTE)mp->realMRU, &datasize)) { 691 /* not present - set size to 1 (will become 0 later) */ 692 datasize = 1; 693 *mp->realMRU = 0; 694 } 695 else 696 datasize /= sizeof(WCHAR); 697 698 TRACE("MRU list = %s, datasize = %d\n", debugstr_w(mp->realMRU), datasize); 699 700 mp->cursize = datasize - 1; 701 /* datasize now has number of items in the MRUList */ 702 703 /* get actual values for each entry */ 704 realname[1] = 0; 705 for(i=0; i<mp->cursize; i++) { 706 realname[0] = 'a' + i; 707 if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) { 708 /* not present - what to do ??? */ 709 ERR("Key %s not found 1\n", debugstr_w(realname)); 710 } 711 mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM)); 712 witem->size = datasize; 713 if(RegQueryValueExW( newkey, realname, 0, &type, 714 &witem->datastart, &datasize)) { 715 /* not present - what to do ??? */ 716 ERR("Key %s not found 2\n", debugstr_w(realname)); 717 } 718 } 719 RegCloseKey( newkey ); 720 } 721 else 722 mp->cursize = 0; 723 724 TRACE("(%u %u %x %p %s %p): Current Size = %d\n", 725 mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags, 726 mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), 727 mp->extview.u.string_cmpfn, mp->cursize); 728 return mp; 729 } 730 731 /************************************************************************** 732 * CreateMRUListLazyW [COMCTL32.404] 733 * 734 * See CreateMRUListLazyA. 735 */ 736 HANDLE WINAPI CreateMRUListLazyW (const MRUINFOW *infoW, DWORD dwParam2, 737 DWORD dwParam3, DWORD dwParam4) 738 { 739 LPWINEMRULIST mp; 740 741 /* Native does not check for a NULL lpcml */ 742 if (!infoW->hKey || IsBadStringPtrW(infoW->lpszSubKey, -1)) 743 return NULL; 744 745 mp = Alloc(sizeof(WINEMRULIST)); 746 memcpy(&mp->extview, infoW, sizeof(MRUINFOW)); 747 mp->extview.lpszSubKey = Alloc((lstrlenW(infoW->lpszSubKey) + 1) * sizeof(WCHAR)); 748 lstrcpyW(mp->extview.lpszSubKey, infoW->lpszSubKey); 749 mp->isUnicode = TRUE; 750 751 return create_mru_list(mp); 752 } 753 754 /************************************************************************** 755 * CreateMRUListLazyA [COMCTL32.157] 756 * 757 * Creates a most-recently-used list. 758 * 759 * PARAMS 760 * lpcml [I] ptr to CREATEMRULIST structure. 761 * dwParam2 [I] Unknown 762 * dwParam3 [I] Unknown 763 * dwParam4 [I] Unknown 764 * 765 * RETURNS 766 * Handle to MRU list. 767 */ 768 HANDLE WINAPI CreateMRUListLazyA (const MRUINFOA *lpcml, DWORD dwParam2, 769 DWORD dwParam3, DWORD dwParam4) 770 { 771 LPWINEMRULIST mp; 772 DWORD len; 773 774 /* Native does not check for a NULL lpcml */ 775 776 if (!lpcml->hKey || IsBadStringPtrA(lpcml->lpszSubKey, -1)) 777 return 0; 778 779 mp = Alloc(sizeof(WINEMRULIST)); 780 memcpy(&mp->extview, lpcml, sizeof(MRUINFOA)); 781 len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0); 782 mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR)); 783 MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, 784 mp->extview.lpszSubKey, len); 785 mp->isUnicode = FALSE; 786 return create_mru_list(mp); 787 } 788 789 /************************************************************************** 790 * CreateMRUListW [COMCTL32.400] 791 * 792 * See CreateMRUListA. 793 */ 794 HANDLE WINAPI CreateMRUListW (const MRUINFOW *infoW) 795 { 796 return CreateMRUListLazyW(infoW, 0, 0, 0); 797 } 798 799 /************************************************************************** 800 * CreateMRUListA [COMCTL32.151] 801 * 802 * Creates a most-recently-used list. 803 * 804 * PARAMS 805 * lpcml [I] ptr to CREATEMRULIST structure. 806 * 807 * RETURNS 808 * Handle to MRU list. 809 */ 810 HANDLE WINAPI CreateMRUListA (const MRUINFOA *lpcml) 811 { 812 return CreateMRUListLazyA (lpcml, 0, 0, 0); 813 } 814 815 816 /************************************************************************** 817 * EnumMRUListW [COMCTL32.403] 818 * 819 * Enumerate item in a most-recently-used list 820 * 821 * PARAMS 822 * hList [I] list handle 823 * nItemPos [I] item position to enumerate 824 * lpBuffer [O] buffer to receive item 825 * nBufferSize [I] size of buffer 826 * 827 * RETURNS 828 * For binary lists specifies how many bytes were copied to buffer, for 829 * string lists specifies full length of string. Enumerating past the end 830 * of list returns -1. 831 * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in 832 * the list. 833 */ 834 INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer, 835 DWORD nBufferSize) 836 { 837 const WINEMRULIST *mp = hList; 838 const WINEMRUITEM *witem; 839 INT desired, datasize; 840 841 if (!mp) return -1; 842 if ((nItemPos < 0) || !lpBuffer) return mp->cursize; 843 if (nItemPos >= mp->cursize) return -1; 844 desired = mp->realMRU[nItemPos]; 845 desired -= 'a'; 846 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); 847 witem = mp->array[desired]; 848 datasize = min( witem->size, nBufferSize ); 849 memcpy( lpBuffer, &witem->datastart, datasize); 850 TRACE("(%p, %d, %p, %d): returning len=%d\n", 851 hList, nItemPos, lpBuffer, nBufferSize, datasize); 852 return datasize; 853 } 854 855 /************************************************************************** 856 * EnumMRUListA [COMCTL32.154] 857 * 858 * See EnumMRUListW. 859 */ 860 INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer, 861 DWORD nBufferSize) 862 { 863 const WINEMRULIST *mp = hList; 864 LPWINEMRUITEM witem; 865 INT desired, datasize; 866 DWORD lenA; 867 868 if (!mp) return -1; 869 if ((nItemPos < 0) || !lpBuffer) return mp->cursize; 870 if (nItemPos >= mp->cursize) return -1; 871 desired = mp->realMRU[nItemPos]; 872 desired -= 'a'; 873 TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); 874 witem = mp->array[desired]; 875 if(mp->extview.fFlags & MRU_BINARY) { 876 datasize = min( witem->size, nBufferSize ); 877 memcpy( lpBuffer, &witem->datastart, datasize); 878 } else { 879 lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, 880 NULL, 0, NULL, NULL); 881 datasize = min( lenA, nBufferSize ); 882 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, 883 lpBuffer, datasize, NULL, NULL); 884 ((char *)lpBuffer)[ datasize - 1 ] = '\0'; 885 datasize = lenA - 1; 886 } 887 TRACE("(%p, %d, %p, %d): returning len=%d\n", 888 hList, nItemPos, lpBuffer, nBufferSize, datasize); 889 return datasize; 890 } 891 892 /************************************************************************** 893 * Str_GetPtrWtoA [internal] 894 * 895 * Converts a unicode string into a multi byte string 896 * 897 * PARAMS 898 * lpSrc [I] Pointer to the unicode source string 899 * lpDest [O] Pointer to caller supplied storage for the multi byte string 900 * nMaxLen [I] Size, in bytes, of the destination buffer 901 * 902 * RETURNS 903 * Length, in bytes, of the converted string. 904 */ 905 906 INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen) 907 { 908 INT len; 909 910 TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen); 911 912 if (!lpDest && lpSrc) 913 return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); 914 915 if (nMaxLen == 0) 916 return 0; 917 918 if (lpSrc == NULL) { 919 lpDest[0] = '\0'; 920 return 0; 921 } 922 923 len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); 924 if (len >= nMaxLen) 925 len = nMaxLen - 1; 926 927 WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL); 928 lpDest[len] = '\0'; 929 930 return len; 931 } 932 933 /************************************************************************** 934 * Str_GetPtrAtoW [internal] 935 * 936 * Converts a multibyte string into a unicode string 937 * 938 * PARAMS 939 * lpSrc [I] Pointer to the multibyte source string 940 * lpDest [O] Pointer to caller supplied storage for the unicode string 941 * nMaxLen [I] Size, in characters, of the destination buffer 942 * 943 * RETURNS 944 * Length, in characters, of the converted string. 945 */ 946 947 INT Str_GetPtrAtoW (LPCSTR lpSrc, LPWSTR lpDest, INT nMaxLen) 948 { 949 INT len; 950 951 TRACE("(%s %p %d)\n", debugstr_a(lpSrc), lpDest, nMaxLen); 952 953 if (!lpDest && lpSrc) 954 return MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, 0, 0); 955 956 if (nMaxLen == 0) 957 return 0; 958 959 if (lpSrc == NULL) { 960 lpDest[0] = '\0'; 961 return 0; 962 } 963 964 len = MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, 0, 0); 965 if (len >= nMaxLen) 966 len = nMaxLen - 1; 967 968 MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, lpDest, len); 969 lpDest[len] = '\0'; 970 971 return len; 972 } 973 974 975 /************************************************************************** 976 * Str_SetPtrAtoW [internal] 977 * 978 * Converts a multi byte string to a unicode string. 979 * If the pointer to the destination buffer is NULL a buffer is allocated. 980 * If the destination buffer is too small to keep the converted multi byte 981 * string the destination buffer is reallocated. If the source pointer is 982 * NULL, the destination buffer is freed. 983 * 984 * PARAMS 985 * lppDest [I/O] pointer to a pointer to the destination buffer 986 * lpSrc [I] pointer to a multi byte string 987 * 988 * RETURNS 989 * TRUE: conversion successful 990 * FALSE: error 991 */ 992 BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc) 993 { 994 TRACE("(%p %s)\n", lppDest, lpSrc); 995 996 if (lpSrc) { 997 INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0); 998 LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR)); 999 1000 if (!ptr) 1001 return FALSE; 1002 MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len); 1003 *lppDest = ptr; 1004 } 1005 else { 1006 Free (*lppDest); 1007 *lppDest = NULL; 1008 } 1009 1010 return TRUE; 1011 } 1012 1013 /************************************************************************** 1014 * Str_SetPtrWtoA [internal] 1015 * 1016 * Converts a unicode string to a multi byte string. 1017 * If the pointer to the destination buffer is NULL a buffer is allocated. 1018 * If the destination buffer is too small to keep the converted wide 1019 * string the destination buffer is reallocated. If the source pointer is 1020 * NULL, the destination buffer is freed. 1021 * 1022 * PARAMS 1023 * lppDest [I/O] pointer to a pointer to the destination buffer 1024 * lpSrc [I] pointer to a wide string 1025 * 1026 * RETURNS 1027 * TRUE: conversion successful 1028 * FALSE: error 1029 */ 1030 BOOL Str_SetPtrWtoA (LPSTR *lppDest, LPCWSTR lpSrc) 1031 { 1032 TRACE("(%p %s)\n", lppDest, debugstr_w(lpSrc)); 1033 1034 if (lpSrc) { 1035 INT len = WideCharToMultiByte(CP_ACP,0,lpSrc,-1,NULL,0,NULL,FALSE); 1036 LPSTR ptr = ReAlloc (*lppDest, len*sizeof(CHAR)); 1037 1038 if (!ptr) 1039 return FALSE; 1040 WideCharToMultiByte(CP_ACP,0,lpSrc,-1,ptr,len,NULL,FALSE); 1041 *lppDest = ptr; 1042 } 1043 else { 1044 Free (*lppDest); 1045 *lppDest = NULL; 1046 } 1047 1048 return TRUE; 1049 } 1050 1051 1052 /************************************************************************** 1053 * Notification functions 1054 */ 1055 1056 typedef struct tagNOTIFYDATA 1057 { 1058 HWND hwndFrom; 1059 HWND hwndTo; 1060 DWORD dwParam3; 1061 DWORD dwParam4; 1062 DWORD dwParam5; 1063 DWORD dwParam6; 1064 } NOTIFYDATA, *LPNOTIFYDATA; 1065 1066 1067 /************************************************************************** 1068 * DoNotify [Internal] 1069 */ 1070 1071 static LRESULT DoNotify (const NOTIFYDATA *lpNotify, UINT uCode, LPNMHDR lpHdr) 1072 { 1073 NMHDR nmhdr; 1074 LPNMHDR lpNmh = NULL; 1075 UINT idFrom = 0; 1076 1077 TRACE("(%p %p %d %p 0x%08x)\n", 1078 lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr, 1079 lpNotify->dwParam5); 1080 1081 if (!lpNotify->hwndTo) 1082 return 0; 1083 1084 if (lpNotify->hwndFrom == (HWND)-1) { 1085 lpNmh = lpHdr; 1086 idFrom = lpHdr->idFrom; 1087 } 1088 else { 1089 if (lpNotify->hwndFrom) 1090 idFrom = GetDlgCtrlID (lpNotify->hwndFrom); 1091 1092 lpNmh = (lpHdr) ? lpHdr : &nmhdr; 1093 1094 lpNmh->hwndFrom = lpNotify->hwndFrom; 1095 lpNmh->idFrom = idFrom; 1096 lpNmh->code = uCode; 1097 } 1098 1099 return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh); 1100 } 1101 1102 1103 /************************************************************************** 1104 * SendNotify [COMCTL32.341] 1105 * 1106 * Sends a WM_NOTIFY message to the specified window. 1107 * 1108 * PARAMS 1109 * hwndTo [I] Window to receive the message 1110 * hwndFrom [I] Window that the message is from (see notes) 1111 * uCode [I] Notification code 1112 * lpHdr [I] The NMHDR and any additional information to send or NULL 1113 * 1114 * RETURNS 1115 * Success: return value from notification 1116 * Failure: 0 1117 * 1118 * NOTES 1119 * If hwndFrom is -1 then the identifier of the control sending the 1120 * message is taken from the NMHDR structure. 1121 * If hwndFrom is not -1 then lpHdr can be NULL. 1122 */ 1123 LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr) 1124 { 1125 NOTIFYDATA notify; 1126 1127 TRACE("(%p %p %d %p)\n", 1128 hwndTo, hwndFrom, uCode, lpHdr); 1129 1130 notify.hwndFrom = hwndFrom; 1131 notify.hwndTo = hwndTo; 1132 notify.dwParam5 = 0; 1133 notify.dwParam6 = 0; 1134 1135 return DoNotify (¬ify, uCode, lpHdr); 1136 } 1137 1138 1139 /************************************************************************** 1140 * SendNotifyEx [COMCTL32.342] 1141 * 1142 * Sends a WM_NOTIFY message to the specified window. 1143 * 1144 * PARAMS 1145 * hwndFrom [I] Window to receive the message 1146 * hwndTo [I] Window that the message is from 1147 * uCode [I] Notification code 1148 * lpHdr [I] The NMHDR and any additional information to send or NULL 1149 * dwParam5 [I] Unknown 1150 * 1151 * RETURNS 1152 * Success: return value from notification 1153 * Failure: 0 1154 * 1155 * NOTES 1156 * If hwndFrom is -1 then the identifier of the control sending the 1157 * message is taken from the NMHDR structure. 1158 * If hwndFrom is not -1 then lpHdr can be NULL. 1159 */ 1160 LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode, 1161 LPNMHDR lpHdr, DWORD dwParam5) 1162 { 1163 NOTIFYDATA notify; 1164 HWND hwndNotify; 1165 1166 TRACE("(%p %p %d %p 0x%08x)\n", 1167 hwndFrom, hwndTo, uCode, lpHdr, dwParam5); 1168 1169 hwndNotify = hwndTo; 1170 if (!hwndTo) { 1171 if (IsWindow (hwndFrom)) { 1172 hwndNotify = GetParent (hwndFrom); 1173 if (!hwndNotify) 1174 return 0; 1175 } 1176 } 1177 1178 notify.hwndFrom = hwndFrom; 1179 notify.hwndTo = hwndNotify; 1180 notify.dwParam5 = dwParam5; 1181 notify.dwParam6 = 0; 1182 1183 return DoNotify (¬ify, uCode, lpHdr); 1184 } 1185