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 = _ILGetTextPointer(pidlOut); 1859 if (pszDest) 1860 { 1861 lstrcpyA(pszDest, "x:\\"); 1862 pszDest[0] = toupper(lpszNew[0]); 1863 TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); 1864 } 1865 } 1866 return pidlOut; 1867 } 1868 1869 LPITEMIDLIST _ILCreateEntireNetwork(void) 1870 { 1871 LPITEMIDLIST pidlOut; 1872 1873 TRACE("\n"); 1874 1875 pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); 1876 if (pidlOut) 1877 { 1878 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1879 1880 pData->u.network.dummy = 0; 1881 strcpy(pData->u.network.szNames, "Entire Network"); 1882 } 1883 return pidlOut; 1884 } 1885 1886 /************************************************************************** 1887 * _ILGetDrive() 1888 * 1889 * Gets the text for the drive eg. 'c:\' 1890 * 1891 * RETURNS 1892 * strlen (lpszText) 1893 */ 1894 DWORD _ILGetDrive(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uSize) 1895 { 1896 TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); 1897 1898 if(_ILIsMyComputer(pidl)) 1899 pidl = ILGetNext(pidl); 1900 1901 if (pidl && _ILIsDrive(pidl)) 1902 return _ILSimpleGetTextW(pidl, pOut, uSize); 1903 1904 return 0; 1905 } 1906 1907 /************************************************************************** 1908 * 1909 * ### 2. section testing pidls ### 1910 * 1911 ************************************************************************** 1912 * _ILIsUnicode() 1913 * _ILIsDesktop() 1914 * _ILIsMyComputer() 1915 * _ILIsSpecialFolder() 1916 * _ILIsDrive() 1917 * _ILIsFolder() 1918 * _ILIsValue() 1919 * _ILIsPidlSimple() 1920 */ 1921 BOOL _ILIsUnicode(LPCITEMIDLIST pidl) 1922 { 1923 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1924 1925 TRACE("(%p)\n",pidl); 1926 1927 return (pidl && lpPData && PT_VALUEW == lpPData->type); 1928 } 1929 1930 BOOL _ILIsDesktop(LPCITEMIDLIST pidl) 1931 { 1932 TRACE("(%p)\n",pidl); 1933 1934 return !pidl || !pidl->mkid.cb; 1935 } 1936 1937 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl) 1938 { 1939 IID *iid = _ILGetGUIDPointer(pidl); 1940 1941 TRACE("(%p)\n", pidl); 1942 1943 if (iid) 1944 return IsEqualIID(iid, &CLSID_MyDocuments); 1945 return FALSE; 1946 } 1947 1948 BOOL _ILIsNetHood(LPCITEMIDLIST pidl) 1949 { 1950 IID *iid = _ILGetGUIDPointer(pidl); 1951 1952 TRACE("(%p)\n", pidl); 1953 1954 if (iid) 1955 return IsEqualIID(iid, &CLSID_NetworkPlaces); 1956 return FALSE; 1957 } 1958 1959 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl) 1960 { 1961 IID *iid = _ILGetGUIDPointer(pidl); 1962 1963 TRACE("(%p)\n", pidl); 1964 1965 if (iid) 1966 return IsEqualIID(iid, &CLSID_ControlPanel); 1967 return FALSE; 1968 } 1969 1970 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) 1971 { 1972 REFIID iid = _ILGetGUIDPointer(pidl); 1973 1974 TRACE("(%p)\n",pidl); 1975 1976 if (iid) 1977 return IsEqualIID(iid, &CLSID_MyComputer); 1978 return FALSE; 1979 } 1980 1981 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl) 1982 { 1983 IID *iid = _ILGetGUIDPointer(pidl); 1984 1985 TRACE("(%p)\n", pidl); 1986 1987 if (iid) 1988 return IsEqualIID(iid, &CLSID_RecycleBin); 1989 return FALSE; 1990 } 1991 1992 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) 1993 { 1994 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1995 1996 TRACE("(%p)\n",pidl); 1997 1998 return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || 1999 (pidl && pidl->mkid.cb == 0x00) 2000 )); 2001 } 2002 2003 BOOL _ILIsDrive(LPCITEMIDLIST pidl) 2004 { 2005 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2006 2007 TRACE("(%p)\n",pidl); 2008 2009 return (pidl && lpPData && (PT_DRIVE == lpPData->type || 2010 PT_DRIVE1 == lpPData->type || 2011 PT_DRIVE2 == lpPData->type || 2012 PT_DRIVE3 == lpPData->type)); 2013 } 2014 2015 BOOL _ILIsFolder(LPCITEMIDLIST pidl) 2016 { 2017 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2018 2019 TRACE("(%p)\n",pidl); 2020 2021 return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); 2022 } 2023 2024 BOOL _ILIsValue(LPCITEMIDLIST pidl) 2025 { 2026 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2027 2028 TRACE("(%p)\n",pidl); 2029 2030 return (pidl && lpPData && PT_VALUE == lpPData->type); 2031 } 2032 2033 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) 2034 { 2035 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2036 2037 TRACE("(%p)\n",pidl); 2038 2039 return (pidl && lpPData && (lpPData->type == 0)); 2040 } 2041 2042 /************************************************************************** 2043 * _ILIsPidlSimple 2044 */ 2045 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) 2046 { 2047 BOOL ret = TRUE; 2048 2049 if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */ 2050 { 2051 WORD len = pidl->mkid.cb; 2052 LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); 2053 2054 if (pidlnext->mkid.cb) 2055 ret = FALSE; 2056 } 2057 2058 TRACE("%s\n", ret ? "Yes" : "No"); 2059 return ret; 2060 } 2061 2062 /************************************************************************** 2063 * 2064 * ### 3. section getting values from pidls ### 2065 */ 2066 2067 /************************************************************************** 2068 * _ILSimpleGetTextW 2069 * 2070 * gets the text for the first item in the pidl (eg. simple pidl) 2071 * 2072 * returns the length of the string 2073 */ 2074 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) 2075 { 2076 DWORD dwReturn; 2077 FileStructW *pFileStructW = _ILGetFileStructW(pidl); 2078 2079 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2080 2081 if (pFileStructW) { 2082 lstrcpynW(szOut, pFileStructW->wszName, uOutSize); 2083 dwReturn = lstrlenW(pFileStructW->wszName); 2084 } else { 2085 GUID const * riid; 2086 WCHAR szTemp[MAX_PATH]; 2087 LPSTR szSrc; 2088 LPWSTR szSrcW; 2089 dwReturn=0; 2090 2091 if (!pidl) 2092 return 0; 2093 2094 if (szOut) 2095 *szOut = 0; 2096 2097 if (_ILIsDesktop(pidl)) 2098 { 2099 /* desktop */ 2100 if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, _countof(szTemp))) 2101 { 2102 if (szOut) 2103 lstrcpynW(szOut, szTemp, uOutSize); 2104 2105 dwReturn = lstrlenW (szTemp); 2106 } 2107 } 2108 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2109 { 2110 /* unicode filesystem */ 2111 if (szOut) 2112 lstrcpynW(szOut, szSrcW, uOutSize); 2113 2114 dwReturn = lstrlenW(szSrcW); 2115 } 2116 else if (( szSrc = _ILGetTextPointer(pidl) )) 2117 { 2118 /* filesystem */ 2119 MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, _countof(szTemp)); 2120 2121 if (szOut) 2122 lstrcpynW(szOut, szTemp, uOutSize); 2123 2124 dwReturn = lstrlenW (szTemp); 2125 } 2126 else if (( riid = _ILGetGUIDPointer(pidl) )) 2127 { 2128 /* special folder */ 2129 if ( HCR_GetClassNameW(riid, szTemp, _countof(szTemp))) 2130 { 2131 if (szOut) 2132 lstrcpynW(szOut, szTemp, uOutSize); 2133 2134 dwReturn = lstrlenW (szTemp); 2135 } 2136 } 2137 else 2138 { 2139 ERR("-- no text\n"); 2140 } 2141 } 2142 2143 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); 2144 return dwReturn; 2145 } 2146 2147 /************************************************************************** 2148 * 2149 * ### 4. getting pointers to parts of pidls ### 2150 * 2151 ************************************************************************** 2152 * _ILGetDataPointer() 2153 */ 2154 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) 2155 { 2156 if(!_ILIsEmpty(pidl)) 2157 return (LPPIDLDATA)pidl->mkid.abID; 2158 return NULL; 2159 } 2160 2161 /************************************************************************** 2162 * _ILGetTextPointerW() 2163 * gets a pointer to the unicode long filename string stored in the pidl 2164 */ 2165 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) 2166 { 2167 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2168 2169 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2170 2171 if (!pdata) 2172 return NULL; 2173 2174 switch (pdata->type) 2175 { 2176 case PT_GUID: 2177 case PT_SHELLEXT: 2178 case PT_YAGUID: 2179 return NULL; 2180 2181 case PT_DRIVE: 2182 case PT_DRIVE1: 2183 case PT_DRIVE2: 2184 case PT_DRIVE3: 2185 /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ 2186 return NULL; 2187 2188 case PT_FOLDER: 2189 case PT_FOLDER1: 2190 case PT_VALUE: 2191 case PT_IESPECIAL1: 2192 case PT_IESPECIAL2: 2193 /*return (LPSTR)&(pdata->u.file.szNames);*/ 2194 return NULL; 2195 2196 case PT_WORKGRP: 2197 case PT_COMP: 2198 case PT_NETWORK: 2199 case PT_NETPROVIDER: 2200 case PT_SHARE: 2201 /*return (LPSTR)&(pdata->u.network.szNames);*/ 2202 return NULL; 2203 2204 case PT_VALUEW: 2205 return (LPWSTR)pdata->u.file.szNames; 2206 2207 #ifdef __REACTOS__ /* r54423 */ 2208 case PT_CPLAPPLET: 2209 return pdata->u.cpanel.szName; 2210 #endif 2211 2212 } 2213 return NULL; 2214 } 2215 2216 2217 /************************************************************************** 2218 * _ILGetTextPointer() 2219 * gets a pointer to the long filename string stored in the pidl 2220 */ 2221 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) 2222 { 2223 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2224 2225 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2226 2227 if (!pdata) 2228 return NULL; 2229 2230 switch (pdata->type) 2231 { 2232 case PT_GUID: 2233 case PT_SHELLEXT: 2234 case PT_YAGUID: 2235 return NULL; 2236 2237 case PT_DRIVE: 2238 case PT_DRIVE1: 2239 case PT_DRIVE2: 2240 case PT_DRIVE3: 2241 return pdata->u.drive.szDriveName; 2242 2243 case PT_FOLDER: 2244 case PT_FOLDER1: 2245 case PT_VALUE: 2246 case PT_IESPECIAL1: 2247 case PT_IESPECIAL2: 2248 return pdata->u.file.szNames; 2249 2250 case PT_WORKGRP: 2251 case PT_COMP: 2252 case PT_NETWORK: 2253 case PT_NETPROVIDER: 2254 case PT_SHARE: 2255 return pdata->u.network.szNames; 2256 } 2257 return NULL; 2258 } 2259 2260 /************************************************************************** 2261 * _ILGetSTextPointer() 2262 * gets a pointer to the short filename string stored in the pidl 2263 */ 2264 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) 2265 { 2266 /* TRACE(pidl,"(pidl%p)\n", pidl); */ 2267 2268 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2269 2270 if (!pdata) 2271 return NULL; 2272 2273 switch (pdata->type) 2274 { 2275 case PT_FOLDER: 2276 case PT_VALUE: 2277 case PT_IESPECIAL1: 2278 case PT_IESPECIAL2: 2279 return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; 2280 2281 case PT_WORKGRP: 2282 return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; 2283 } 2284 return NULL; 2285 } 2286 2287 /************************************************************************** 2288 * _ILGetGUIDPointer() 2289 * 2290 * returns reference to guid stored in some pidls 2291 */ 2292 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) 2293 { 2294 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2295 2296 TRACE("%p\n", pidl); 2297 2298 if (!pdata) 2299 return NULL; 2300 2301 TRACE("pdata->type 0x%04x\n", pdata->type); 2302 switch (pdata->type) 2303 { 2304 case PT_SHELLEXT: 2305 case PT_GUID: 2306 case PT_YAGUID: 2307 return &(pdata->u.guid.guid); 2308 2309 default: 2310 TRACE("Unknown pidl type 0x%04x\n", pdata->type); 2311 break; 2312 } 2313 return NULL; 2314 } 2315 2316 /****************************************************************************** 2317 * _ILGetFileStructW [Internal] 2318 * 2319 * Get pointer the a SHITEMID's FileStructW field if present 2320 * 2321 * PARAMS 2322 * pidl [I] The SHITEMID 2323 * 2324 * RETURNS 2325 * Success: Pointer to pidl's FileStructW field. 2326 * Failure: NULL 2327 */ 2328 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { 2329 FileStructW *pFileStructW; 2330 WORD cbOffset; 2331 2332 if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) 2333 return NULL; 2334 2335 cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); 2336 pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); 2337 2338 /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP 2339 * style with a FileStructW member. If we switch all our shellfolder-implementations to 2340 * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ 2341 if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */ 2342 /* FileStructW is positioned after FileStruct */ 2343 cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || 2344 /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ 2345 cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || 2346 pidl->mkid.cb != cbOffset + pFileStructW->cbLen) 2347 { 2348 WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); 2349 return NULL; 2350 } 2351 2352 return pFileStructW; 2353 } 2354 2355 /************************************************************************* 2356 * _ILGetFileDateTime 2357 * 2358 * Given the ItemIdList, get the FileTime 2359 * 2360 * PARAMS 2361 * pidl [I] The ItemIDList 2362 * pFt [I] the resulted FILETIME of the file 2363 * 2364 * RETURNS 2365 * True if Successful 2366 * 2367 * NOTES 2368 * 2369 */ 2370 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) 2371 { 2372 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2373 2374 if (!pdata) 2375 return FALSE; 2376 2377 switch (pdata->type) 2378 { 2379 case PT_FOLDER: 2380 case PT_VALUE: 2381 DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); 2382 break; 2383 default: 2384 return FALSE; 2385 } 2386 return TRUE; 2387 } 2388 2389 BOOL _ILGetFileDate(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) 2390 { 2391 FILETIME ft,lft; 2392 SYSTEMTIME time; 2393 BOOL ret; 2394 2395 if (_ILGetFileDateTime( pidl, &ft )) 2396 { 2397 FileTimeToLocalFileTime(&ft, &lft); 2398 FileTimeToSystemTime (&lft, &time); 2399 2400 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, pOut, uOutSize); 2401 if (ret) 2402 { 2403 /* Append space + time without seconds */ 2404 pOut[ret - 1] = L' '; 2405 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); 2406 } 2407 } 2408 else 2409 { 2410 pOut[0] = UNICODE_NULL; 2411 ret = FALSE; 2412 } 2413 return ret; 2414 } 2415 2416 /************************************************************************* 2417 * _ILGetFileSize 2418 * 2419 * Given the ItemIdList, get the FileSize 2420 * 2421 * PARAMS 2422 * pidl [I] The ItemIDList 2423 * pOut [I] The buffer to save the result 2424 * uOutsize [I] The size of the buffer 2425 * 2426 * RETURNS 2427 * The FileSize 2428 * 2429 * NOTES 2430 * pOut can be null when no string is needed 2431 * 2432 */ 2433 DWORD _ILGetFileSize(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) 2434 { 2435 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2436 DWORD dwSize; 2437 2438 if (!pdata) 2439 return 0; 2440 2441 switch (pdata->type) 2442 { 2443 case PT_VALUE: 2444 dwSize = pdata->u.file.dwFileSize; 2445 if (pOut) 2446 StrFormatKBSizeW(dwSize, pOut, uOutSize); 2447 return dwSize; 2448 } 2449 if (pOut) 2450 *pOut = UNICODE_NULL; 2451 return 0; 2452 } 2453 2454 BOOL _ILGetExtension(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) 2455 { 2456 WCHAR szTemp[MAX_PATH]; 2457 LPCWSTR pPoint; 2458 LPCITEMIDLIST pidlTemp = pidl; 2459 2460 TRACE("pidl=%p\n",pidl); 2461 2462 if (!pidl) 2463 return FALSE; 2464 2465 pidlTemp = ILFindLastID(pidl); 2466 2467 if (!_ILIsValue(pidlTemp)) 2468 return FALSE; 2469 if (!_ILSimpleGetTextW(pidlTemp, szTemp, _countof(szTemp))) 2470 return FALSE; 2471 2472 pPoint = PathFindExtensionW(szTemp); 2473 2474 if (!*pPoint) 2475 return FALSE; 2476 2477 pPoint++; 2478 lstrcpynW(pOut, pPoint, uOutSize); 2479 TRACE("%s\n", debugstr_w(pOut)); 2480 2481 return TRUE; 2482 } 2483 2484 /************************************************************************* 2485 * _ILGetFileType 2486 * 2487 * Given the ItemIdList, get the file type description 2488 * 2489 * PARAMS 2490 * pidl [I] The ItemIDList (simple) 2491 * pOut [I] The buffer to save the result 2492 * uOutsize [I] The size of the buffer 2493 * 2494 * RETURNS 2495 * nothing 2496 * 2497 * NOTES 2498 * This function copies as much as possible into the buffer. 2499 */ 2500 void _ILGetFileType(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) 2501 { 2502 WCHAR sType[64], sTemp[64]; 2503 2504 if(_ILIsValue(pidl)) 2505 { 2506 if(uOutSize > 0) 2507 pOut[0] = 0; 2508 if (_ILGetExtension(pidl, sType, _countof(sType))) 2509 { 2510 if (HCR_MapTypeToValueW(sType, sTemp, _countof(sTemp), TRUE)) 2511 { 2512 /* retrieve description */ 2513 if (HCR_MapTypeToValueW(sTemp, pOut, uOutSize, FALSE)) 2514 return; 2515 } 2516 2517 /* display Ext-file as description */ 2518 CharUpperW(sType); 2519 /* load localized file string */ 2520 sTemp[0] = UNICODE_NULL; 2521 if (LoadStringW(shell32_hInstance, IDS_ANY_FILE, sTemp, _countof(sTemp))) 2522 { 2523 sTemp[_countof(sTemp) - 1] = UNICODE_NULL; 2524 StringCchPrintfW(pOut, uOutSize, sTemp, sType); 2525 } 2526 } 2527 } 2528 else 2529 { 2530 pOut[0] = UNICODE_NULL; 2531 LoadStringW(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize); 2532 /* make sure its null terminated */ 2533 pOut[uOutSize - 1] = UNICODE_NULL; 2534 } 2535 } 2536 2537 /************************************************************************* 2538 * _ILGetFileAttributes 2539 * 2540 * Given the ItemIdList, get the Attrib string format 2541 * 2542 * PARAMS 2543 * pidl [I] The ItemIDList 2544 * pOut [I] The buffer to save the result 2545 * uOutsize [I] The size of the Buffer 2546 * 2547 * RETURNS 2548 * Attributes 2549 * 2550 * FIXME 2551 * return value 0 in case of error is a valid return value 2552 * 2553 */ 2554 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) 2555 { 2556 LPPIDLDATA pData = _ILGetDataPointer(pidl); 2557 WORD wAttrib = 0; 2558 int i; 2559 2560 if (!pData) 2561 return 0; 2562 2563 switch(pData->type) 2564 { 2565 case PT_FOLDER: 2566 case PT_VALUE: 2567 wAttrib = pData->u.file.uFileAttribs; 2568 break; 2569 } 2570 2571 if(uOutSize >= 6) 2572 { 2573 i=0; 2574 if(wAttrib & FILE_ATTRIBUTE_READONLY) 2575 pOut[i++] = L'R'; 2576 if(wAttrib & FILE_ATTRIBUTE_HIDDEN) 2577 pOut[i++] = L'H'; 2578 if(wAttrib & FILE_ATTRIBUTE_SYSTEM) 2579 pOut[i++] = L'S'; 2580 if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) 2581 pOut[i++] = L'A'; 2582 if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) 2583 pOut[i++] = L'C'; 2584 pOut[i] = UNICODE_NULL; 2585 } 2586 return wAttrib; 2587 } 2588 2589 /************************************************************************* 2590 * ILFreeaPidl 2591 * 2592 * frees an aPidl struct 2593 */ 2594 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) 2595 { 2596 UINT i; 2597 2598 if (apidl) 2599 { 2600 for (i = 0; i < cidl; i++) 2601 SHFree(apidl[i]); 2602 SHFree(apidl); 2603 } 2604 } 2605 2606 /************************************************************************* 2607 * ILCopyaPidl 2608 * 2609 * copies an aPidl struct 2610 */ 2611 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl) 2612 { 2613 UINT i; 2614 PITEMID_CHILD *apidldest; 2615 2616 if (!apidlsrc) 2617 return NULL; 2618 2619 apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD)); 2620 2621 for (i = 0; i < cidl; i++) 2622 apidldest[i] = ILClone(apidlsrc[i]); 2623 2624 return apidldest; 2625 } 2626 2627 /************************************************************************* 2628 * _ILCopyCidaToaPidl 2629 * 2630 * creates aPidl from CIDA 2631 */ 2632 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) 2633 { 2634 UINT i; 2635 LPITEMIDLIST *dst; 2636 2637 dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); 2638 if (!dst) 2639 return NULL; 2640 2641 if (pidl) 2642 *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); 2643 2644 for (i = 0; i < cida->cidl; i++) 2645 dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); 2646 2647 return dst; 2648 } 2649