1 /* 2 * pidl Handling 3 * 4 * Copyright 1998 Juergen Schmied 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * NOTES 21 * a pidl == NULL means desktop and is legal 22 * 23 */ 24 25 #include <wine/config.h> 26 27 #define WIN32_NO_STATUS 28 #define _INC_WINDOWS 29 #define COBJMACROS 30 #define NONAMELESSUNION 31 #define NONAMELESSSTRUCT 32 33 #include <windef.h> 34 #include <winbase.h> 35 #include <strsafe.h> 36 #include <shlobj.h> 37 #include <undocshell.h> 38 #include <shlwapi.h> 39 #include <shlguid_undoc.h> 40 #include <wine/debug.h> 41 #include <wine/unicode.h> 42 43 #include "pidl.h" 44 #include "shell32_main.h" 45 #include "shresdef.h" 46 47 WINE_DEFAULT_DEBUG_CHANNEL(pidl); 48 WINE_DECLARE_DEBUG_CHANNEL(shell); 49 50 /* from comctl32.dll */ 51 extern LPVOID WINAPI Alloc(INT); 52 extern BOOL WINAPI Free(LPVOID); 53 54 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl); 55 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl); 56 57 EXTERN_C HWND BindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx); 58 59 EXTERN_C HRESULT 60 BindCtx_RegisterObjectParam( 61 _In_ IBindCtx *pBindCtx, 62 _In_ LPOLESTR pszKey, 63 _In_opt_ IUnknown *punk, 64 _Out_ LPBC *ppbc); 65 66 /************************************************************************* 67 * ILGetDisplayNameExA 68 * 69 * Retrieves the display name of an ItemIDList 70 * 71 * PARAMS 72 * psf [I] Shell Folder to start with, if NULL the desktop is used 73 * pidl [I] ItemIDList relative to the psf to get the display name for 74 * path [O] Filled in with the display name, assumed to be at least MAX_PATH long 75 * type [I] Type of display name to retrieve 76 * 0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root 77 * 1 = SHGDN_NORMAL relative to the root folder 78 * 2 = SHGDN_INFOLDER relative to the root folder, only the last name 79 * 80 * RETURNS 81 * True if the display name could be retrieved successfully, False otherwise 82 */ 83 static BOOL ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type) 84 { 85 BOOL ret = FALSE; 86 WCHAR wPath[MAX_PATH]; 87 88 TRACE("%p %p %p %d\n", psf, pidl, path, type); 89 90 if (!pidl || !path) 91 return FALSE; 92 93 ret = ILGetDisplayNameExW(psf, pidl, wPath, type); 94 WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL); 95 TRACE("%p %p %s\n", psf, pidl, debugstr_a(path)); 96 97 return ret; 98 } 99 100 BOOL ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type) 101 { 102 LPSHELLFOLDER psfParent, lsf = psf; 103 HRESULT ret = NO_ERROR; 104 LPCITEMIDLIST pidllast; 105 STRRET strret; 106 DWORD flag; 107 108 TRACE("%p %p %p %x\n", psf, pidl, path, type); 109 110 if (!pidl || !path) 111 return FALSE; 112 113 if (!lsf) 114 { 115 ret = SHGetDesktopFolder(&lsf); 116 if (FAILED(ret)) 117 return FALSE; 118 } 119 120 switch (type) 121 { 122 case ILGDN_FORPARSING: 123 flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; 124 break; 125 case ILGDN_NORMAL: 126 flag = SHGDN_NORMAL; 127 break; 128 case ILGDN_INFOLDER: 129 flag = SHGDN_INFOLDER; 130 break; 131 default: 132 FIXME("Unknown type parameter = %x\n", type); 133 flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; 134 break; 135 } 136 137 if (!*(const WORD*)pidl || type == ILGDN_FORPARSING) 138 { 139 ret = IShellFolder_GetDisplayNameOf(lsf, pidl, flag, &strret); 140 if (SUCCEEDED(ret)) 141 { 142 if(!StrRetToStrNW(path, MAX_PATH, &strret, pidl)) 143 ret = E_FAIL; 144 } 145 } 146 else 147 { 148 ret = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidllast); 149 if (SUCCEEDED(ret)) 150 { 151 ret = IShellFolder_GetDisplayNameOf(psfParent, pidllast, flag, &strret); 152 if (SUCCEEDED(ret)) 153 { 154 if(!StrRetToStrNW(path, MAX_PATH, &strret, pidllast)) 155 ret = E_FAIL; 156 } 157 IShellFolder_Release(psfParent); 158 } 159 } 160 161 TRACE("%p %p %s\n", psf, pidl, debugstr_w(path)); 162 163 if (!psf) 164 IShellFolder_Release(lsf); 165 return SUCCEEDED(ret); 166 } 167 168 /************************************************************************* 169 * ILGetDisplayNameEx [SHELL32.186] 170 */ 171 BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type) 172 { 173 TRACE_(shell)("%p %p %p %d\n", psf, pidl, path, type); 174 175 if (SHELL_OsIsUnicode()) 176 return ILGetDisplayNameExW(psf, pidl, path, type); 177 return ILGetDisplayNameExA(psf, pidl, path, type); 178 } 179 180 /************************************************************************* 181 * ILGetDisplayName [SHELL32.15] 182 */ 183 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path) 184 { 185 TRACE_(shell)("%p %p\n", pidl, path); 186 187 if (SHELL_OsIsUnicode()) 188 return ILGetDisplayNameExW(NULL, pidl, path, ILGDN_FORPARSING); 189 return ILGetDisplayNameExA(NULL, pidl, path, ILGDN_FORPARSING); 190 } 191 192 /************************************************************************* 193 * ILFindLastID [SHELL32.16] 194 * 195 * NOTES 196 * observed: pidl=Desktop return=pidl 197 */ 198 LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl) 199 { 200 LPCITEMIDLIST pidlLast = pidl; 201 202 TRACE("(pidl=%p)\n",pidl); 203 204 if (!pidl) 205 return NULL; 206 207 while (pidl->mkid.cb) 208 { 209 pidlLast = pidl; 210 pidl = ILGetNext(pidl); 211 } 212 return (LPITEMIDLIST)pidlLast; 213 } 214 215 /************************************************************************* 216 * ILRemoveLastID [SHELL32.17] 217 * 218 * NOTES 219 * when pidl=Desktop return=FALSE 220 */ 221 BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl) 222 { 223 TRACE_(shell)("pidl=%p\n",pidl); 224 225 if (_ILIsEmpty(pidl)) 226 return FALSE; 227 ILFindLastID(pidl)->mkid.cb = 0; 228 return TRUE; 229 } 230 231 /************************************************************************* 232 * ILClone [SHELL32.18] 233 * 234 * NOTES 235 * duplicate an idlist 236 */ 237 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl) 238 { 239 DWORD len; 240 LPITEMIDLIST newpidl; 241 242 if (!pidl) 243 return NULL; 244 245 len = ILGetSize(pidl); 246 newpidl = SHAlloc(len); 247 if (newpidl) 248 memcpy(newpidl,pidl,len); 249 250 TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); 251 pdump(pidl); 252 253 return newpidl; 254 } 255 256 /************************************************************************* 257 * ILCloneFirst [SHELL32.19] 258 * 259 * NOTES 260 * duplicates the first idlist of a complex pidl 261 */ 262 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl) 263 { 264 DWORD len; 265 LPITEMIDLIST pidlNew = NULL; 266 267 TRACE("pidl=%p\n", pidl); 268 pdump(pidl); 269 270 if (pidl) 271 { 272 len = pidl->mkid.cb; 273 pidlNew = SHAlloc(len+2); 274 if (pidlNew) 275 { 276 memcpy(pidlNew,pidl,len+2); /* 2 -> mind a desktop pidl */ 277 278 if (len) 279 ILGetNext(pidlNew)->mkid.cb = 0x00; 280 } 281 } 282 TRACE("-- newpidl=%p\n",pidlNew); 283 284 return pidlNew; 285 } 286 287 /************************************************************************* 288 * ILLoadFromStream (SHELL32.26) 289 * 290 * NOTES 291 * the first two bytes are the len, the pidl is following then 292 */ 293 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl) 294 { 295 WORD wLen = 0; 296 DWORD dwBytesRead; 297 HRESULT ret = E_FAIL; 298 299 300 TRACE_(shell)("%p %p\n", pStream , ppPidl); 301 302 SHFree(*ppPidl); 303 *ppPidl = NULL; 304 305 IStream_AddRef (pStream); 306 307 if (SUCCEEDED(IStream_Read(pStream, &wLen, 2, &dwBytesRead))) 308 { 309 TRACE("PIDL length is %d\n", wLen); 310 if (wLen != 0) 311 { 312 *ppPidl = SHAlloc (wLen); 313 if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead))) 314 { 315 TRACE("Stream read OK\n"); 316 ret = S_OK; 317 } 318 else 319 { 320 WARN("reading pidl failed\n"); 321 SHFree(*ppPidl); 322 *ppPidl = NULL; 323 } 324 } 325 else 326 { 327 *ppPidl = NULL; 328 ret = S_OK; 329 } 330 } 331 332 /* we are not yet fully compatible */ 333 if (*ppPidl && !pcheck(*ppPidl)) 334 { 335 WARN("Check failed\n"); 336 SHFree(*ppPidl); 337 *ppPidl = NULL; 338 } 339 340 IStream_Release (pStream); 341 TRACE("done\n"); 342 return ret; 343 } 344 345 /************************************************************************* 346 * ILSaveToStream (SHELL32.27) 347 * 348 * NOTES 349 * the first two bytes are the len, the pidl is following then 350 */ 351 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl) 352 { 353 WORD wLen = 0; 354 HRESULT ret = E_FAIL; 355 356 TRACE_(shell)("%p %p\n", pStream, pPidl); 357 358 IStream_AddRef (pStream); 359 360 wLen = ILGetSize(pPidl); 361 362 if (SUCCEEDED(IStream_Write(pStream, &wLen, 2, NULL))) 363 { 364 if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL))) 365 ret = S_OK; 366 } 367 IStream_Release (pStream); 368 369 return ret; 370 } 371 372 /************************************************************************* 373 * SHILCreateFromPath [SHELL32.28] 374 * 375 * Create an ItemIDList from a path 376 * 377 * PARAMS 378 * path [I] 379 * ppidl [O] 380 * attributes [I/O] requested attributes on call and actual attributes when 381 * the function returns 382 * 383 * RETURNS 384 * NO_ERROR if successful, or an OLE errer code otherwise 385 * 386 * NOTES 387 * Wrapper for IShellFolder_ParseDisplayName(). 388 */ 389 HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) 390 { 391 WCHAR lpszDisplayName[MAX_PATH]; 392 393 TRACE_(shell)("%s %p 0x%08x\n", path, ppidl, attributes ? *attributes : 0); 394 395 if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH)) 396 lpszDisplayName[MAX_PATH-1] = 0; 397 398 return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes); 399 } 400 401 HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) 402 { 403 LPSHELLFOLDER sf; 404 DWORD pchEaten; 405 HRESULT ret = E_FAIL; 406 407 TRACE_(shell)("%s %p 0x%08x\n", debugstr_w(path), ppidl, attributes ? *attributes : 0); 408 409 if (SUCCEEDED (SHGetDesktopFolder(&sf))) 410 { 411 ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes); 412 IShellFolder_Release(sf); 413 } 414 return ret; 415 } 416 417 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes) 418 { 419 if ( SHELL_OsIsUnicode()) 420 return SHILCreateFromPathW (path, ppidl, attributes); 421 return SHILCreateFromPathA (path, ppidl, attributes); 422 } 423 424 /************************************************************************* 425 * SHCloneSpecialIDList [SHELL32.89] 426 * 427 * Create an ItemIDList to one of the special folders. 428 429 * PARAMS 430 * hwndOwner [in] 431 * nFolder [in] CSIDL_xxxxx 432 * fCreate [in] Create folder if it does not exist 433 * 434 * RETURNS 435 * Success: The newly created pidl 436 * Failure: NULL, if inputs are invalid. 437 * 438 * NOTES 439 * exported by ordinal. 440 * Caller is responsible for deallocating the returned ItemIDList with the 441 * shells IMalloc interface, aka ILFree. 442 */ 443 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate) 444 { 445 LPITEMIDLIST ppidl; 446 TRACE_(shell)("(hwnd=%p,csidl=0x%x,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F"); 447 448 if (fCreate) 449 nFolder |= CSIDL_FLAG_CREATE; 450 451 SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl); 452 return ppidl; 453 } 454 455 /************************************************************************* 456 * ILGlobalClone [SHELL32.20] 457 * 458 * Clones an ItemIDList using Alloc. 459 * 460 * PARAMS 461 * pidl [I] ItemIDList to clone 462 * 463 * RETURNS 464 * Newly allocated ItemIDList. 465 * 466 * NOTES 467 * exported by ordinal. 468 */ 469 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl) 470 { 471 DWORD len; 472 LPITEMIDLIST newpidl; 473 474 if (!pidl) 475 return NULL; 476 477 len = ILGetSize(pidl); 478 newpidl = Alloc(len); 479 if (newpidl) 480 memcpy(newpidl,pidl,len); 481 482 TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); 483 pdump(pidl); 484 485 return newpidl; 486 } 487 488 BOOL _ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1, LPCITEMIDLIST pidltemp2) 489 { 490 LPPIDLDATA pdata1 = _ILGetDataPointer(pidltemp1); 491 LPPIDLDATA pdata2 = _ILGetDataPointer(pidltemp2); 492 493 IID *iid1 = _ILGetGUIDPointer(pidltemp1); 494 IID *iid2 = _ILGetGUIDPointer(pidltemp2); 495 496 FileStructW* pDataW1 = _ILGetFileStructW(pidltemp1); 497 FileStructW* pDataW2 = _ILGetFileStructW(pidltemp2); 498 499 if (_ILIsDesktop(pidltemp1) && _ILIsDesktop(pidltemp2)) 500 { 501 return TRUE; 502 } 503 else if (_ILIsDesktop(pidltemp1) || _ILIsDesktop(pidltemp2)) 504 { 505 return FALSE; 506 } 507 else if (iid1 || iid2) 508 { 509 if (!iid1 || !iid2 || memcmp(iid1, iid2, sizeof(GUID))) 510 return FALSE; 511 } 512 else if (pDataW1 || pDataW2) 513 { 514 if (!pDataW1 || !pDataW2 || wcsicmp(pDataW1->wszName, pDataW2->wszName)) 515 return FALSE; 516 } 517 else if (_ILIsFolder(pidltemp1) || _ILIsFolder(pidltemp2)) 518 { 519 if (!_ILIsFolder(pidltemp1) || !_ILIsFolder(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames)) 520 return FALSE; 521 } 522 else if (_ILIsValue(pidltemp1) || _ILIsValue(pidltemp2)) 523 { 524 if (!_ILIsValue(pidltemp1) || !_ILIsValue(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames)) 525 return FALSE; 526 } 527 else if (_ILIsDrive(pidltemp1) || _ILIsDrive(pidltemp2)) 528 { 529 if (!_ILIsDrive(pidltemp1) || !_ILIsDrive(pidltemp2) || pdata1->u.drive.szDriveName[0] != pdata2->u.drive.szDriveName[0]) 530 return FALSE; 531 } 532 else 533 { 534 if ((pidltemp1->mkid.cb != pidltemp2->mkid.cb) || 535 !RtlEqualMemory((BYTE*)&pidltemp1->mkid, (BYTE*)&pidltemp2->mkid, pidltemp1->mkid.cb)) 536 { 537 return FALSE; 538 } 539 } 540 541 return TRUE; 542 } 543 544 /************************************************************************* 545 * ILIsEqual [SHELL32.21] 546 * 547 */ 548 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 549 { 550 LPCITEMIDLIST pidltemp1 = pidl1; 551 LPCITEMIDLIST pidltemp2 = pidl2; 552 553 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); 554 555 /* 556 * Explorer reads from registry directly (StreamMRU), 557 * so we can only check here 558 */ 559 if (!pcheck(pidl1) || !pcheck (pidl2)) 560 return FALSE; 561 562 pdump (pidl1); 563 pdump (pidl2); 564 565 if (!pidl1 || !pidl2) 566 return FALSE; 567 568 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) 569 { 570 if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2)) 571 return FALSE; 572 573 pidltemp1 = ILGetNext(pidltemp1); 574 pidltemp2 = ILGetNext(pidltemp2); 575 } 576 577 if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb) 578 return TRUE; 579 580 return FALSE; 581 } 582 583 /************************************************************************* 584 * ILIsParent [SHELL32.23] 585 * 586 * Verifies that pidlParent is indeed the (immediate) parent of pidlChild. 587 * 588 * PARAMS 589 * pidlParent [I] 590 * pidlChild [I] 591 * bImmediate [I] only return true if the parent is the direct parent 592 * of the child 593 * 594 * RETURNS 595 * True if the parent ItemIDlist is a complete part of the child ItemIdList, 596 * False otherwise. 597 * 598 * NOTES 599 * parent = a/b, child = a/b/c -> true, c is in folder a/b 600 * child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b 601 * child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b 602 * child = a/b -> false if bImmediate is true 603 * child = a/b -> true if bImmediate is false 604 */ 605 BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate) 606 { 607 LPCITEMIDLIST pParent = pidlParent; 608 LPCITEMIDLIST pChild = pidlChild; 609 610 TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate); 611 612 if (!pParent || !pChild) 613 return FALSE; 614 615 while (pParent->mkid.cb && pChild->mkid.cb) 616 { 617 if (!_ILHACKCompareSimpleIds(pParent, pChild)) 618 return FALSE; 619 620 pParent = ILGetNext(pParent); 621 pChild = ILGetNext(pChild); 622 } 623 624 /* child has shorter name than parent */ 625 if (pParent->mkid.cb) 626 return FALSE; 627 628 /* not immediate descent */ 629 if ((!pChild->mkid.cb || ILGetNext(pChild)->mkid.cb) && bImmediate) 630 return FALSE; 631 632 return TRUE; 633 } 634 635 /************************************************************************* 636 * ILFindChild [SHELL32.24] 637 * 638 * Compares elements from pidl1 and pidl2. 639 * 640 * PARAMS 641 * pidl1 [I] 642 * pidl2 [I] 643 * 644 * RETURNS 645 * pidl1 is desktop pidl2 646 * pidl1 shorter pidl2 pointer to first different element of pidl2 647 * if there was at least one equal element 648 * pidl2 shorter pidl1 0 649 * pidl2 equal pidl1 pointer to last 0x00-element of pidl2 650 * 651 * NOTES 652 * exported by ordinal. 653 */ 654 PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2) 655 { 656 LPCITEMIDLIST pidltemp1 = pidl1; 657 LPCITEMIDLIST pidltemp2 = pidl2; 658 LPCITEMIDLIST ret=NULL; 659 660 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); 661 662 /* explorer reads from registry directly (StreamMRU), 663 so we can only check here */ 664 if ((!pcheck (pidl1)) || (!pcheck (pidl2))) 665 return FALSE; 666 667 pdump (pidl1); 668 pdump (pidl2); 669 670 if (_ILIsDesktop(pidl1)) 671 { 672 ret = pidl2; 673 } 674 else 675 { 676 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) 677 { 678 if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2)) 679 return FALSE; 680 681 pidltemp1 = ILGetNext(pidltemp1); 682 pidltemp2 = ILGetNext(pidltemp2); 683 ret = pidltemp2; 684 } 685 686 if (pidltemp1->mkid.cb) 687 ret = NULL; /* elements of pidl1 left*/ 688 } 689 TRACE_(shell)("--- %p\n", ret); 690 return (PUIDLIST_RELATIVE)ret; /* pidl 1 is shorter */ 691 } 692 693 /************************************************************************* 694 * ILCombine [SHELL32.25] 695 * 696 * Concatenates two complex ItemIDLists. 697 * 698 * PARAMS 699 * pidl1 [I] first complex ItemIDLists 700 * pidl2 [I] complex ItemIDLists to append 701 * 702 * RETURNS 703 * if both pidl's == NULL NULL 704 * if pidl1 == NULL cloned pidl2 705 * if pidl2 == NULL cloned pidl1 706 * otherwise new pidl with pidl2 appended to pidl1 707 * 708 * NOTES 709 * exported by ordinal. 710 * Does not destroy the passed in ItemIDLists! 711 */ 712 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 713 { 714 DWORD len1,len2; 715 LPITEMIDLIST pidlNew; 716 717 TRACE("pidl=%p pidl=%p\n",pidl1,pidl2); 718 719 if (!pidl1 && !pidl2) return NULL; 720 721 pdump (pidl1); 722 pdump (pidl2); 723 724 if (!pidl1) 725 { 726 pidlNew = ILClone(pidl2); 727 return pidlNew; 728 } 729 730 if (!pidl2) 731 { 732 pidlNew = ILClone(pidl1); 733 return pidlNew; 734 } 735 736 len1 = ILGetSize(pidl1)-2; 737 len2 = ILGetSize(pidl2); 738 pidlNew = SHAlloc(len1+len2); 739 740 if (pidlNew) 741 { 742 memcpy(pidlNew,pidl1,len1); 743 memcpy(((BYTE *)pidlNew)+len1,pidl2,len2); 744 } 745 746 /* TRACE(pidl,"--new pidl=%p\n",pidlNew);*/ 747 return pidlNew; 748 } 749 750 #ifndef __REACTOS__ /* See ..\utils.cpp */ 751 /************************************************************************* 752 * SHGetRealIDL [SHELL32.98] 753 * 754 * NOTES 755 */ 756 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal) 757 { 758 IDataObject* pDataObj; 759 HRESULT hr; 760 761 hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple, 762 &IID_IDataObject, 0, (LPVOID*)&pDataObj); 763 if (SUCCEEDED(hr)) 764 { 765 STGMEDIUM medium; 766 FORMATETC fmt; 767 768 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); 769 fmt.ptd = NULL; 770 fmt.dwAspect = DVASPECT_CONTENT; 771 fmt.lindex = -1; 772 fmt.tymed = TYMED_HGLOBAL; 773 774 hr = IDataObject_GetData(pDataObj, &fmt, &medium); 775 776 IDataObject_Release(pDataObj); 777 778 if (SUCCEEDED(hr)) 779 { 780 /*assert(pida->cidl==1);*/ 781 LPIDA pida = GlobalLock(medium.u.hGlobal); 782 783 LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); 784 LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); 785 786 *pidlReal = ILCombine(pidl_folder, pidl_child); 787 788 if (!*pidlReal) 789 hr = E_OUTOFMEMORY; 790 791 GlobalUnlock(medium.u.hGlobal); 792 GlobalFree(medium.u.hGlobal); 793 } 794 } 795 796 return hr; 797 } 798 #endif 799 800 /************************************************************************* 801 * SHLogILFromFSIL [SHELL32.95] 802 * 803 * NOTES 804 * pild = CSIDL_DESKTOP ret = 0 805 * pild = CSIDL_DRIVES ret = 0 806 */ 807 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl) 808 { 809 FIXME("(pidl=%p)\n",pidl); 810 811 pdump(pidl); 812 813 return 0; 814 } 815 816 /************************************************************************* 817 * ILGetSize [SHELL32.152] 818 * 819 * Gets the byte size of an ItemIDList including zero terminator 820 * 821 * PARAMS 822 * pidl [I] ItemIDList 823 * 824 * RETURNS 825 * size of pidl in bytes 826 * 827 * NOTES 828 * exported by ordinal 829 */ 830 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl) 831 { 832 LPCSHITEMID si; 833 UINT len=0; 834 835 if (pidl) 836 { 837 si = &(pidl->mkid); 838 839 while (si->cb) 840 { 841 len += si->cb; 842 si = (LPCSHITEMID)(((const BYTE*)si)+si->cb); 843 } 844 len += 2; 845 } 846 TRACE("pidl=%p size=%u\n",pidl, len); 847 return len; 848 } 849 850 /************************************************************************* 851 * ILGetNext [SHELL32.153] 852 * 853 * Gets the next ItemID of an ItemIDList 854 * 855 * PARAMS 856 * pidl [I] ItemIDList 857 * 858 * RETURNS 859 * null -> null 860 * desktop -> null 861 * simple pidl -> pointer to 0x0000 element 862 * 863 * NOTES 864 * exported by ordinal. 865 */ 866 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl) 867 { 868 WORD len; 869 870 TRACE("%p\n", pidl); 871 872 if (pidl) 873 { 874 len = pidl->mkid.cb; 875 if (len) 876 { 877 pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len); 878 TRACE("-- %p\n", pidl); 879 return (LPITEMIDLIST)pidl; 880 } 881 } 882 return NULL; 883 } 884 885 /************************************************************************* 886 * ILAppendID [SHELL32.154] 887 * 888 * Adds the single ItemID item to the ItemIDList indicated by pidl. 889 * If bEnd is FALSE, inserts the item in the front of the list, 890 * otherwise it adds the item to the end. (???) 891 * 892 * PARAMS 893 * pidl [I] ItemIDList to extend 894 * item [I] ItemID to prepend/append 895 * bEnd [I] Indicates if the item should be appended 896 * 897 * NOTES 898 * Destroys the passed in idlist! (???) 899 */ 900 LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd) 901 { 902 LPITEMIDLIST idlRet; 903 LPCITEMIDLIST itemid = (LPCITEMIDLIST)item; 904 905 WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd); 906 907 pdump (pidl); 908 pdump (itemid); 909 910 if (_ILIsDesktop(pidl)) 911 { 912 idlRet = ILClone(itemid); 913 SHFree (pidl); 914 return idlRet; 915 } 916 917 if (bEnd) 918 idlRet = ILCombine(pidl, itemid); 919 else 920 idlRet = ILCombine(itemid, pidl); 921 922 SHFree(pidl); 923 return idlRet; 924 } 925 926 /************************************************************************* 927 * ILFree [SHELL32.155] 928 * 929 * Frees memory (if not NULL) allocated by SHMalloc allocator 930 * 931 * PARAMS 932 * pidl [I] 933 * 934 * RETURNS 935 * Nothing 936 * 937 * NOTES 938 * exported by ordinal 939 */ 940 void WINAPI ILFree(LPITEMIDLIST pidl) 941 { 942 TRACE("(pidl=%p)\n",pidl); 943 SHFree(pidl); 944 } 945 946 /************************************************************************* 947 * ILGlobalFree [SHELL32.156] 948 * 949 * Frees memory (if not NULL) allocated by Alloc allocator 950 * 951 * PARAMS 952 * pidl [I] 953 * 954 * RETURNS 955 * Nothing 956 * 957 * NOTES 958 * exported by ordinal. 959 */ 960 void WINAPI ILGlobalFree( LPITEMIDLIST pidl) 961 { 962 TRACE("%p\n", pidl); 963 964 Free(pidl); 965 } 966 967 /************************************************************************* 968 * ILCreateFromPathA [SHELL32.189] 969 * 970 * Creates a complex ItemIDList from a path and returns it. 971 * 972 * PARAMS 973 * path [I] 974 * 975 * RETURNS 976 * the newly created complex ItemIDList or NULL if failed 977 * 978 * NOTES 979 * exported by ordinal. 980 */ 981 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) 982 { 983 LPITEMIDLIST pidlnew = NULL; 984 985 TRACE_(shell)("%s\n", debugstr_a(path)); 986 987 if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL))) 988 return pidlnew; 989 return NULL; 990 } 991 992 /************************************************************************* 993 * ILCreateFromPathW [SHELL32.190] 994 * 995 * See ILCreateFromPathA. 996 */ 997 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) 998 { 999 LPITEMIDLIST pidlnew = NULL; 1000 1001 TRACE_(shell)("%s\n", debugstr_w(path)); 1002 1003 if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL))) 1004 return pidlnew; 1005 return NULL; 1006 } 1007 1008 /************************************************************************* 1009 * ILCreateFromPath [SHELL32.157] 1010 */ 1011 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) 1012 { 1013 if ( SHELL_OsIsUnicode()) 1014 return ILCreateFromPathW (path); 1015 return ILCreateFromPathA (path); 1016 } 1017 1018 /************************************************************************* 1019 * _ILParsePathW [internal] 1020 * 1021 * Creates an ItemIDList from a path and returns it. 1022 * 1023 * PARAMS 1024 * path [I] path to parse and convert into an ItemIDList 1025 * lpFindFile [I] pointer to buffer to initialize the FileSystem 1026 * Bind Data object with 1027 * bBindCtx [I] indicates to create a BindContext and assign a 1028 * FileSystem Bind Data object 1029 * ppidl [O] the newly create ItemIDList 1030 * prgfInOut [I/O] requested attributes on input and actual 1031 * attributes on return 1032 * 1033 * RETURNS 1034 * NO_ERROR on success or an OLE error code 1035 * 1036 * NOTES 1037 * If either lpFindFile is non-NULL or bBindCtx is TRUE, this function 1038 * creates a BindContext object and assigns a FileSystem Bind Data object 1039 * to it, passing the BindContext to IShellFolder_ParseDisplayName. Each 1040 * IShellFolder uses that FileSystem Bind Data object of the BindContext 1041 * to pass data about the current path element to the next object. This 1042 * is used to avoid having to verify the current path element on disk, so 1043 * that creating an ItemIDList from a nonexistent path still can work. 1044 */ 1045 static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile, 1046 BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut) 1047 { 1048 LPSHELLFOLDER pSF = NULL; 1049 LPBC pBC = NULL; 1050 HRESULT ret; 1051 1052 TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx, 1053 ppidl, ppidl ? *ppidl : NULL, 1054 prgfInOut, prgfInOut ? *prgfInOut : 0); 1055 1056 ret = SHGetDesktopFolder(&pSF); 1057 if (FAILED(ret)) 1058 return ret; 1059 1060 if (lpFindFile || bBindCtx) 1061 ret = IFileSystemBindData_Constructor(lpFindFile, &pBC); 1062 1063 if (SUCCEEDED(ret)) 1064 { 1065 ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut); 1066 } 1067 1068 if (pBC) 1069 { 1070 IBindCtx_Release(pBC); 1071 pBC = NULL; 1072 } 1073 1074 IShellFolder_Release(pSF); 1075 1076 if (FAILED(ret) && ppidl) 1077 *ppidl = NULL; 1078 1079 TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0); 1080 1081 return ret; 1082 } 1083 1084 /************************************************************************* 1085 * SHSimpleIDListFromPath [SHELL32.162] 1086 * 1087 * Creates a simple ItemIDList from a path and returns it. This function 1088 * does not fail on nonexistent paths. 1089 * 1090 * PARAMS 1091 * path [I] path to parse and convert into an ItemIDList 1092 * 1093 * RETURNS 1094 * the newly created simple ItemIDList 1095 * 1096 * NOTES 1097 * Simple in the name does not mean a relative ItemIDList but rather a 1098 * fully qualified list, where only the file name is filled in and the 1099 * directory flag for those ItemID elements this is known about, eg. 1100 * it is not the last element in the ItemIDList or the actual directory 1101 * exists on disk. 1102 * exported by ordinal. 1103 */ 1104 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) 1105 { 1106 LPITEMIDLIST pidl = NULL; 1107 LPWSTR wPath = NULL; 1108 int len; 1109 1110 TRACE("%s\n", debugstr_a(lpszPath)); 1111 1112 if (lpszPath) 1113 { 1114 len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0); 1115 wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1116 MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); 1117 } 1118 1119 _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); 1120 1121 HeapFree(GetProcessHeap(), 0, wPath); 1122 TRACE("%s %p\n", debugstr_a(lpszPath), pidl); 1123 return pidl; 1124 } 1125 1126 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) 1127 { 1128 LPITEMIDLIST pidl = NULL; 1129 1130 TRACE("%s\n", debugstr_w(lpszPath)); 1131 1132 _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); 1133 1134 TRACE("%s %p\n", debugstr_w(lpszPath), pidl); 1135 return pidl; 1136 } 1137 1138 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) 1139 { 1140 if ( SHELL_OsIsUnicode()) 1141 return SHSimpleIDListFromPathW (lpszPath); 1142 return SHSimpleIDListFromPathA (lpszPath); 1143 } 1144 1145 /************************************************************************* 1146 * SHGetDataFromIDListA [SHELL32.247] 1147 * 1148 * NOTES 1149 * the pidl can be a simple one. since we can't get the path out of the pidl 1150 * we have to take all data from the pidl 1151 */ 1152 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1153 int nFormat, LPVOID dest, int len) 1154 { 1155 LPSTR filename, shortname; 1156 WIN32_FIND_DATAA * pfd; 1157 1158 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1159 1160 pdump(pidl); 1161 if (!psf || !dest) 1162 return E_INVALIDARG; 1163 1164 switch (nFormat) 1165 { 1166 case SHGDFIL_FINDDATA: 1167 pfd = dest; 1168 1169 if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) 1170 return E_INVALIDARG; 1171 1172 if (len < sizeof(WIN32_FIND_DATAA)) 1173 return E_INVALIDARG; 1174 1175 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); 1176 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1177 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1178 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1179 1180 filename = _ILGetTextPointer(pidl); 1181 shortname = _ILGetSTextPointer(pidl); 1182 1183 if (filename) 1184 lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); 1185 else 1186 pfd->cFileName[0] = '\0'; 1187 1188 if (shortname) 1189 lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); 1190 else 1191 pfd->cAlternateFileName[0] = '\0'; 1192 return S_OK; 1193 1194 case SHGDFIL_NETRESOURCE: 1195 case SHGDFIL_DESCRIPTIONID: 1196 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1197 break; 1198 1199 default: 1200 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1201 } 1202 1203 return E_INVALIDARG; 1204 } 1205 1206 /************************************************************************* 1207 * SHGetDataFromIDListW [SHELL32.248] 1208 * 1209 */ 1210 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1211 int nFormat, LPVOID dest, int len) 1212 { 1213 LPSTR filename, shortname; 1214 WIN32_FIND_DATAW * pfd = dest; 1215 1216 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1217 1218 pdump(pidl); 1219 1220 if (!psf || !dest) 1221 return E_INVALIDARG; 1222 1223 switch (nFormat) 1224 { 1225 case SHGDFIL_FINDDATA: 1226 pfd = dest; 1227 1228 if (_ILIsDrive(pidl)) 1229 return E_INVALIDARG; 1230 1231 if (len < sizeof(WIN32_FIND_DATAW)) 1232 return E_INVALIDARG; 1233 1234 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW)); 1235 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1236 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1237 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1238 1239 filename = _ILGetTextPointer(pidl); 1240 shortname = _ILGetSTextPointer(pidl); 1241 1242 if (!filename) 1243 pfd->cFileName[0] = '\0'; 1244 else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) 1245 pfd->cFileName[MAX_PATH-1] = 0; 1246 1247 if (!shortname) 1248 pfd->cAlternateFileName[0] = '\0'; 1249 else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) 1250 pfd->cAlternateFileName[13] = 0; 1251 return S_OK; 1252 1253 case SHGDFIL_NETRESOURCE: 1254 case SHGDFIL_DESCRIPTIONID: 1255 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1256 break; 1257 1258 default: 1259 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1260 } 1261 1262 return E_INVALIDARG; 1263 } 1264 1265 /************************************************************************* 1266 * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220] 1267 * 1268 * PARAMETERS 1269 * pidl, [IN] pidl 1270 * pszPath [OUT] path 1271 * 1272 * RETURNS 1273 * path from a passed PIDL. 1274 * 1275 * NOTES 1276 * NULL returns FALSE 1277 * desktop pidl gives path to desktop directory back 1278 * special pidls returning FALSE 1279 */ 1280 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) 1281 { 1282 WCHAR wszPath[MAX_PATH]; 1283 BOOL bSuccess; 1284 1285 bSuccess = SHGetPathFromIDListW(pidl, wszPath); 1286 WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); 1287 1288 return bSuccess; 1289 } 1290 1291 /************************************************************************* 1292 * SHGetPathFromIDListW [SHELL32.@] 1293 * 1294 * See SHGetPathFromIDListA. 1295 */ 1296 HRESULT WINAPI 1297 SHGetPathCchFromIDListW( 1298 _In_ LPCITEMIDLIST pidl, 1299 _Out_writes_(cchPathMax) LPWSTR pszPath, 1300 _In_ SIZE_T cchPathMax) 1301 { 1302 HRESULT hr; 1303 LPCITEMIDLIST pidlLast; 1304 LPSHELLFOLDER psfFolder; 1305 DWORD dwAttributes; 1306 STRRET strret; 1307 1308 TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); 1309 pdump(pidl); 1310 1311 *pszPath = UNICODE_NULL; 1312 if (!pidl) 1313 return E_FAIL; 1314 1315 hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); 1316 if (FAILED(hr)) 1317 { 1318 ERR("SHBindToParent failed: %x\n", hr); 1319 return hr; 1320 } 1321 1322 dwAttributes = SFGAO_FILESYSTEM; 1323 hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); 1324 if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) 1325 { 1326 WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr); 1327 IShellFolder_Release(psfFolder); 1328 return E_FAIL; 1329 } 1330 1331 hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); 1332 IShellFolder_Release(psfFolder); 1333 if (FAILED(hr)) 1334 return hr; 1335 1336 hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax); 1337 1338 TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); 1339 return hr; 1340 } 1341 1342 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) 1343 { 1344 return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH)); 1345 } 1346 1347 /************************************************************************* 1348 * SHBindToParent [shell version 5.0] 1349 */ 1350 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) 1351 { 1352 IShellFolder * psfDesktop; 1353 HRESULT hr=E_FAIL; 1354 1355 TRACE_(shell)("pidl=%p\n", pidl); 1356 pdump(pidl); 1357 1358 if (!pidl || !ppv) 1359 return E_INVALIDARG; 1360 1361 *ppv = NULL; 1362 if (ppidlLast) 1363 *ppidlLast = NULL; 1364 1365 hr = SHGetDesktopFolder(&psfDesktop); 1366 if (FAILED(hr)) 1367 return hr; 1368 1369 if (_ILIsPidlSimple(pidl)) 1370 { 1371 /* we are on desktop level */ 1372 hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv); 1373 } 1374 else 1375 { 1376 LPITEMIDLIST pidlParent = ILClone(pidl); 1377 ILRemoveLastID(pidlParent); 1378 hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv); 1379 SHFree (pidlParent); 1380 } 1381 1382 IShellFolder_Release(psfDesktop); 1383 1384 if (SUCCEEDED(hr) && ppidlLast) 1385 *ppidlLast = ILFindLastID(pidl); 1386 1387 TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); 1388 return hr; 1389 } 1390 1391 /************************************************************************* 1392 * SHParseDisplayName [shell version 6.0] 1393 */ 1394 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, 1395 LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) 1396 { 1397 HRESULT hr; 1398 LPWSTR pszNameDup; 1399 IShellFolder *psfDesktop; 1400 IBindCtx *pBindCtx = NULL; 1401 1402 TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut); 1403 1404 *ppidl = NULL; 1405 1406 if (psfgaoOut) 1407 *psfgaoOut = 0; 1408 1409 pszNameDup = StrDupW(pszName); 1410 if (!pszNameDup) 1411 return E_OUTOFMEMORY; 1412 1413 psfDesktop = NULL; 1414 hr = SHGetDesktopFolder(&psfDesktop); 1415 if (FAILED(hr)) 1416 { 1417 LocalFree(pszNameDup); 1418 return hr; 1419 } 1420 1421 if (!pbc) 1422 { 1423 hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx); 1424 pbc = pBindCtx; 1425 } 1426 1427 if (SUCCEEDED(hr)) 1428 { 1429 ULONG sfgao = sfgaoIn, cchEaten; 1430 HWND hwndUI = BindCtx_GetUIWindow(pbc); 1431 hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop, 1432 hwndUI, 1433 pbc, 1434 pszNameDup, 1435 &cchEaten, 1436 ppidl, 1437 (psfgaoOut ? &sfgao : NULL)); 1438 if (SUCCEEDED(hr) && psfgaoOut) 1439 *psfgaoOut = (sfgao & sfgaoIn); 1440 } 1441 1442 LocalFree(pszNameDup); 1443 1444 if (psfDesktop) 1445 psfDesktop->lpVtbl->Release(psfDesktop); 1446 1447 if (pBindCtx) 1448 pBindCtx->lpVtbl->Release(pBindCtx); 1449 1450 return hr; 1451 } 1452 1453 /************************************************************************* 1454 * SHGetNameFromIDList [SHELL32.@] 1455 */ 1456 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName) 1457 { 1458 IShellFolder *psfparent; 1459 LPCITEMIDLIST child_pidl; 1460 STRRET disp_name; 1461 HRESULT ret; 1462 1463 TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName); 1464 1465 *ppszName = NULL; 1466 ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl); 1467 if(SUCCEEDED(ret)) 1468 { 1469 switch(sigdnName) 1470 { 1471 /* sigdnName & 0xffff */ 1472 case SIGDN_NORMALDISPLAY: /* SHGDN_NORMAL */ 1473 case SIGDN_PARENTRELATIVEPARSING: /* SHGDN_INFOLDER | SHGDN_FORPARSING */ 1474 case SIGDN_PARENTRELATIVEEDITING: /* SHGDN_INFOLDER | SHGDN_FOREDITING */ 1475 case SIGDN_DESKTOPABSOLUTEPARSING: /* SHGDN_FORPARSING */ 1476 case SIGDN_DESKTOPABSOLUTEEDITING: /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/ 1477 case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */ 1478 case SIGDN_PARENTRELATIVE: /* SIGDN_INFOLDER */ 1479 1480 disp_name.uType = STRRET_WSTR; 1481 ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl, 1482 sigdnName & 0xffff, 1483 &disp_name); 1484 if(SUCCEEDED(ret)) 1485 ret = StrRetToStrW(&disp_name, pidl, ppszName); 1486 1487 break; 1488 1489 case SIGDN_FILESYSPATH: 1490 *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH); 1491 if(SHGetPathFromIDListW(pidl, *ppszName)) 1492 { 1493 TRACE("Got string %s\n", debugstr_w(*ppszName)); 1494 ret = S_OK; 1495 } 1496 else 1497 { 1498 CoTaskMemFree(*ppszName); 1499 ret = E_INVALIDARG; 1500 } 1501 break; 1502 1503 case SIGDN_URL: 1504 default: 1505 FIXME("Unsupported SIGDN %x\n", sigdnName); 1506 ret = E_FAIL; 1507 } 1508 1509 IShellFolder_Release(psfparent); 1510 } 1511 return ret; 1512 } 1513 1514 #ifndef __REACTOS__ 1515 1516 /************************************************************************* 1517 * SHGetIDListFromObject [SHELL32.@] 1518 */ 1519 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) 1520 { 1521 IPersistIDList *ppersidl; 1522 IPersistFolder2 *ppf2; 1523 IDataObject *pdo; 1524 IFolderView *pfv; 1525 HRESULT ret; 1526 1527 if(!punk) 1528 return E_NOINTERFACE; 1529 1530 *ppidl = NULL; 1531 1532 /* Try IPersistIDList */ 1533 ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl); 1534 if(SUCCEEDED(ret)) 1535 { 1536 TRACE("IPersistIDList (%p)\n", ppersidl); 1537 ret = IPersistIDList_GetIDList(ppersidl, ppidl); 1538 IPersistIDList_Release(ppersidl); 1539 if(SUCCEEDED(ret)) 1540 return ret; 1541 } 1542 1543 /* Try IPersistFolder2 */ 1544 ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2); 1545 if(SUCCEEDED(ret)) 1546 { 1547 TRACE("IPersistFolder2 (%p)\n", ppf2); 1548 ret = IPersistFolder2_GetCurFolder(ppf2, ppidl); 1549 IPersistFolder2_Release(ppf2); 1550 if(SUCCEEDED(ret)) 1551 return ret; 1552 } 1553 1554 /* Try IDataObject */ 1555 ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo); 1556 if(SUCCEEDED(ret)) 1557 { 1558 IShellItem *psi; 1559 TRACE("IDataObject (%p)\n", pdo); 1560 ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, 1561 &IID_IShellItem, (void**)&psi); 1562 if(SUCCEEDED(ret)) 1563 { 1564 ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); 1565 IShellItem_Release(psi); 1566 } 1567 IDataObject_Release(pdo); 1568 1569 if(SUCCEEDED(ret)) 1570 return ret; 1571 } 1572 1573 /* Try IFolderView */ 1574 ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv); 1575 if(SUCCEEDED(ret)) 1576 { 1577 IShellFolder *psf; 1578 TRACE("IFolderView (%p)\n", pfv); 1579 ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf); 1580 if(SUCCEEDED(ret)) 1581 { 1582 /* We might be able to get IPersistFolder2 from a shellfolder. */ 1583 ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); 1584 } 1585 IFolderView_Release(pfv); 1586 return ret; 1587 } 1588 1589 return ret; 1590 } 1591 1592 #endif /* !__REACTOS__ */ 1593 1594 /************************************************************************** 1595 * 1596 * internal functions 1597 * 1598 * ### 1. section creating pidls ### 1599 * 1600 ************************************************************************* 1601 */ 1602 1603 /* Basic PIDL constructor. Allocates size + 5 bytes, where: 1604 * - two bytes are SHITEMID.cb 1605 * - one byte is PIDLDATA.type 1606 * - two bytes are the NULL PIDL terminator 1607 * Sets type of the returned PIDL to type. 1608 */ 1609 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) 1610 { 1611 LPITEMIDLIST pidlOut = NULL; 1612 1613 pidlOut = SHAlloc(size + 5); 1614 if(pidlOut) 1615 { 1616 LPPIDLDATA pData; 1617 LPITEMIDLIST pidlNext; 1618 1619 ZeroMemory(pidlOut, size + 5); 1620 pidlOut->mkid.cb = size + 3; 1621 1622 pData = _ILGetDataPointer(pidlOut); 1623 if (pData) 1624 pData->type = type; 1625 1626 pidlNext = ILGetNext(pidlOut); 1627 if (pidlNext) 1628 pidlNext->mkid.cb = 0x00; 1629 TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); 1630 } 1631 1632 return pidlOut; 1633 } 1634 1635 LPITEMIDLIST _ILCreateDesktop(void) 1636 { 1637 LPITEMIDLIST ret; 1638 1639 TRACE("()\n"); 1640 ret = SHAlloc(2); 1641 if (ret) 1642 ret->mkid.cb = 0; 1643 return ret; 1644 } 1645 1646 LPITEMIDLIST _ILCreateMyComputer(void) 1647 { 1648 TRACE("()\n"); 1649 return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); 1650 } 1651 1652 LPITEMIDLIST _ILCreateMyDocuments(void) 1653 { 1654 TRACE("()\n"); 1655 return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); 1656 } 1657 1658 LPITEMIDLIST _ILCreateIExplore(void) 1659 { 1660 TRACE("()\n"); 1661 return _ILCreateGuid(PT_GUID, &CLSID_Internet); 1662 } 1663 1664 LPITEMIDLIST _ILCreateControlPanel(void) 1665 { 1666 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1667 1668 TRACE("()\n"); 1669 if (parent) 1670 { 1671 LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); 1672 1673 if (cpl) 1674 { 1675 ret = ILCombine(parent, cpl); 1676 SHFree(cpl); 1677 } 1678 SHFree(parent); 1679 } 1680 return ret; 1681 } 1682 1683 LPITEMIDLIST _ILCreatePrinters(void) 1684 { 1685 #ifdef __REACTOS__ 1686 // Note: Wine returns the PIDL as it was in Windows 95, NT5 moved it into CSIDL_CONTROLS 1687 extern HRESULT SHGetFolderLocationHelper(HWND hwnd, int nFolder, REFCLSID clsid, LPITEMIDLIST *ppidl); 1688 LPITEMIDLIST pidl; 1689 SHGetFolderLocationHelper(NULL, CSIDL_CONTROLS, &CLSID_Printers, &pidl); 1690 return pidl; 1691 #else 1692 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1693 1694 TRACE("()\n"); 1695 if (parent) 1696 { 1697 LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); 1698 1699 if (printers) 1700 { 1701 ret = ILCombine(parent, printers); 1702 SHFree(printers); 1703 } 1704 SHFree(parent); 1705 } 1706 return ret; 1707 #endif 1708 } 1709 1710 LPITEMIDLIST _ILCreateNetwork(void) 1711 { 1712 TRACE("()\n"); 1713 return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); 1714 } 1715 1716 LPITEMIDLIST _ILCreateBitBucket(void) 1717 { 1718 TRACE("()\n"); 1719 return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); 1720 } 1721 1722 LPITEMIDLIST _ILCreateAdminTools(void) 1723 { 1724 TRACE("()\n"); 1725 return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME 1726 } 1727 1728 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) 1729 { 1730 LPITEMIDLIST pidlOut; 1731 1732 if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) 1733 { 1734 pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); 1735 if (pidlOut) 1736 { 1737 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1738 1739 pData->u.guid.guid = *guid; 1740 TRACE("-- create GUID-pidl %s\n", 1741 debugstr_guid(&(pData->u.guid.guid))); 1742 } 1743 } 1744 else 1745 { 1746 WARN("%d: invalid type for GUID\n", type); 1747 pidlOut = NULL; 1748 } 1749 return pidlOut; 1750 } 1751 1752 #ifndef __REACTOS__ 1753 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) 1754 { 1755 IID iid; 1756 1757 if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) 1758 { 1759 ERR("%s is not a GUID\n", szGUID); 1760 return NULL; 1761 } 1762 return _ILCreateGuid(PT_GUID, &iid); 1763 } 1764 #endif 1765 1766 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) 1767 { 1768 IID iid; 1769 1770 #ifndef __REACTOS__ 1771 if (FAILED(SHCLSIDFromStringW(szGUID, &iid))) 1772 #else 1773 if (!GUIDFromStringW(szGUID, &iid)) 1774 #endif 1775 { 1776 ERR("%s is not a GUID\n", debugstr_w(szGUID)); 1777 return NULL; 1778 } 1779 return _ILCreateGuid(PT_GUID, &iid); 1780 } 1781 1782 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) 1783 { 1784 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ 1785 DWORD len, len1, wlen, alen; 1786 LPITEMIDLIST pidl; 1787 PIDLTYPE type; 1788 1789 if (!wfd) 1790 return NULL; 1791 1792 TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); 1793 1794 /* prepare buffer with both names */ 1795 len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); 1796 len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); 1797 alen = len + len1; 1798 1799 type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; 1800 1801 wlen = lstrlenW(wfd->cFileName) + 1; 1802 pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + 1803 FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); 1804 if (pidl) 1805 { 1806 LPPIDLDATA pData = _ILGetDataPointer(pidl); 1807 FileStruct *fs = &pData->u.file; 1808 FileStructW *fsw; 1809 WORD *pOffsetW; 1810 1811 FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); 1812 fs->dwFileSize = wfd->nFileSizeLow; 1813 fs->uFileAttribs = wfd->dwFileAttributes; 1814 memcpy(fs->szNames, buff, alen); 1815 1816 fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); 1817 fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); 1818 FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); 1819 FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); 1820 memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); 1821 1822 pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); 1823 *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; 1824 TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); 1825 } 1826 return pidl; 1827 1828 } 1829 1830 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) 1831 { 1832 HANDLE hFile; 1833 WIN32_FIND_DATAW stffile; 1834 1835 if (!ppidl) 1836 return E_INVALIDARG; 1837 1838 hFile = FindFirstFileW(szPath, &stffile); 1839 if (hFile == INVALID_HANDLE_VALUE) 1840 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 1841 1842 FindClose(hFile); 1843 1844 *ppidl = _ILCreateFromFindDataW(&stffile); 1845 1846 return *ppidl ? S_OK : E_OUTOFMEMORY; 1847 } 1848 1849 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) 1850 { 1851 LPITEMIDLIST pidlOut; 1852 1853 TRACE("(%s)\n",debugstr_w(lpszNew)); 1854 1855 pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); 1856 if (pidlOut) 1857 { 1858 LPSTR pszDest; 1859 1860 pszDest = _ILGetTextPointer(pidlOut); 1861 if (pszDest) 1862 { 1863 strcpy(pszDest, "x:\\"); 1864 pszDest[0]=toupperW(lpszNew[0]); 1865 TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); 1866 } 1867 } 1868 return pidlOut; 1869 } 1870 1871 LPITEMIDLIST _ILCreateEntireNetwork(void) 1872 { 1873 LPITEMIDLIST pidlOut; 1874 1875 TRACE("\n"); 1876 1877 pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); 1878 if (pidlOut) 1879 { 1880 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1881 1882 pData->u.network.dummy = 0; 1883 strcpy(pData->u.network.szNames, "Entire Network"); 1884 } 1885 return pidlOut; 1886 } 1887 1888 /************************************************************************** 1889 * _ILGetDrive() 1890 * 1891 * Gets the text for the drive eg. 'c:\' 1892 * 1893 * RETURNS 1894 * strlen (lpszText) 1895 */ 1896 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) 1897 { 1898 TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); 1899 1900 if(_ILIsMyComputer(pidl)) 1901 pidl = ILGetNext(pidl); 1902 1903 if (pidl && _ILIsDrive(pidl)) 1904 return _ILSimpleGetText(pidl, pOut, uSize); 1905 1906 return 0; 1907 } 1908 1909 /************************************************************************** 1910 * 1911 * ### 2. section testing pidls ### 1912 * 1913 ************************************************************************** 1914 * _ILIsUnicode() 1915 * _ILIsDesktop() 1916 * _ILIsMyComputer() 1917 * _ILIsSpecialFolder() 1918 * _ILIsDrive() 1919 * _ILIsFolder() 1920 * _ILIsValue() 1921 * _ILIsPidlSimple() 1922 */ 1923 BOOL _ILIsUnicode(LPCITEMIDLIST pidl) 1924 { 1925 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1926 1927 TRACE("(%p)\n",pidl); 1928 1929 return (pidl && lpPData && PT_VALUEW == lpPData->type); 1930 } 1931 1932 BOOL _ILIsDesktop(LPCITEMIDLIST pidl) 1933 { 1934 TRACE("(%p)\n",pidl); 1935 1936 return !pidl || !pidl->mkid.cb; 1937 } 1938 1939 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl) 1940 { 1941 IID *iid = _ILGetGUIDPointer(pidl); 1942 1943 TRACE("(%p)\n", pidl); 1944 1945 if (iid) 1946 return IsEqualIID(iid, &CLSID_MyDocuments); 1947 return FALSE; 1948 } 1949 1950 BOOL _ILIsNetHood(LPCITEMIDLIST pidl) 1951 { 1952 IID *iid = _ILGetGUIDPointer(pidl); 1953 1954 TRACE("(%p)\n", pidl); 1955 1956 if (iid) 1957 return IsEqualIID(iid, &CLSID_NetworkPlaces); 1958 return FALSE; 1959 } 1960 1961 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl) 1962 { 1963 IID *iid = _ILGetGUIDPointer(pidl); 1964 1965 TRACE("(%p)\n", pidl); 1966 1967 if (iid) 1968 return IsEqualIID(iid, &CLSID_ControlPanel); 1969 return FALSE; 1970 } 1971 1972 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) 1973 { 1974 REFIID iid = _ILGetGUIDPointer(pidl); 1975 1976 TRACE("(%p)\n",pidl); 1977 1978 if (iid) 1979 return IsEqualIID(iid, &CLSID_MyComputer); 1980 return FALSE; 1981 } 1982 1983 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl) 1984 { 1985 IID *iid = _ILGetGUIDPointer(pidl); 1986 1987 TRACE("(%p)\n", pidl); 1988 1989 if (iid) 1990 return IsEqualIID(iid, &CLSID_RecycleBin); 1991 return FALSE; 1992 } 1993 1994 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) 1995 { 1996 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1997 1998 TRACE("(%p)\n",pidl); 1999 2000 return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || 2001 (pidl && pidl->mkid.cb == 0x00) 2002 )); 2003 } 2004 2005 BOOL _ILIsDrive(LPCITEMIDLIST pidl) 2006 { 2007 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2008 2009 TRACE("(%p)\n",pidl); 2010 2011 return (pidl && lpPData && (PT_DRIVE == lpPData->type || 2012 PT_DRIVE1 == lpPData->type || 2013 PT_DRIVE2 == lpPData->type || 2014 PT_DRIVE3 == lpPData->type)); 2015 } 2016 2017 BOOL _ILIsFolder(LPCITEMIDLIST pidl) 2018 { 2019 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2020 2021 TRACE("(%p)\n",pidl); 2022 2023 return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); 2024 } 2025 2026 BOOL _ILIsValue(LPCITEMIDLIST pidl) 2027 { 2028 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2029 2030 TRACE("(%p)\n",pidl); 2031 2032 return (pidl && lpPData && PT_VALUE == lpPData->type); 2033 } 2034 2035 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) 2036 { 2037 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2038 2039 TRACE("(%p)\n",pidl); 2040 2041 return (pidl && lpPData && (lpPData->type == 0)); 2042 } 2043 2044 /************************************************************************** 2045 * _ILIsPidlSimple 2046 */ 2047 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) 2048 { 2049 BOOL ret = TRUE; 2050 2051 if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */ 2052 { 2053 WORD len = pidl->mkid.cb; 2054 LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); 2055 2056 if (pidlnext->mkid.cb) 2057 ret = FALSE; 2058 } 2059 2060 TRACE("%s\n", ret ? "Yes" : "No"); 2061 return ret; 2062 } 2063 2064 /************************************************************************** 2065 * 2066 * ### 3. section getting values from pidls ### 2067 */ 2068 2069 /************************************************************************** 2070 * _ILSimpleGetText 2071 * 2072 * gets the text for the first item in the pidl (eg. simple pidl) 2073 * 2074 * returns the length of the string 2075 */ 2076 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) 2077 { 2078 DWORD dwReturn=0; 2079 LPSTR szSrc; 2080 LPWSTR szSrcW; 2081 GUID const * riid; 2082 char szTemp[MAX_PATH]; 2083 2084 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2085 2086 if (!pidl) 2087 return 0; 2088 2089 if (szOut) 2090 *szOut = 0; 2091 2092 if (_ILIsDesktop(pidl)) 2093 { 2094 /* desktop */ 2095 if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2096 { 2097 if (szOut) 2098 lstrcpynA(szOut, szTemp, uOutSize); 2099 2100 dwReturn = strlen (szTemp); 2101 } 2102 } 2103 else if (( szSrc = _ILGetTextPointer(pidl) )) 2104 { 2105 /* filesystem */ 2106 if (szOut) 2107 lstrcpynA(szOut, szSrc, uOutSize); 2108 2109 dwReturn = strlen(szSrc); 2110 } 2111 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2112 { 2113 /* unicode filesystem */ 2114 WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); 2115 2116 if (szOut) 2117 lstrcpynA(szOut, szTemp, uOutSize); 2118 2119 dwReturn = strlen (szTemp); 2120 } 2121 else if (( riid = _ILGetGUIDPointer(pidl) )) 2122 { 2123 /* special folder */ 2124 if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) ) 2125 { 2126 if (szOut) 2127 lstrcpynA(szOut, szTemp, uOutSize); 2128 2129 dwReturn = strlen (szTemp); 2130 } 2131 } 2132 else 2133 { 2134 ERR("-- no text\n"); 2135 } 2136 2137 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn); 2138 return dwReturn; 2139 } 2140 2141 /************************************************************************** 2142 * _ILSimpleGetTextW 2143 * 2144 * gets the text for the first item in the pidl (eg. simple pidl) 2145 * 2146 * returns the length of the string 2147 */ 2148 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) 2149 { 2150 DWORD dwReturn; 2151 FileStructW *pFileStructW = _ILGetFileStructW(pidl); 2152 2153 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2154 2155 if (pFileStructW) { 2156 lstrcpynW(szOut, pFileStructW->wszName, uOutSize); 2157 dwReturn = lstrlenW(pFileStructW->wszName); 2158 } else { 2159 GUID const * riid; 2160 WCHAR szTemp[MAX_PATH]; 2161 LPSTR szSrc; 2162 LPWSTR szSrcW; 2163 dwReturn=0; 2164 2165 if (!pidl) 2166 return 0; 2167 2168 if (szOut) 2169 *szOut = 0; 2170 2171 if (_ILIsDesktop(pidl)) 2172 { 2173 /* desktop */ 2174 if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2175 { 2176 if (szOut) 2177 lstrcpynW(szOut, szTemp, uOutSize); 2178 2179 dwReturn = lstrlenW (szTemp); 2180 } 2181 } 2182 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2183 { 2184 /* unicode filesystem */ 2185 if (szOut) 2186 lstrcpynW(szOut, szSrcW, uOutSize); 2187 2188 dwReturn = lstrlenW(szSrcW); 2189 } 2190 else if (( szSrc = _ILGetTextPointer(pidl) )) 2191 { 2192 /* filesystem */ 2193 MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); 2194 2195 if (szOut) 2196 lstrcpynW(szOut, szTemp, uOutSize); 2197 2198 dwReturn = lstrlenW (szTemp); 2199 } 2200 else if (( riid = _ILGetGUIDPointer(pidl) )) 2201 { 2202 /* special folder */ 2203 if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) ) 2204 { 2205 if (szOut) 2206 lstrcpynW(szOut, szTemp, uOutSize); 2207 2208 dwReturn = lstrlenW (szTemp); 2209 } 2210 } 2211 else 2212 { 2213 ERR("-- no text\n"); 2214 } 2215 } 2216 2217 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); 2218 return dwReturn; 2219 } 2220 2221 /************************************************************************** 2222 * 2223 * ### 4. getting pointers to parts of pidls ### 2224 * 2225 ************************************************************************** 2226 * _ILGetDataPointer() 2227 */ 2228 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) 2229 { 2230 if(!_ILIsEmpty(pidl)) 2231 return (LPPIDLDATA)pidl->mkid.abID; 2232 return NULL; 2233 } 2234 2235 /************************************************************************** 2236 * _ILGetTextPointerW() 2237 * gets a pointer to the unicode long filename string stored in the pidl 2238 */ 2239 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) 2240 { 2241 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2242 2243 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2244 2245 if (!pdata) 2246 return NULL; 2247 2248 switch (pdata->type) 2249 { 2250 case PT_GUID: 2251 case PT_SHELLEXT: 2252 case PT_YAGUID: 2253 return NULL; 2254 2255 case PT_DRIVE: 2256 case PT_DRIVE1: 2257 case PT_DRIVE2: 2258 case PT_DRIVE3: 2259 /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ 2260 return NULL; 2261 2262 case PT_FOLDER: 2263 case PT_FOLDER1: 2264 case PT_VALUE: 2265 case PT_IESPECIAL1: 2266 case PT_IESPECIAL2: 2267 /*return (LPSTR)&(pdata->u.file.szNames);*/ 2268 return NULL; 2269 2270 case PT_WORKGRP: 2271 case PT_COMP: 2272 case PT_NETWORK: 2273 case PT_NETPROVIDER: 2274 case PT_SHARE: 2275 /*return (LPSTR)&(pdata->u.network.szNames);*/ 2276 return NULL; 2277 2278 case PT_VALUEW: 2279 return (LPWSTR)pdata->u.file.szNames; 2280 2281 #ifdef __REACTOS__ /* r54423 */ 2282 case PT_CPLAPPLET: 2283 return pdata->u.cpanel.szName; 2284 #endif 2285 2286 } 2287 return NULL; 2288 } 2289 2290 2291 /************************************************************************** 2292 * _ILGetTextPointer() 2293 * gets a pointer to the long filename string stored in the pidl 2294 */ 2295 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) 2296 { 2297 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2298 2299 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2300 2301 if (!pdata) 2302 return NULL; 2303 2304 switch (pdata->type) 2305 { 2306 case PT_GUID: 2307 case PT_SHELLEXT: 2308 case PT_YAGUID: 2309 return NULL; 2310 2311 case PT_DRIVE: 2312 case PT_DRIVE1: 2313 case PT_DRIVE2: 2314 case PT_DRIVE3: 2315 return pdata->u.drive.szDriveName; 2316 2317 case PT_FOLDER: 2318 case PT_FOLDER1: 2319 case PT_VALUE: 2320 case PT_IESPECIAL1: 2321 case PT_IESPECIAL2: 2322 return pdata->u.file.szNames; 2323 2324 case PT_WORKGRP: 2325 case PT_COMP: 2326 case PT_NETWORK: 2327 case PT_NETPROVIDER: 2328 case PT_SHARE: 2329 return pdata->u.network.szNames; 2330 } 2331 return NULL; 2332 } 2333 2334 /************************************************************************** 2335 * _ILGetSTextPointer() 2336 * gets a pointer to the short filename string stored in the pidl 2337 */ 2338 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) 2339 { 2340 /* TRACE(pidl,"(pidl%p)\n", pidl); */ 2341 2342 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2343 2344 if (!pdata) 2345 return NULL; 2346 2347 switch (pdata->type) 2348 { 2349 case PT_FOLDER: 2350 case PT_VALUE: 2351 case PT_IESPECIAL1: 2352 case PT_IESPECIAL2: 2353 return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; 2354 2355 case PT_WORKGRP: 2356 return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; 2357 } 2358 return NULL; 2359 } 2360 2361 /************************************************************************** 2362 * _ILGetGUIDPointer() 2363 * 2364 * returns reference to guid stored in some pidls 2365 */ 2366 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) 2367 { 2368 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2369 2370 TRACE("%p\n", pidl); 2371 2372 if (!pdata) 2373 return NULL; 2374 2375 TRACE("pdata->type 0x%04x\n", pdata->type); 2376 switch (pdata->type) 2377 { 2378 case PT_SHELLEXT: 2379 case PT_GUID: 2380 case PT_YAGUID: 2381 return &(pdata->u.guid.guid); 2382 2383 default: 2384 TRACE("Unknown pidl type 0x%04x\n", pdata->type); 2385 break; 2386 } 2387 return NULL; 2388 } 2389 2390 /****************************************************************************** 2391 * _ILGetFileStructW [Internal] 2392 * 2393 * Get pointer the a SHITEMID's FileStructW field if present 2394 * 2395 * PARAMS 2396 * pidl [I] The SHITEMID 2397 * 2398 * RETURNS 2399 * Success: Pointer to pidl's FileStructW field. 2400 * Failure: NULL 2401 */ 2402 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { 2403 FileStructW *pFileStructW; 2404 WORD cbOffset; 2405 2406 if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) 2407 return NULL; 2408 2409 cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); 2410 pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); 2411 2412 /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP 2413 * style with a FileStructW member. If we switch all our shellfolder-implementations to 2414 * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ 2415 if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */ 2416 /* FileStructW is positioned after FileStruct */ 2417 cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || 2418 /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ 2419 cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || 2420 pidl->mkid.cb != cbOffset + pFileStructW->cbLen) 2421 { 2422 WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); 2423 return NULL; 2424 } 2425 2426 return pFileStructW; 2427 } 2428 2429 /************************************************************************* 2430 * _ILGetFileDateTime 2431 * 2432 * Given the ItemIdList, get the FileTime 2433 * 2434 * PARAMS 2435 * pidl [I] The ItemIDList 2436 * pFt [I] the resulted FILETIME of the file 2437 * 2438 * RETURNS 2439 * True if Successful 2440 * 2441 * NOTES 2442 * 2443 */ 2444 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) 2445 { 2446 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2447 2448 if (!pdata) 2449 return FALSE; 2450 2451 switch (pdata->type) 2452 { 2453 case PT_FOLDER: 2454 case PT_VALUE: 2455 DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); 2456 break; 2457 default: 2458 return FALSE; 2459 } 2460 return TRUE; 2461 } 2462 2463 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2464 { 2465 FILETIME ft,lft; 2466 SYSTEMTIME time; 2467 BOOL ret; 2468 2469 if (_ILGetFileDateTime( pidl, &ft )) 2470 { 2471 FileTimeToLocalFileTime(&ft, &lft); 2472 FileTimeToSystemTime (&lft, &time); 2473 2474 ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize); 2475 if (ret) 2476 { 2477 /* Append space + time without seconds */ 2478 pOut[ret-1] = ' '; 2479 GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); 2480 } 2481 } 2482 else 2483 { 2484 pOut[0] = '\0'; 2485 ret = FALSE; 2486 } 2487 return ret; 2488 } 2489 2490 /************************************************************************* 2491 * _ILGetFileSize 2492 * 2493 * Given the ItemIdList, get the FileSize 2494 * 2495 * PARAMS 2496 * pidl [I] The ItemIDList 2497 * pOut [I] The buffer to save the result 2498 * uOutsize [I] The size of the buffer 2499 * 2500 * RETURNS 2501 * The FileSize 2502 * 2503 * NOTES 2504 * pOut can be null when no string is needed 2505 * 2506 */ 2507 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2508 { 2509 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2510 DWORD dwSize; 2511 2512 if (!pdata) 2513 return 0; 2514 2515 switch (pdata->type) 2516 { 2517 case PT_VALUE: 2518 dwSize = pdata->u.file.dwFileSize; 2519 if (pOut) 2520 StrFormatKBSizeA(dwSize, pOut, uOutSize); 2521 return dwSize; 2522 } 2523 if (pOut) 2524 *pOut = 0x00; 2525 return 0; 2526 } 2527 2528 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2529 { 2530 char szTemp[MAX_PATH]; 2531 const char * pPoint; 2532 LPCITEMIDLIST pidlTemp=pidl; 2533 2534 TRACE("pidl=%p\n",pidl); 2535 2536 if (!pidl) 2537 return FALSE; 2538 2539 pidlTemp = ILFindLastID(pidl); 2540 2541 if (!_ILIsValue(pidlTemp)) 2542 return FALSE; 2543 if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) 2544 return FALSE; 2545 2546 pPoint = PathFindExtensionA(szTemp); 2547 2548 if (!*pPoint) 2549 return FALSE; 2550 2551 pPoint++; 2552 lstrcpynA(pOut, pPoint, uOutSize); 2553 TRACE("%s\n",pOut); 2554 2555 return TRUE; 2556 } 2557 2558 /************************************************************************* 2559 * _ILGetFileType 2560 * 2561 * Given the ItemIdList, get the file type description 2562 * 2563 * PARAMS 2564 * pidl [I] The ItemIDList (simple) 2565 * pOut [I] The buffer to save the result 2566 * uOutsize [I] The size of the buffer 2567 * 2568 * RETURNS 2569 * nothing 2570 * 2571 * NOTES 2572 * This function copies as much as possible into the buffer. 2573 */ 2574 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2575 { 2576 #ifdef __REACTOS__ /* r32966 */ 2577 char sType[64]; 2578 #endif 2579 2580 if(_ILIsValue(pidl)) 2581 { 2582 char sTemp[64]; 2583 2584 if(uOutSize > 0) 2585 pOut[0] = 0; 2586 #ifdef __REACTOS__ /* r32966 */ 2587 if (_ILGetExtension (pidl, sType, 64)) 2588 { 2589 if (HCR_MapTypeToValueA(sType, sTemp, 64, TRUE)) 2590 { 2591 /* retrieve description */ 2592 if(HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )) 2593 return; 2594 } 2595 /* display Ext-file as description */ 2596 _strupr(sType); 2597 /* load localized file string */ 2598 sTemp[0] = '\0'; 2599 if(LoadStringA(shell32_hInstance, IDS_ANY_FILE, sTemp, 64)) 2600 { 2601 sTemp[63] = '\0'; 2602 StringCchPrintfA(pOut, uOutSize, sTemp, sType); 2603 } 2604 } 2605 #else 2606 if (_ILGetExtension (pidl, sTemp, 64)) 2607 { 2608 if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE) 2609 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE ))) 2610 { 2611 lstrcpynA (pOut, sTemp, uOutSize - 6); 2612 strcat (pOut, "-file"); 2613 } 2614 } 2615 #endif 2616 } 2617 else 2618 #ifdef __REACTOS__ /* r32966 */ 2619 { 2620 pOut[0] = '\0'; 2621 LoadStringA(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize); 2622 /* make sure its null terminated */ 2623 pOut[uOutSize-1] = '\0'; 2624 } 2625 #else 2626 lstrcpynA(pOut, "Folder", uOutSize); 2627 #endif 2628 } 2629 2630 /************************************************************************* 2631 * _ILGetFileAttributes 2632 * 2633 * Given the ItemIdList, get the Attrib string format 2634 * 2635 * PARAMS 2636 * pidl [I] The ItemIDList 2637 * pOut [I] The buffer to save the result 2638 * uOutsize [I] The size of the Buffer 2639 * 2640 * RETURNS 2641 * Attributes 2642 * 2643 * FIXME 2644 * return value 0 in case of error is a valid return value 2645 * 2646 */ 2647 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2648 { 2649 LPPIDLDATA pData = _ILGetDataPointer(pidl); 2650 WORD wAttrib = 0; 2651 int i; 2652 2653 if (!pData) 2654 return 0; 2655 2656 switch(pData->type) 2657 { 2658 case PT_FOLDER: 2659 case PT_VALUE: 2660 wAttrib = pData->u.file.uFileAttribs; 2661 break; 2662 } 2663 2664 if(uOutSize >= 6) 2665 { 2666 i=0; 2667 if(wAttrib & FILE_ATTRIBUTE_READONLY) 2668 pOut[i++] = 'R'; 2669 if(wAttrib & FILE_ATTRIBUTE_HIDDEN) 2670 pOut[i++] = 'H'; 2671 if(wAttrib & FILE_ATTRIBUTE_SYSTEM) 2672 pOut[i++] = 'S'; 2673 if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) 2674 pOut[i++] = 'A'; 2675 if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) 2676 pOut[i++] = 'C'; 2677 pOut[i] = 0x00; 2678 } 2679 return wAttrib; 2680 } 2681 2682 /************************************************************************* 2683 * ILFreeaPidl 2684 * 2685 * frees an aPidl struct 2686 */ 2687 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) 2688 { 2689 UINT i; 2690 2691 if (apidl) 2692 { 2693 for (i = 0; i < cidl; i++) 2694 SHFree(apidl[i]); 2695 SHFree(apidl); 2696 } 2697 } 2698 2699 /************************************************************************* 2700 * ILCopyaPidl 2701 * 2702 * copies an aPidl struct 2703 */ 2704 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl) 2705 { 2706 UINT i; 2707 PITEMID_CHILD *apidldest; 2708 2709 if (!apidlsrc) 2710 return NULL; 2711 2712 apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD)); 2713 2714 for (i = 0; i < cidl; i++) 2715 apidldest[i] = ILClone(apidlsrc[i]); 2716 2717 return apidldest; 2718 } 2719 2720 /************************************************************************* 2721 * _ILCopyCidaToaPidl 2722 * 2723 * creates aPidl from CIDA 2724 */ 2725 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) 2726 { 2727 UINT i; 2728 LPITEMIDLIST *dst; 2729 2730 dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); 2731 if (!dst) 2732 return NULL; 2733 2734 if (pidl) 2735 *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); 2736 2737 for (i = 0; i < cida->cidl; i++) 2738 dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); 2739 2740 return dst; 2741 } 2742