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