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