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 /************************************************************************* 751 * SHGetRealIDL [SHELL32.98] 752 * 753 * NOTES 754 */ 755 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal) 756 { 757 IDataObject* pDataObj; 758 HRESULT hr; 759 760 hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple, 761 &IID_IDataObject, 0, (LPVOID*)&pDataObj); 762 if (SUCCEEDED(hr)) 763 { 764 STGMEDIUM medium; 765 FORMATETC fmt; 766 767 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); 768 fmt.ptd = NULL; 769 fmt.dwAspect = DVASPECT_CONTENT; 770 fmt.lindex = -1; 771 fmt.tymed = TYMED_HGLOBAL; 772 773 hr = IDataObject_GetData(pDataObj, &fmt, &medium); 774 775 IDataObject_Release(pDataObj); 776 777 if (SUCCEEDED(hr)) 778 { 779 /*assert(pida->cidl==1);*/ 780 LPIDA pida = GlobalLock(medium.u.hGlobal); 781 782 LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); 783 LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); 784 785 *pidlReal = ILCombine(pidl_folder, pidl_child); 786 787 if (!*pidlReal) 788 hr = E_OUTOFMEMORY; 789 790 GlobalUnlock(medium.u.hGlobal); 791 GlobalFree(medium.u.hGlobal); 792 } 793 } 794 795 return hr; 796 } 797 798 /************************************************************************* 799 * SHLogILFromFSIL [SHELL32.95] 800 * 801 * NOTES 802 * pild = CSIDL_DESKTOP ret = 0 803 * pild = CSIDL_DRIVES ret = 0 804 */ 805 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl) 806 { 807 FIXME("(pidl=%p)\n",pidl); 808 809 pdump(pidl); 810 811 return 0; 812 } 813 814 /************************************************************************* 815 * ILGetSize [SHELL32.152] 816 * 817 * Gets the byte size of an ItemIDList including zero terminator 818 * 819 * PARAMS 820 * pidl [I] ItemIDList 821 * 822 * RETURNS 823 * size of pidl in bytes 824 * 825 * NOTES 826 * exported by ordinal 827 */ 828 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl) 829 { 830 LPCSHITEMID si; 831 UINT len=0; 832 833 if (pidl) 834 { 835 si = &(pidl->mkid); 836 837 while (si->cb) 838 { 839 len += si->cb; 840 si = (LPCSHITEMID)(((const BYTE*)si)+si->cb); 841 } 842 len += 2; 843 } 844 TRACE("pidl=%p size=%u\n",pidl, len); 845 return len; 846 } 847 848 /************************************************************************* 849 * ILGetNext [SHELL32.153] 850 * 851 * Gets the next ItemID of an ItemIDList 852 * 853 * PARAMS 854 * pidl [I] ItemIDList 855 * 856 * RETURNS 857 * null -> null 858 * desktop -> null 859 * simple pidl -> pointer to 0x0000 element 860 * 861 * NOTES 862 * exported by ordinal. 863 */ 864 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl) 865 { 866 WORD len; 867 868 TRACE("%p\n", pidl); 869 870 if (pidl) 871 { 872 len = pidl->mkid.cb; 873 if (len) 874 { 875 pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len); 876 TRACE("-- %p\n", pidl); 877 return (LPITEMIDLIST)pidl; 878 } 879 } 880 return NULL; 881 } 882 883 /************************************************************************* 884 * ILAppendID [SHELL32.154] 885 * 886 * Adds the single ItemID item to the ItemIDList indicated by pidl. 887 * If bEnd is FALSE, inserts the item in the front of the list, 888 * otherwise it adds the item to the end. (???) 889 * 890 * PARAMS 891 * pidl [I] ItemIDList to extend 892 * item [I] ItemID to prepend/append 893 * bEnd [I] Indicates if the item should be appended 894 * 895 * NOTES 896 * Destroys the passed in idlist! (???) 897 */ 898 LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd) 899 { 900 LPITEMIDLIST idlRet; 901 LPCITEMIDLIST itemid = (LPCITEMIDLIST)item; 902 903 WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd); 904 905 pdump (pidl); 906 pdump (itemid); 907 908 if (_ILIsDesktop(pidl)) 909 { 910 idlRet = ILClone(itemid); 911 SHFree (pidl); 912 return idlRet; 913 } 914 915 if (bEnd) 916 idlRet = ILCombine(pidl, itemid); 917 else 918 idlRet = ILCombine(itemid, pidl); 919 920 SHFree(pidl); 921 return idlRet; 922 } 923 924 /************************************************************************* 925 * ILFree [SHELL32.155] 926 * 927 * Frees memory (if not NULL) allocated by SHMalloc allocator 928 * 929 * PARAMS 930 * pidl [I] 931 * 932 * RETURNS 933 * Nothing 934 * 935 * NOTES 936 * exported by ordinal 937 */ 938 void WINAPI ILFree(LPITEMIDLIST pidl) 939 { 940 TRACE("(pidl=%p)\n",pidl); 941 SHFree(pidl); 942 } 943 944 /************************************************************************* 945 * ILGlobalFree [SHELL32.156] 946 * 947 * Frees memory (if not NULL) allocated by Alloc allocator 948 * 949 * PARAMS 950 * pidl [I] 951 * 952 * RETURNS 953 * Nothing 954 * 955 * NOTES 956 * exported by ordinal. 957 */ 958 void WINAPI ILGlobalFree( LPITEMIDLIST pidl) 959 { 960 TRACE("%p\n", pidl); 961 962 Free(pidl); 963 } 964 965 /************************************************************************* 966 * ILCreateFromPathA [SHELL32.189] 967 * 968 * Creates a complex ItemIDList from a path and returns it. 969 * 970 * PARAMS 971 * path [I] 972 * 973 * RETURNS 974 * the newly created complex ItemIDList or NULL if failed 975 * 976 * NOTES 977 * exported by ordinal. 978 */ 979 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) 980 { 981 LPITEMIDLIST pidlnew = NULL; 982 983 TRACE_(shell)("%s\n", debugstr_a(path)); 984 985 if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL))) 986 return pidlnew; 987 return NULL; 988 } 989 990 /************************************************************************* 991 * ILCreateFromPathW [SHELL32.190] 992 * 993 * See ILCreateFromPathA. 994 */ 995 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) 996 { 997 LPITEMIDLIST pidlnew = NULL; 998 999 TRACE_(shell)("%s\n", debugstr_w(path)); 1000 1001 if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL))) 1002 return pidlnew; 1003 return NULL; 1004 } 1005 1006 /************************************************************************* 1007 * ILCreateFromPath [SHELL32.157] 1008 */ 1009 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) 1010 { 1011 if ( SHELL_OsIsUnicode()) 1012 return ILCreateFromPathW (path); 1013 return ILCreateFromPathA (path); 1014 } 1015 1016 /************************************************************************* 1017 * _ILParsePathW [internal] 1018 * 1019 * Creates an ItemIDList from a path and returns it. 1020 * 1021 * PARAMS 1022 * path [I] path to parse and convert into an ItemIDList 1023 * lpFindFile [I] pointer to buffer to initialize the FileSystem 1024 * Bind Data object with 1025 * bBindCtx [I] indicates to create a BindContext and assign a 1026 * FileSystem Bind Data object 1027 * ppidl [O] the newly create ItemIDList 1028 * prgfInOut [I/O] requested attributes on input and actual 1029 * attributes on return 1030 * 1031 * RETURNS 1032 * NO_ERROR on success or an OLE error code 1033 * 1034 * NOTES 1035 * If either lpFindFile is non-NULL or bBindCtx is TRUE, this function 1036 * creates a BindContext object and assigns a FileSystem Bind Data object 1037 * to it, passing the BindContext to IShellFolder_ParseDisplayName. Each 1038 * IShellFolder uses that FileSystem Bind Data object of the BindContext 1039 * to pass data about the current path element to the next object. This 1040 * is used to avoid having to verify the current path element on disk, so 1041 * that creating an ItemIDList from a nonexistent path still can work. 1042 */ 1043 static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile, 1044 BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut) 1045 { 1046 LPSHELLFOLDER pSF = NULL; 1047 LPBC pBC = NULL; 1048 HRESULT ret; 1049 1050 TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx, 1051 ppidl, ppidl ? *ppidl : NULL, 1052 prgfInOut, prgfInOut ? *prgfInOut : 0); 1053 1054 ret = SHGetDesktopFolder(&pSF); 1055 if (FAILED(ret)) 1056 return ret; 1057 1058 if (lpFindFile || bBindCtx) 1059 ret = IFileSystemBindData_Constructor(lpFindFile, &pBC); 1060 1061 if (SUCCEEDED(ret)) 1062 { 1063 ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut); 1064 } 1065 1066 if (pBC) 1067 { 1068 IBindCtx_Release(pBC); 1069 pBC = NULL; 1070 } 1071 1072 IShellFolder_Release(pSF); 1073 1074 if (FAILED(ret) && ppidl) 1075 *ppidl = NULL; 1076 1077 TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0); 1078 1079 return ret; 1080 } 1081 1082 /************************************************************************* 1083 * SHSimpleIDListFromPath [SHELL32.162] 1084 * 1085 * Creates a simple ItemIDList from a path and returns it. This function 1086 * does not fail on nonexistent paths. 1087 * 1088 * PARAMS 1089 * path [I] path to parse and convert into an ItemIDList 1090 * 1091 * RETURNS 1092 * the newly created simple ItemIDList 1093 * 1094 * NOTES 1095 * Simple in the name does not mean a relative ItemIDList but rather a 1096 * fully qualified list, where only the file name is filled in and the 1097 * directory flag for those ItemID elements this is known about, eg. 1098 * it is not the last element in the ItemIDList or the actual directory 1099 * exists on disk. 1100 * exported by ordinal. 1101 */ 1102 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) 1103 { 1104 LPITEMIDLIST pidl = NULL; 1105 LPWSTR wPath = NULL; 1106 int len; 1107 1108 TRACE("%s\n", debugstr_a(lpszPath)); 1109 1110 if (lpszPath) 1111 { 1112 len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0); 1113 wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1114 MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); 1115 } 1116 #ifdef __REACTOS__ 1117 // FIXME: Needs folder attribute 1118 if (PathFileExistsW(wPath)) 1119 { 1120 pidl = ILCreateFromPathW(wPath); 1121 HeapFree(GetProcessHeap(), 0, wPath); 1122 return pidl; 1123 } 1124 #endif 1125 1126 _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); 1127 1128 HeapFree(GetProcessHeap(), 0, wPath); 1129 TRACE("%s %p\n", debugstr_a(lpszPath), pidl); 1130 return pidl; 1131 } 1132 1133 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) 1134 { 1135 LPITEMIDLIST pidl = NULL; 1136 1137 TRACE("%s\n", debugstr_w(lpszPath)); 1138 #ifdef __REACTOS__ 1139 // FIXME: Needs folder attribute 1140 if (PathFileExistsW(lpszPath)) 1141 return ILCreateFromPathW(lpszPath); 1142 #endif 1143 1144 _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); 1145 TRACE("%s %p\n", debugstr_w(lpszPath), pidl); 1146 return pidl; 1147 } 1148 1149 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) 1150 { 1151 if ( SHELL_OsIsUnicode()) 1152 return SHSimpleIDListFromPathW (lpszPath); 1153 return SHSimpleIDListFromPathA (lpszPath); 1154 } 1155 1156 /************************************************************************* 1157 * SHGetDataFromIDListA [SHELL32.247] 1158 * 1159 * NOTES 1160 * the pidl can be a simple one. since we can't get the path out of the pidl 1161 * we have to take all data from the pidl 1162 */ 1163 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1164 int nFormat, LPVOID dest, int len) 1165 { 1166 LPSTR filename, shortname; 1167 WIN32_FIND_DATAA * pfd; 1168 1169 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1170 1171 pdump(pidl); 1172 if (!psf || !dest) 1173 return E_INVALIDARG; 1174 1175 switch (nFormat) 1176 { 1177 case SHGDFIL_FINDDATA: 1178 pfd = dest; 1179 1180 if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) 1181 return E_INVALIDARG; 1182 1183 if (len < sizeof(WIN32_FIND_DATAA)) 1184 return E_INVALIDARG; 1185 1186 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); 1187 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1188 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1189 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1190 1191 filename = _ILGetTextPointer(pidl); 1192 shortname = _ILGetSTextPointer(pidl); 1193 1194 if (filename) 1195 lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); 1196 else 1197 pfd->cFileName[0] = '\0'; 1198 1199 if (shortname) 1200 lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); 1201 else 1202 pfd->cAlternateFileName[0] = '\0'; 1203 return S_OK; 1204 1205 case SHGDFIL_NETRESOURCE: 1206 case SHGDFIL_DESCRIPTIONID: 1207 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1208 break; 1209 1210 default: 1211 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1212 } 1213 1214 return E_INVALIDARG; 1215 } 1216 1217 /************************************************************************* 1218 * SHGetDataFromIDListW [SHELL32.248] 1219 * 1220 */ 1221 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1222 int nFormat, LPVOID dest, int len) 1223 { 1224 LPSTR filename, shortname; 1225 WIN32_FIND_DATAW * pfd = dest; 1226 1227 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1228 1229 pdump(pidl); 1230 1231 if (!psf || !dest) 1232 return E_INVALIDARG; 1233 1234 switch (nFormat) 1235 { 1236 case SHGDFIL_FINDDATA: 1237 pfd = dest; 1238 1239 if (_ILIsDrive(pidl)) 1240 return E_INVALIDARG; 1241 1242 if (len < sizeof(WIN32_FIND_DATAW)) 1243 return E_INVALIDARG; 1244 1245 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW)); 1246 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1247 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1248 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1249 1250 filename = _ILGetTextPointer(pidl); 1251 shortname = _ILGetSTextPointer(pidl); 1252 1253 if (!filename) 1254 pfd->cFileName[0] = '\0'; 1255 else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) 1256 pfd->cFileName[MAX_PATH-1] = 0; 1257 1258 if (!shortname) 1259 pfd->cAlternateFileName[0] = '\0'; 1260 else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) 1261 pfd->cAlternateFileName[13] = 0; 1262 return S_OK; 1263 1264 case SHGDFIL_NETRESOURCE: 1265 case SHGDFIL_DESCRIPTIONID: 1266 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1267 break; 1268 1269 default: 1270 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1271 } 1272 1273 return E_INVALIDARG; 1274 } 1275 1276 /************************************************************************* 1277 * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220] 1278 * 1279 * PARAMETERS 1280 * pidl, [IN] pidl 1281 * pszPath [OUT] path 1282 * 1283 * RETURNS 1284 * path from a passed PIDL. 1285 * 1286 * NOTES 1287 * NULL returns FALSE 1288 * desktop pidl gives path to desktop directory back 1289 * special pidls returning FALSE 1290 */ 1291 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) 1292 { 1293 WCHAR wszPath[MAX_PATH]; 1294 BOOL bSuccess; 1295 1296 bSuccess = SHGetPathFromIDListW(pidl, wszPath); 1297 WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); 1298 1299 return bSuccess; 1300 } 1301 1302 /************************************************************************* 1303 * SHGetPathFromIDListW [SHELL32.@] 1304 * 1305 * See SHGetPathFromIDListA. 1306 */ 1307 HRESULT WINAPI 1308 SHGetPathCchFromIDListW( 1309 _In_ LPCITEMIDLIST pidl, 1310 _Out_writes_(cchPathMax) LPWSTR pszPath, 1311 _In_ SIZE_T cchPathMax) 1312 { 1313 HRESULT hr; 1314 LPCITEMIDLIST pidlLast; 1315 LPSHELLFOLDER psfFolder; 1316 DWORD dwAttributes; 1317 STRRET strret; 1318 1319 TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); 1320 pdump(pidl); 1321 1322 *pszPath = UNICODE_NULL; 1323 if (!pidl) 1324 return E_FAIL; 1325 1326 hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); 1327 if (FAILED(hr)) 1328 { 1329 ERR("SHBindToParent failed: %x\n", hr); 1330 return hr; 1331 } 1332 1333 dwAttributes = SFGAO_FILESYSTEM; 1334 hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); 1335 if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) 1336 { 1337 WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr); 1338 IShellFolder_Release(psfFolder); 1339 return E_FAIL; 1340 } 1341 1342 hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); 1343 IShellFolder_Release(psfFolder); 1344 if (FAILED(hr)) 1345 return hr; 1346 1347 hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax); 1348 1349 TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); 1350 return hr; 1351 } 1352 1353 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) 1354 { 1355 return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH)); 1356 } 1357 1358 /************************************************************************* 1359 * SHBindToParent [shell version 5.0] 1360 */ 1361 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) 1362 { 1363 IShellFolder * psfDesktop; 1364 HRESULT hr=E_FAIL; 1365 1366 TRACE_(shell)("pidl=%p\n", pidl); 1367 pdump(pidl); 1368 1369 if (!pidl || !ppv) 1370 return E_INVALIDARG; 1371 1372 *ppv = NULL; 1373 if (ppidlLast) 1374 *ppidlLast = NULL; 1375 1376 hr = SHGetDesktopFolder(&psfDesktop); 1377 if (FAILED(hr)) 1378 return hr; 1379 1380 if (_ILIsPidlSimple(pidl)) 1381 { 1382 /* we are on desktop level */ 1383 hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv); 1384 } 1385 else 1386 { 1387 LPITEMIDLIST pidlParent = ILClone(pidl); 1388 ILRemoveLastID(pidlParent); 1389 hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv); 1390 SHFree (pidlParent); 1391 } 1392 1393 IShellFolder_Release(psfDesktop); 1394 1395 if (SUCCEEDED(hr) && ppidlLast) 1396 *ppidlLast = ILFindLastID(pidl); 1397 1398 TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); 1399 return hr; 1400 } 1401 1402 /************************************************************************* 1403 * SHParseDisplayName [shell version 6.0] 1404 */ 1405 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, 1406 LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) 1407 { 1408 HRESULT hr; 1409 LPWSTR pszNameDup; 1410 IShellFolder *psfDesktop; 1411 IBindCtx *pBindCtx = NULL; 1412 1413 TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut); 1414 1415 *ppidl = NULL; 1416 1417 if (psfgaoOut) 1418 *psfgaoOut = 0; 1419 1420 pszNameDup = StrDupW(pszName); 1421 if (!pszNameDup) 1422 return E_OUTOFMEMORY; 1423 1424 psfDesktop = NULL; 1425 hr = SHGetDesktopFolder(&psfDesktop); 1426 if (FAILED(hr)) 1427 { 1428 LocalFree(pszNameDup); 1429 return hr; 1430 } 1431 1432 if (!pbc) 1433 { 1434 hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx); 1435 pbc = pBindCtx; 1436 } 1437 1438 if (SUCCEEDED(hr)) 1439 { 1440 ULONG sfgao = sfgaoIn, cchEaten; 1441 HWND hwndUI = BindCtx_GetUIWindow(pbc); 1442 hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop, 1443 hwndUI, 1444 pbc, 1445 pszNameDup, 1446 &cchEaten, 1447 ppidl, 1448 (psfgaoOut ? &sfgao : NULL)); 1449 if (SUCCEEDED(hr) && psfgaoOut) 1450 *psfgaoOut = (sfgao & sfgaoIn); 1451 } 1452 1453 LocalFree(pszNameDup); 1454 1455 if (psfDesktop) 1456 psfDesktop->lpVtbl->Release(psfDesktop); 1457 1458 if (pBindCtx) 1459 pBindCtx->lpVtbl->Release(pBindCtx); 1460 1461 return hr; 1462 } 1463 1464 /************************************************************************* 1465 * SHGetNameFromIDList [SHELL32.@] 1466 */ 1467 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName) 1468 { 1469 IShellFolder *psfparent; 1470 LPCITEMIDLIST child_pidl; 1471 STRRET disp_name; 1472 HRESULT ret; 1473 1474 TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName); 1475 1476 *ppszName = NULL; 1477 ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl); 1478 if(SUCCEEDED(ret)) 1479 { 1480 switch(sigdnName) 1481 { 1482 /* sigdnName & 0xffff */ 1483 case SIGDN_NORMALDISPLAY: /* SHGDN_NORMAL */ 1484 case SIGDN_PARENTRELATIVEPARSING: /* SHGDN_INFOLDER | SHGDN_FORPARSING */ 1485 case SIGDN_PARENTRELATIVEEDITING: /* SHGDN_INFOLDER | SHGDN_FOREDITING */ 1486 case SIGDN_DESKTOPABSOLUTEPARSING: /* SHGDN_FORPARSING */ 1487 case SIGDN_DESKTOPABSOLUTEEDITING: /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/ 1488 case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */ 1489 case SIGDN_PARENTRELATIVE: /* SIGDN_INFOLDER */ 1490 1491 disp_name.uType = STRRET_WSTR; 1492 ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl, 1493 sigdnName & 0xffff, 1494 &disp_name); 1495 if(SUCCEEDED(ret)) 1496 ret = StrRetToStrW(&disp_name, pidl, ppszName); 1497 1498 break; 1499 1500 case SIGDN_FILESYSPATH: 1501 *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH); 1502 if(SHGetPathFromIDListW(pidl, *ppszName)) 1503 { 1504 TRACE("Got string %s\n", debugstr_w(*ppszName)); 1505 ret = S_OK; 1506 } 1507 else 1508 { 1509 CoTaskMemFree(*ppszName); 1510 ret = E_INVALIDARG; 1511 } 1512 break; 1513 1514 case SIGDN_URL: 1515 default: 1516 FIXME("Unsupported SIGDN %x\n", sigdnName); 1517 ret = E_FAIL; 1518 } 1519 1520 IShellFolder_Release(psfparent); 1521 } 1522 return ret; 1523 } 1524 1525 #ifndef __REACTOS__ 1526 1527 /************************************************************************* 1528 * SHGetIDListFromObject [SHELL32.@] 1529 */ 1530 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) 1531 { 1532 IPersistIDList *ppersidl; 1533 IPersistFolder2 *ppf2; 1534 IDataObject *pdo; 1535 IFolderView *pfv; 1536 HRESULT ret; 1537 1538 if(!punk) 1539 return E_NOINTERFACE; 1540 1541 *ppidl = NULL; 1542 1543 /* Try IPersistIDList */ 1544 ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl); 1545 if(SUCCEEDED(ret)) 1546 { 1547 TRACE("IPersistIDList (%p)\n", ppersidl); 1548 ret = IPersistIDList_GetIDList(ppersidl, ppidl); 1549 IPersistIDList_Release(ppersidl); 1550 if(SUCCEEDED(ret)) 1551 return ret; 1552 } 1553 1554 /* Try IPersistFolder2 */ 1555 ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2); 1556 if(SUCCEEDED(ret)) 1557 { 1558 TRACE("IPersistFolder2 (%p)\n", ppf2); 1559 ret = IPersistFolder2_GetCurFolder(ppf2, ppidl); 1560 IPersistFolder2_Release(ppf2); 1561 if(SUCCEEDED(ret)) 1562 return ret; 1563 } 1564 1565 /* Try IDataObject */ 1566 ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo); 1567 if(SUCCEEDED(ret)) 1568 { 1569 IShellItem *psi; 1570 TRACE("IDataObject (%p)\n", pdo); 1571 ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, 1572 &IID_IShellItem, (void**)&psi); 1573 if(SUCCEEDED(ret)) 1574 { 1575 ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); 1576 IShellItem_Release(psi); 1577 } 1578 IDataObject_Release(pdo); 1579 1580 if(SUCCEEDED(ret)) 1581 return ret; 1582 } 1583 1584 /* Try IFolderView */ 1585 ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv); 1586 if(SUCCEEDED(ret)) 1587 { 1588 IShellFolder *psf; 1589 TRACE("IFolderView (%p)\n", pfv); 1590 ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf); 1591 if(SUCCEEDED(ret)) 1592 { 1593 /* We might be able to get IPersistFolder2 from a shellfolder. */ 1594 ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); 1595 } 1596 IFolderView_Release(pfv); 1597 return ret; 1598 } 1599 1600 return ret; 1601 } 1602 1603 #endif /* !__REACTOS__ */ 1604 1605 /************************************************************************** 1606 * 1607 * internal functions 1608 * 1609 * ### 1. section creating pidls ### 1610 * 1611 ************************************************************************* 1612 */ 1613 1614 /* Basic PIDL constructor. Allocates size + 5 bytes, where: 1615 * - two bytes are SHITEMID.cb 1616 * - one byte is PIDLDATA.type 1617 * - two bytes are the NULL PIDL terminator 1618 * Sets type of the returned PIDL to type. 1619 */ 1620 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) 1621 { 1622 LPITEMIDLIST pidlOut = NULL; 1623 1624 pidlOut = SHAlloc(size + 5); 1625 if(pidlOut) 1626 { 1627 LPPIDLDATA pData; 1628 LPITEMIDLIST pidlNext; 1629 1630 ZeroMemory(pidlOut, size + 5); 1631 pidlOut->mkid.cb = size + 3; 1632 1633 pData = _ILGetDataPointer(pidlOut); 1634 if (pData) 1635 pData->type = type; 1636 1637 pidlNext = ILGetNext(pidlOut); 1638 if (pidlNext) 1639 pidlNext->mkid.cb = 0x00; 1640 TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); 1641 } 1642 1643 return pidlOut; 1644 } 1645 1646 LPITEMIDLIST _ILCreateDesktop(void) 1647 { 1648 LPITEMIDLIST ret; 1649 1650 TRACE("()\n"); 1651 ret = SHAlloc(2); 1652 if (ret) 1653 ret->mkid.cb = 0; 1654 return ret; 1655 } 1656 1657 LPITEMIDLIST _ILCreateMyComputer(void) 1658 { 1659 TRACE("()\n"); 1660 return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); 1661 } 1662 1663 LPITEMIDLIST _ILCreateMyDocuments(void) 1664 { 1665 TRACE("()\n"); 1666 return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); 1667 } 1668 1669 LPITEMIDLIST _ILCreateIExplore(void) 1670 { 1671 TRACE("()\n"); 1672 return _ILCreateGuid(PT_GUID, &CLSID_Internet); 1673 } 1674 1675 LPITEMIDLIST _ILCreateControlPanel(void) 1676 { 1677 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1678 1679 TRACE("()\n"); 1680 if (parent) 1681 { 1682 LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); 1683 1684 if (cpl) 1685 { 1686 ret = ILCombine(parent, cpl); 1687 SHFree(cpl); 1688 } 1689 SHFree(parent); 1690 } 1691 return ret; 1692 } 1693 1694 LPITEMIDLIST _ILCreatePrinters(void) 1695 { 1696 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1697 1698 TRACE("()\n"); 1699 if (parent) 1700 { 1701 LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); 1702 1703 if (printers) 1704 { 1705 ret = ILCombine(parent, printers); 1706 SHFree(printers); 1707 } 1708 SHFree(parent); 1709 } 1710 return ret; 1711 } 1712 1713 LPITEMIDLIST _ILCreateNetwork(void) 1714 { 1715 TRACE("()\n"); 1716 return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); 1717 } 1718 1719 LPITEMIDLIST _ILCreateBitBucket(void) 1720 { 1721 TRACE("()\n"); 1722 return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); 1723 } 1724 1725 LPITEMIDLIST _ILCreateAdminTools(void) 1726 { 1727 TRACE("()\n"); 1728 return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME 1729 } 1730 1731 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) 1732 { 1733 LPITEMIDLIST pidlOut; 1734 1735 if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) 1736 { 1737 pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); 1738 if (pidlOut) 1739 { 1740 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1741 1742 pData->u.guid.guid = *guid; 1743 TRACE("-- create GUID-pidl %s\n", 1744 debugstr_guid(&(pData->u.guid.guid))); 1745 } 1746 } 1747 else 1748 { 1749 WARN("%d: invalid type for GUID\n", type); 1750 pidlOut = NULL; 1751 } 1752 return pidlOut; 1753 } 1754 1755 #ifndef __REACTOS__ 1756 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) 1757 { 1758 IID iid; 1759 1760 if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) 1761 { 1762 ERR("%s is not a GUID\n", szGUID); 1763 return NULL; 1764 } 1765 return _ILCreateGuid(PT_GUID, &iid); 1766 } 1767 #endif 1768 1769 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) 1770 { 1771 IID iid; 1772 1773 #ifndef __REACTOS__ 1774 if (FAILED(SHCLSIDFromStringW(szGUID, &iid))) 1775 #else 1776 if (!GUIDFromStringW(szGUID, &iid)) 1777 #endif 1778 { 1779 ERR("%s is not a GUID\n", debugstr_w(szGUID)); 1780 return NULL; 1781 } 1782 return _ILCreateGuid(PT_GUID, &iid); 1783 } 1784 1785 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) 1786 { 1787 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ 1788 DWORD len, len1, wlen, alen; 1789 LPITEMIDLIST pidl; 1790 PIDLTYPE type; 1791 1792 if (!wfd) 1793 return NULL; 1794 1795 TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); 1796 1797 /* prepare buffer with both names */ 1798 len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); 1799 len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); 1800 alen = len + len1; 1801 1802 type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; 1803 1804 wlen = lstrlenW(wfd->cFileName) + 1; 1805 pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + 1806 FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); 1807 if (pidl) 1808 { 1809 LPPIDLDATA pData = _ILGetDataPointer(pidl); 1810 FileStruct *fs = &pData->u.file; 1811 FileStructW *fsw; 1812 WORD *pOffsetW; 1813 1814 FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); 1815 fs->dwFileSize = wfd->nFileSizeLow; 1816 fs->uFileAttribs = wfd->dwFileAttributes; 1817 memcpy(fs->szNames, buff, alen); 1818 1819 fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); 1820 fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); 1821 FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); 1822 FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); 1823 memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); 1824 1825 pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); 1826 *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; 1827 TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); 1828 } 1829 return pidl; 1830 1831 } 1832 1833 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) 1834 { 1835 HANDLE hFile; 1836 WIN32_FIND_DATAW stffile; 1837 1838 if (!ppidl) 1839 return E_INVALIDARG; 1840 1841 hFile = FindFirstFileW(szPath, &stffile); 1842 if (hFile == INVALID_HANDLE_VALUE) 1843 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 1844 1845 FindClose(hFile); 1846 1847 *ppidl = _ILCreateFromFindDataW(&stffile); 1848 1849 return *ppidl ? S_OK : E_OUTOFMEMORY; 1850 } 1851 1852 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) 1853 { 1854 LPITEMIDLIST pidlOut; 1855 1856 TRACE("(%s)\n",debugstr_w(lpszNew)); 1857 1858 pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); 1859 if (pidlOut) 1860 { 1861 LPSTR pszDest; 1862 1863 pszDest = _ILGetTextPointer(pidlOut); 1864 if (pszDest) 1865 { 1866 strcpy(pszDest, "x:\\"); 1867 pszDest[0]=toupperW(lpszNew[0]); 1868 TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); 1869 } 1870 } 1871 return pidlOut; 1872 } 1873 1874 LPITEMIDLIST _ILCreateEntireNetwork(void) 1875 { 1876 LPITEMIDLIST pidlOut; 1877 1878 TRACE("\n"); 1879 1880 pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); 1881 if (pidlOut) 1882 { 1883 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1884 1885 pData->u.network.dummy = 0; 1886 strcpy(pData->u.network.szNames, "Entire Network"); 1887 } 1888 return pidlOut; 1889 } 1890 1891 /************************************************************************** 1892 * _ILGetDrive() 1893 * 1894 * Gets the text for the drive eg. 'c:\' 1895 * 1896 * RETURNS 1897 * strlen (lpszText) 1898 */ 1899 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) 1900 { 1901 TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); 1902 1903 if(_ILIsMyComputer(pidl)) 1904 pidl = ILGetNext(pidl); 1905 1906 if (pidl && _ILIsDrive(pidl)) 1907 return _ILSimpleGetText(pidl, pOut, uSize); 1908 1909 return 0; 1910 } 1911 1912 /************************************************************************** 1913 * 1914 * ### 2. section testing pidls ### 1915 * 1916 ************************************************************************** 1917 * _ILIsUnicode() 1918 * _ILIsDesktop() 1919 * _ILIsMyComputer() 1920 * _ILIsSpecialFolder() 1921 * _ILIsDrive() 1922 * _ILIsFolder() 1923 * _ILIsValue() 1924 * _ILIsPidlSimple() 1925 */ 1926 BOOL _ILIsUnicode(LPCITEMIDLIST pidl) 1927 { 1928 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1929 1930 TRACE("(%p)\n",pidl); 1931 1932 return (pidl && lpPData && PT_VALUEW == lpPData->type); 1933 } 1934 1935 BOOL _ILIsDesktop(LPCITEMIDLIST pidl) 1936 { 1937 TRACE("(%p)\n",pidl); 1938 1939 return !pidl || !pidl->mkid.cb; 1940 } 1941 1942 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl) 1943 { 1944 IID *iid = _ILGetGUIDPointer(pidl); 1945 1946 TRACE("(%p)\n", pidl); 1947 1948 if (iid) 1949 return IsEqualIID(iid, &CLSID_MyDocuments); 1950 return FALSE; 1951 } 1952 1953 BOOL _ILIsNetHood(LPCITEMIDLIST pidl) 1954 { 1955 IID *iid = _ILGetGUIDPointer(pidl); 1956 1957 TRACE("(%p)\n", pidl); 1958 1959 if (iid) 1960 return IsEqualIID(iid, &CLSID_NetworkPlaces); 1961 return FALSE; 1962 } 1963 1964 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl) 1965 { 1966 IID *iid = _ILGetGUIDPointer(pidl); 1967 1968 TRACE("(%p)\n", pidl); 1969 1970 if (iid) 1971 return IsEqualIID(iid, &CLSID_ControlPanel); 1972 return FALSE; 1973 } 1974 1975 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) 1976 { 1977 REFIID iid = _ILGetGUIDPointer(pidl); 1978 1979 TRACE("(%p)\n",pidl); 1980 1981 if (iid) 1982 return IsEqualIID(iid, &CLSID_MyComputer); 1983 return FALSE; 1984 } 1985 1986 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl) 1987 { 1988 IID *iid = _ILGetGUIDPointer(pidl); 1989 1990 TRACE("(%p)\n", pidl); 1991 1992 if (iid) 1993 return IsEqualIID(iid, &CLSID_RecycleBin); 1994 return FALSE; 1995 } 1996 1997 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) 1998 { 1999 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2000 2001 TRACE("(%p)\n",pidl); 2002 2003 return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || 2004 (pidl && pidl->mkid.cb == 0x00) 2005 )); 2006 } 2007 2008 BOOL _ILIsDrive(LPCITEMIDLIST pidl) 2009 { 2010 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2011 2012 TRACE("(%p)\n",pidl); 2013 2014 return (pidl && lpPData && (PT_DRIVE == lpPData->type || 2015 PT_DRIVE1 == lpPData->type || 2016 PT_DRIVE2 == lpPData->type || 2017 PT_DRIVE3 == lpPData->type)); 2018 } 2019 2020 BOOL _ILIsFolder(LPCITEMIDLIST pidl) 2021 { 2022 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2023 2024 TRACE("(%p)\n",pidl); 2025 2026 return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); 2027 } 2028 2029 BOOL _ILIsValue(LPCITEMIDLIST pidl) 2030 { 2031 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2032 2033 TRACE("(%p)\n",pidl); 2034 2035 return (pidl && lpPData && PT_VALUE == lpPData->type); 2036 } 2037 2038 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) 2039 { 2040 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 2041 2042 TRACE("(%p)\n",pidl); 2043 2044 return (pidl && lpPData && (lpPData->type == 0)); 2045 } 2046 2047 /************************************************************************** 2048 * _ILIsPidlSimple 2049 */ 2050 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) 2051 { 2052 BOOL ret = TRUE; 2053 2054 if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */ 2055 { 2056 WORD len = pidl->mkid.cb; 2057 LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); 2058 2059 if (pidlnext->mkid.cb) 2060 ret = FALSE; 2061 } 2062 2063 TRACE("%s\n", ret ? "Yes" : "No"); 2064 return ret; 2065 } 2066 2067 /************************************************************************** 2068 * 2069 * ### 3. section getting values from pidls ### 2070 */ 2071 2072 /************************************************************************** 2073 * _ILSimpleGetText 2074 * 2075 * gets the text for the first item in the pidl (eg. simple pidl) 2076 * 2077 * returns the length of the string 2078 */ 2079 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) 2080 { 2081 DWORD dwReturn=0; 2082 LPSTR szSrc; 2083 LPWSTR szSrcW; 2084 GUID const * riid; 2085 char szTemp[MAX_PATH]; 2086 2087 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2088 2089 if (!pidl) 2090 return 0; 2091 2092 if (szOut) 2093 *szOut = 0; 2094 2095 if (_ILIsDesktop(pidl)) 2096 { 2097 /* desktop */ 2098 if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2099 { 2100 if (szOut) 2101 lstrcpynA(szOut, szTemp, uOutSize); 2102 2103 dwReturn = strlen (szTemp); 2104 } 2105 } 2106 else if (( szSrc = _ILGetTextPointer(pidl) )) 2107 { 2108 /* filesystem */ 2109 if (szOut) 2110 lstrcpynA(szOut, szSrc, uOutSize); 2111 2112 dwReturn = strlen(szSrc); 2113 } 2114 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2115 { 2116 /* unicode filesystem */ 2117 WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); 2118 2119 if (szOut) 2120 lstrcpynA(szOut, szTemp, uOutSize); 2121 2122 dwReturn = strlen (szTemp); 2123 } 2124 else if (( riid = _ILGetGUIDPointer(pidl) )) 2125 { 2126 /* special folder */ 2127 if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) ) 2128 { 2129 if (szOut) 2130 lstrcpynA(szOut, szTemp, uOutSize); 2131 2132 dwReturn = strlen (szTemp); 2133 } 2134 } 2135 else 2136 { 2137 ERR("-- no text\n"); 2138 } 2139 2140 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn); 2141 return dwReturn; 2142 } 2143 2144 /************************************************************************** 2145 * _ILSimpleGetTextW 2146 * 2147 * gets the text for the first item in the pidl (eg. simple pidl) 2148 * 2149 * returns the length of the string 2150 */ 2151 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) 2152 { 2153 DWORD dwReturn; 2154 FileStructW *pFileStructW = _ILGetFileStructW(pidl); 2155 2156 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2157 2158 if (pFileStructW) { 2159 lstrcpynW(szOut, pFileStructW->wszName, uOutSize); 2160 dwReturn = lstrlenW(pFileStructW->wszName); 2161 } else { 2162 GUID const * riid; 2163 WCHAR szTemp[MAX_PATH]; 2164 LPSTR szSrc; 2165 LPWSTR szSrcW; 2166 dwReturn=0; 2167 2168 if (!pidl) 2169 return 0; 2170 2171 if (szOut) 2172 *szOut = 0; 2173 2174 if (_ILIsDesktop(pidl)) 2175 { 2176 /* desktop */ 2177 if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2178 { 2179 if (szOut) 2180 lstrcpynW(szOut, szTemp, uOutSize); 2181 2182 dwReturn = lstrlenW (szTemp); 2183 } 2184 } 2185 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2186 { 2187 /* unicode filesystem */ 2188 if (szOut) 2189 lstrcpynW(szOut, szSrcW, uOutSize); 2190 2191 dwReturn = lstrlenW(szSrcW); 2192 } 2193 else if (( szSrc = _ILGetTextPointer(pidl) )) 2194 { 2195 /* filesystem */ 2196 MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); 2197 2198 if (szOut) 2199 lstrcpynW(szOut, szTemp, uOutSize); 2200 2201 dwReturn = lstrlenW (szTemp); 2202 } 2203 else if (( riid = _ILGetGUIDPointer(pidl) )) 2204 { 2205 /* special folder */ 2206 if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) ) 2207 { 2208 if (szOut) 2209 lstrcpynW(szOut, szTemp, uOutSize); 2210 2211 dwReturn = lstrlenW (szTemp); 2212 } 2213 } 2214 else 2215 { 2216 ERR("-- no text\n"); 2217 } 2218 } 2219 2220 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); 2221 return dwReturn; 2222 } 2223 2224 /************************************************************************** 2225 * 2226 * ### 4. getting pointers to parts of pidls ### 2227 * 2228 ************************************************************************** 2229 * _ILGetDataPointer() 2230 */ 2231 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) 2232 { 2233 if(!_ILIsEmpty(pidl)) 2234 return (LPPIDLDATA)pidl->mkid.abID; 2235 return NULL; 2236 } 2237 2238 /************************************************************************** 2239 * _ILGetTextPointerW() 2240 * gets a pointer to the unicode long filename string stored in the pidl 2241 */ 2242 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) 2243 { 2244 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2245 2246 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2247 2248 if (!pdata) 2249 return NULL; 2250 2251 switch (pdata->type) 2252 { 2253 case PT_GUID: 2254 case PT_SHELLEXT: 2255 case PT_YAGUID: 2256 return NULL; 2257 2258 case PT_DRIVE: 2259 case PT_DRIVE1: 2260 case PT_DRIVE2: 2261 case PT_DRIVE3: 2262 /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ 2263 return NULL; 2264 2265 case PT_FOLDER: 2266 case PT_FOLDER1: 2267 case PT_VALUE: 2268 case PT_IESPECIAL1: 2269 case PT_IESPECIAL2: 2270 /*return (LPSTR)&(pdata->u.file.szNames);*/ 2271 return NULL; 2272 2273 case PT_WORKGRP: 2274 case PT_COMP: 2275 case PT_NETWORK: 2276 case PT_NETPROVIDER: 2277 case PT_SHARE: 2278 /*return (LPSTR)&(pdata->u.network.szNames);*/ 2279 return NULL; 2280 2281 case PT_VALUEW: 2282 return (LPWSTR)pdata->u.file.szNames; 2283 2284 #ifdef __REACTOS__ /* r54423 */ 2285 case PT_CPLAPPLET: 2286 return pdata->u.cpanel.szName; 2287 #endif 2288 2289 } 2290 return NULL; 2291 } 2292 2293 2294 /************************************************************************** 2295 * _ILGetTextPointer() 2296 * gets a pointer to the long filename string stored in the pidl 2297 */ 2298 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) 2299 { 2300 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2301 2302 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2303 2304 if (!pdata) 2305 return NULL; 2306 2307 switch (pdata->type) 2308 { 2309 case PT_GUID: 2310 case PT_SHELLEXT: 2311 case PT_YAGUID: 2312 return NULL; 2313 2314 case PT_DRIVE: 2315 case PT_DRIVE1: 2316 case PT_DRIVE2: 2317 case PT_DRIVE3: 2318 return pdata->u.drive.szDriveName; 2319 2320 case PT_FOLDER: 2321 case PT_FOLDER1: 2322 case PT_VALUE: 2323 case PT_IESPECIAL1: 2324 case PT_IESPECIAL2: 2325 return pdata->u.file.szNames; 2326 2327 case PT_WORKGRP: 2328 case PT_COMP: 2329 case PT_NETWORK: 2330 case PT_NETPROVIDER: 2331 case PT_SHARE: 2332 return pdata->u.network.szNames; 2333 } 2334 return NULL; 2335 } 2336 2337 /************************************************************************** 2338 * _ILGetSTextPointer() 2339 * gets a pointer to the short filename string stored in the pidl 2340 */ 2341 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) 2342 { 2343 /* TRACE(pidl,"(pidl%p)\n", pidl); */ 2344 2345 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2346 2347 if (!pdata) 2348 return NULL; 2349 2350 switch (pdata->type) 2351 { 2352 case PT_FOLDER: 2353 case PT_VALUE: 2354 case PT_IESPECIAL1: 2355 case PT_IESPECIAL2: 2356 return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; 2357 2358 case PT_WORKGRP: 2359 return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; 2360 } 2361 return NULL; 2362 } 2363 2364 /************************************************************************** 2365 * _ILGetGUIDPointer() 2366 * 2367 * returns reference to guid stored in some pidls 2368 */ 2369 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) 2370 { 2371 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2372 2373 TRACE("%p\n", pidl); 2374 2375 if (!pdata) 2376 return NULL; 2377 2378 TRACE("pdata->type 0x%04x\n", pdata->type); 2379 switch (pdata->type) 2380 { 2381 case PT_SHELLEXT: 2382 case PT_GUID: 2383 case PT_YAGUID: 2384 return &(pdata->u.guid.guid); 2385 2386 default: 2387 TRACE("Unknown pidl type 0x%04x\n", pdata->type); 2388 break; 2389 } 2390 return NULL; 2391 } 2392 2393 /****************************************************************************** 2394 * _ILGetFileStructW [Internal] 2395 * 2396 * Get pointer the a SHITEMID's FileStructW field if present 2397 * 2398 * PARAMS 2399 * pidl [I] The SHITEMID 2400 * 2401 * RETURNS 2402 * Success: Pointer to pidl's FileStructW field. 2403 * Failure: NULL 2404 */ 2405 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { 2406 FileStructW *pFileStructW; 2407 WORD cbOffset; 2408 2409 if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) 2410 return NULL; 2411 2412 cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); 2413 pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); 2414 2415 /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP 2416 * style with a FileStructW member. If we switch all our shellfolder-implementations to 2417 * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ 2418 if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */ 2419 /* FileStructW is positioned after FileStruct */ 2420 cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || 2421 /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ 2422 cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || 2423 pidl->mkid.cb != cbOffset + pFileStructW->cbLen) 2424 { 2425 WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); 2426 return NULL; 2427 } 2428 2429 return pFileStructW; 2430 } 2431 2432 /************************************************************************* 2433 * _ILGetFileDateTime 2434 * 2435 * Given the ItemIdList, get the FileTime 2436 * 2437 * PARAMS 2438 * pidl [I] The ItemIDList 2439 * pFt [I] the resulted FILETIME of the file 2440 * 2441 * RETURNS 2442 * True if Successful 2443 * 2444 * NOTES 2445 * 2446 */ 2447 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) 2448 { 2449 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2450 2451 if (!pdata) 2452 return FALSE; 2453 2454 switch (pdata->type) 2455 { 2456 case PT_FOLDER: 2457 case PT_VALUE: 2458 DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); 2459 break; 2460 default: 2461 return FALSE; 2462 } 2463 return TRUE; 2464 } 2465 2466 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2467 { 2468 FILETIME ft,lft; 2469 SYSTEMTIME time; 2470 BOOL ret; 2471 2472 if (_ILGetFileDateTime( pidl, &ft )) 2473 { 2474 FileTimeToLocalFileTime(&ft, &lft); 2475 FileTimeToSystemTime (&lft, &time); 2476 2477 ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize); 2478 if (ret) 2479 { 2480 /* Append space + time without seconds */ 2481 pOut[ret-1] = ' '; 2482 GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); 2483 } 2484 } 2485 else 2486 { 2487 pOut[0] = '\0'; 2488 ret = FALSE; 2489 } 2490 return ret; 2491 } 2492 2493 /************************************************************************* 2494 * _ILGetFileSize 2495 * 2496 * Given the ItemIdList, get the FileSize 2497 * 2498 * PARAMS 2499 * pidl [I] The ItemIDList 2500 * pOut [I] The buffer to save the result 2501 * uOutsize [I] The size of the buffer 2502 * 2503 * RETURNS 2504 * The FileSize 2505 * 2506 * NOTES 2507 * pOut can be null when no string is needed 2508 * 2509 */ 2510 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2511 { 2512 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2513 DWORD dwSize; 2514 2515 if (!pdata) 2516 return 0; 2517 2518 switch (pdata->type) 2519 { 2520 case PT_VALUE: 2521 dwSize = pdata->u.file.dwFileSize; 2522 if (pOut) 2523 StrFormatKBSizeA(dwSize, pOut, uOutSize); 2524 return dwSize; 2525 } 2526 if (pOut) 2527 *pOut = 0x00; 2528 return 0; 2529 } 2530 2531 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2532 { 2533 char szTemp[MAX_PATH]; 2534 const char * pPoint; 2535 LPCITEMIDLIST pidlTemp=pidl; 2536 2537 TRACE("pidl=%p\n",pidl); 2538 2539 if (!pidl) 2540 return FALSE; 2541 2542 pidlTemp = ILFindLastID(pidl); 2543 2544 if (!_ILIsValue(pidlTemp)) 2545 return FALSE; 2546 if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) 2547 return FALSE; 2548 2549 pPoint = PathFindExtensionA(szTemp); 2550 2551 if (!*pPoint) 2552 return FALSE; 2553 2554 pPoint++; 2555 lstrcpynA(pOut, pPoint, uOutSize); 2556 TRACE("%s\n",pOut); 2557 2558 return TRUE; 2559 } 2560 2561 /************************************************************************* 2562 * _ILGetFileType 2563 * 2564 * Given the ItemIdList, get the file type description 2565 * 2566 * PARAMS 2567 * pidl [I] The ItemIDList (simple) 2568 * pOut [I] The buffer to save the result 2569 * uOutsize [I] The size of the buffer 2570 * 2571 * RETURNS 2572 * nothing 2573 * 2574 * NOTES 2575 * This function copies as much as possible into the buffer. 2576 */ 2577 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2578 { 2579 #ifdef __REACTOS__ /* r32966 */ 2580 char sType[64]; 2581 #endif 2582 2583 if(_ILIsValue(pidl)) 2584 { 2585 char sTemp[64]; 2586 2587 if(uOutSize > 0) 2588 pOut[0] = 0; 2589 #ifdef __REACTOS__ /* r32966 */ 2590 if (_ILGetExtension (pidl, sType, 64)) 2591 { 2592 if (HCR_MapTypeToValueA(sType, sTemp, 64, TRUE)) 2593 { 2594 /* retrieve description */ 2595 if(HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )) 2596 return; 2597 } 2598 /* display Ext-file as description */ 2599 _strupr(sType); 2600 /* load localized file string */ 2601 sTemp[0] = '\0'; 2602 if(LoadStringA(shell32_hInstance, IDS_ANY_FILE, sTemp, 64)) 2603 { 2604 sTemp[63] = '\0'; 2605 StringCchPrintfA(pOut, uOutSize, sTemp, sType); 2606 } 2607 } 2608 #else 2609 if (_ILGetExtension (pidl, sTemp, 64)) 2610 { 2611 if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE) 2612 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE ))) 2613 { 2614 lstrcpynA (pOut, sTemp, uOutSize - 6); 2615 strcat (pOut, "-file"); 2616 } 2617 } 2618 #endif 2619 } 2620 else 2621 #ifdef __REACTOS__ /* r32966 */ 2622 { 2623 pOut[0] = '\0'; 2624 LoadStringA(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize); 2625 /* make sure its null terminated */ 2626 pOut[uOutSize-1] = '\0'; 2627 } 2628 #else 2629 lstrcpynA(pOut, "Folder", uOutSize); 2630 #endif 2631 } 2632 2633 /************************************************************************* 2634 * _ILGetFileAttributes 2635 * 2636 * Given the ItemIdList, get the Attrib string format 2637 * 2638 * PARAMS 2639 * pidl [I] The ItemIDList 2640 * pOut [I] The buffer to save the result 2641 * uOutsize [I] The size of the Buffer 2642 * 2643 * RETURNS 2644 * Attributes 2645 * 2646 * FIXME 2647 * return value 0 in case of error is a valid return value 2648 * 2649 */ 2650 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2651 { 2652 LPPIDLDATA pData = _ILGetDataPointer(pidl); 2653 WORD wAttrib = 0; 2654 int i; 2655 2656 if (!pData) 2657 return 0; 2658 2659 switch(pData->type) 2660 { 2661 case PT_FOLDER: 2662 case PT_VALUE: 2663 wAttrib = pData->u.file.uFileAttribs; 2664 break; 2665 } 2666 2667 if(uOutSize >= 6) 2668 { 2669 i=0; 2670 if(wAttrib & FILE_ATTRIBUTE_READONLY) 2671 pOut[i++] = 'R'; 2672 if(wAttrib & FILE_ATTRIBUTE_HIDDEN) 2673 pOut[i++] = 'H'; 2674 if(wAttrib & FILE_ATTRIBUTE_SYSTEM) 2675 pOut[i++] = 'S'; 2676 if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) 2677 pOut[i++] = 'A'; 2678 if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) 2679 pOut[i++] = 'C'; 2680 pOut[i] = 0x00; 2681 } 2682 return wAttrib; 2683 } 2684 2685 /************************************************************************* 2686 * ILFreeaPidl 2687 * 2688 * frees an aPidl struct 2689 */ 2690 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) 2691 { 2692 UINT i; 2693 2694 if (apidl) 2695 { 2696 for (i = 0; i < cidl; i++) 2697 SHFree(apidl[i]); 2698 SHFree(apidl); 2699 } 2700 } 2701 2702 /************************************************************************* 2703 * ILCopyaPidl 2704 * 2705 * copies an aPidl struct 2706 */ 2707 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl) 2708 { 2709 UINT i; 2710 PITEMID_CHILD *apidldest; 2711 2712 if (!apidlsrc) 2713 return NULL; 2714 2715 apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD)); 2716 2717 for (i = 0; i < cidl; i++) 2718 apidldest[i] = ILClone(apidlsrc[i]); 2719 2720 return apidldest; 2721 } 2722 2723 /************************************************************************* 2724 * _ILCopyCidaToaPidl 2725 * 2726 * creates aPidl from CIDA 2727 */ 2728 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) 2729 { 2730 UINT i; 2731 LPITEMIDLIST *dst; 2732 2733 dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); 2734 if (!dst) 2735 return NULL; 2736 2737 if (pidl) 2738 *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); 2739 2740 for (i = 0; i < cida->cidl; i++) 2741 dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); 2742 2743 return dst; 2744 } 2745