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 // FIXME: Needs folder attribute 1105 if (PathFileExistsW(wPath)) 1106 { 1107 pidl = ILCreateFromPathW(wPath); 1108 HeapFree(GetProcessHeap(), 0, wPath); 1109 return pidl; 1110 } 1111 #endif 1112 1113 _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); 1114 1115 HeapFree(GetProcessHeap(), 0, wPath); 1116 TRACE("%s %p\n", debugstr_a(lpszPath), pidl); 1117 return pidl; 1118 } 1119 1120 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) 1121 { 1122 LPITEMIDLIST pidl = NULL; 1123 1124 TRACE("%s\n", debugstr_w(lpszPath)); 1125 #ifdef __REACTOS__ 1126 // FIXME: Needs folder attribute 1127 if (PathFileExistsW(lpszPath)) 1128 return ILCreateFromPathW(lpszPath); 1129 #endif 1130 1131 _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); 1132 TRACE("%s %p\n", debugstr_w(lpszPath), pidl); 1133 return pidl; 1134 } 1135 1136 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) 1137 { 1138 if ( SHELL_OsIsUnicode()) 1139 return SHSimpleIDListFromPathW (lpszPath); 1140 return SHSimpleIDListFromPathA (lpszPath); 1141 } 1142 1143 /************************************************************************* 1144 * SHGetDataFromIDListA [SHELL32.247] 1145 * 1146 * NOTES 1147 * the pidl can be a simple one. since we can't get the path out of the pidl 1148 * we have to take all data from the pidl 1149 */ 1150 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1151 int nFormat, LPVOID dest, int len) 1152 { 1153 LPSTR filename, shortname; 1154 WIN32_FIND_DATAA * pfd; 1155 1156 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1157 1158 pdump(pidl); 1159 if (!psf || !dest) 1160 return E_INVALIDARG; 1161 1162 switch (nFormat) 1163 { 1164 case SHGDFIL_FINDDATA: 1165 pfd = dest; 1166 1167 if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) 1168 return E_INVALIDARG; 1169 1170 if (len < sizeof(WIN32_FIND_DATAA)) 1171 return E_INVALIDARG; 1172 1173 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); 1174 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1175 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1176 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1177 1178 filename = _ILGetTextPointer(pidl); 1179 shortname = _ILGetSTextPointer(pidl); 1180 1181 if (filename) 1182 lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); 1183 else 1184 pfd->cFileName[0] = '\0'; 1185 1186 if (shortname) 1187 lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); 1188 else 1189 pfd->cAlternateFileName[0] = '\0'; 1190 return S_OK; 1191 1192 case SHGDFIL_NETRESOURCE: 1193 case SHGDFIL_DESCRIPTIONID: 1194 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1195 break; 1196 1197 default: 1198 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1199 } 1200 1201 return E_INVALIDARG; 1202 } 1203 1204 /************************************************************************* 1205 * SHGetDataFromIDListW [SHELL32.248] 1206 * 1207 */ 1208 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1209 int nFormat, LPVOID dest, int len) 1210 { 1211 LPSTR filename, shortname; 1212 WIN32_FIND_DATAW * pfd = dest; 1213 1214 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1215 1216 pdump(pidl); 1217 1218 if (!psf || !dest) 1219 return E_INVALIDARG; 1220 1221 switch (nFormat) 1222 { 1223 case SHGDFIL_FINDDATA: 1224 pfd = dest; 1225 1226 if (_ILIsDrive(pidl)) 1227 return E_INVALIDARG; 1228 1229 if (len < sizeof(WIN32_FIND_DATAW)) 1230 return E_INVALIDARG; 1231 1232 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW)); 1233 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1234 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1235 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1236 1237 filename = _ILGetTextPointer(pidl); 1238 shortname = _ILGetSTextPointer(pidl); 1239 1240 if (!filename) 1241 pfd->cFileName[0] = '\0'; 1242 else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) 1243 pfd->cFileName[MAX_PATH-1] = 0; 1244 1245 if (!shortname) 1246 pfd->cAlternateFileName[0] = '\0'; 1247 else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) 1248 pfd->cAlternateFileName[13] = 0; 1249 return S_OK; 1250 1251 case SHGDFIL_NETRESOURCE: 1252 case SHGDFIL_DESCRIPTIONID: 1253 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1254 break; 1255 1256 default: 1257 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1258 } 1259 1260 return E_INVALIDARG; 1261 } 1262 1263 /************************************************************************* 1264 * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220] 1265 * 1266 * PARAMETERS 1267 * pidl, [IN] pidl 1268 * pszPath [OUT] path 1269 * 1270 * RETURNS 1271 * path from a passed PIDL. 1272 * 1273 * NOTES 1274 * NULL returns FALSE 1275 * desktop pidl gives path to desktop directory back 1276 * special pidls returning FALSE 1277 */ 1278 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) 1279 { 1280 WCHAR wszPath[MAX_PATH]; 1281 BOOL bSuccess; 1282 1283 bSuccess = SHGetPathFromIDListW(pidl, wszPath); 1284 WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); 1285 1286 return bSuccess; 1287 } 1288 1289 /************************************************************************* 1290 * SHGetPathFromIDListW [SHELL32.@] 1291 * 1292 * See SHGetPathFromIDListA. 1293 */ 1294 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) 1295 { 1296 HRESULT hr; 1297 LPCITEMIDLIST pidlLast; 1298 LPSHELLFOLDER psfFolder; 1299 DWORD dwAttributes; 1300 STRRET strret; 1301 1302 TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); 1303 pdump(pidl); 1304 1305 *pszPath = '\0'; 1306 if (!pidl) 1307 return FALSE; 1308 1309 hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); 1310 if (FAILED(hr)) 1311 { 1312 ERR("SHBindToParent failed: %x\n", hr); 1313 return FALSE; 1314 } 1315 1316 dwAttributes = SFGAO_FILESYSTEM; 1317 hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); 1318 if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) { 1319 WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr); 1320 IShellFolder_Release(psfFolder); 1321 return FALSE; 1322 } 1323 1324 hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); 1325 IShellFolder_Release(psfFolder); 1326 if (FAILED(hr)) return FALSE; 1327 1328 hr = StrRetToBufW(&strret, pidlLast, pszPath, MAX_PATH); 1329 1330 TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); 1331 return SUCCEEDED(hr); 1332 } 1333 1334 /************************************************************************* 1335 * SHBindToParent [shell version 5.0] 1336 */ 1337 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) 1338 { 1339 IShellFolder * psfDesktop; 1340 HRESULT hr=E_FAIL; 1341 1342 TRACE_(shell)("pidl=%p\n", pidl); 1343 pdump(pidl); 1344 1345 if (!pidl || !ppv) 1346 return E_INVALIDARG; 1347 1348 *ppv = NULL; 1349 if (ppidlLast) 1350 *ppidlLast = NULL; 1351 1352 hr = SHGetDesktopFolder(&psfDesktop); 1353 if (FAILED(hr)) 1354 return hr; 1355 1356 if (_ILIsPidlSimple(pidl)) 1357 { 1358 /* we are on desktop level */ 1359 hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv); 1360 } 1361 else 1362 { 1363 LPITEMIDLIST pidlParent = ILClone(pidl); 1364 ILRemoveLastID(pidlParent); 1365 hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv); 1366 SHFree (pidlParent); 1367 } 1368 1369 IShellFolder_Release(psfDesktop); 1370 1371 if (SUCCEEDED(hr) && ppidlLast) 1372 *ppidlLast = ILFindLastID(pidl); 1373 1374 TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); 1375 return hr; 1376 } 1377 1378 /************************************************************************* 1379 * SHParseDisplayName [shell version 6.0] 1380 */ 1381 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, 1382 LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) 1383 { 1384 IShellFolder *psfDesktop; 1385 HRESULT hr=E_FAIL; 1386 ULONG dwAttr=sfgaoIn; 1387 1388 if(!ppidl) 1389 return E_INVALIDARG; 1390 1391 if (!pszName) 1392 { 1393 *ppidl = NULL; 1394 return E_INVALIDARG; 1395 } 1396 1397 hr = SHGetDesktopFolder(&psfDesktop); 1398 if (FAILED(hr)) 1399 { 1400 *ppidl = NULL; 1401 return hr; 1402 } 1403 1404 hr = IShellFolder_ParseDisplayName(psfDesktop, (HWND)NULL, pbc, (LPOLESTR)pszName, (ULONG *)NULL, ppidl, &dwAttr); 1405 1406 IShellFolder_Release(psfDesktop); 1407 1408 if (SUCCEEDED(hr)) 1409 { 1410 if (psfgaoOut) *psfgaoOut = dwAttr; 1411 } 1412 else 1413 { 1414 *ppidl = NULL; 1415 } 1416 1417 return hr; 1418 } 1419 1420 /************************************************************************* 1421 * SHGetNameFromIDList [SHELL32.@] 1422 */ 1423 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName) 1424 { 1425 IShellFolder *psfparent; 1426 LPCITEMIDLIST child_pidl; 1427 STRRET disp_name; 1428 HRESULT ret; 1429 1430 TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName); 1431 1432 *ppszName = NULL; 1433 ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl); 1434 if(SUCCEEDED(ret)) 1435 { 1436 switch(sigdnName) 1437 { 1438 /* sigdnName & 0xffff */ 1439 case SIGDN_NORMALDISPLAY: /* SHGDN_NORMAL */ 1440 case SIGDN_PARENTRELATIVEPARSING: /* SHGDN_INFOLDER | SHGDN_FORPARSING */ 1441 case SIGDN_PARENTRELATIVEEDITING: /* SHGDN_INFOLDER | SHGDN_FOREDITING */ 1442 case SIGDN_DESKTOPABSOLUTEPARSING: /* SHGDN_FORPARSING */ 1443 case SIGDN_DESKTOPABSOLUTEEDITING: /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/ 1444 case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */ 1445 case SIGDN_PARENTRELATIVE: /* SIGDN_INFOLDER */ 1446 1447 disp_name.uType = STRRET_WSTR; 1448 ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl, 1449 sigdnName & 0xffff, 1450 &disp_name); 1451 if(SUCCEEDED(ret)) 1452 ret = StrRetToStrW(&disp_name, pidl, ppszName); 1453 1454 break; 1455 1456 case SIGDN_FILESYSPATH: 1457 *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH); 1458 if(SHGetPathFromIDListW(pidl, *ppszName)) 1459 { 1460 TRACE("Got string %s\n", debugstr_w(*ppszName)); 1461 ret = S_OK; 1462 } 1463 else 1464 { 1465 CoTaskMemFree(*ppszName); 1466 ret = E_INVALIDARG; 1467 } 1468 break; 1469 1470 case SIGDN_URL: 1471 default: 1472 FIXME("Unsupported SIGDN %x\n", sigdnName); 1473 ret = E_FAIL; 1474 } 1475 1476 IShellFolder_Release(psfparent); 1477 } 1478 return ret; 1479 } 1480 1481 #ifndef __REACTOS__ 1482 1483 /************************************************************************* 1484 * SHGetIDListFromObject [SHELL32.@] 1485 */ 1486 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) 1487 { 1488 IPersistIDList *ppersidl; 1489 IPersistFolder2 *ppf2; 1490 IDataObject *pdo; 1491 IFolderView *pfv; 1492 HRESULT ret; 1493 1494 if(!punk) 1495 return E_NOINTERFACE; 1496 1497 *ppidl = NULL; 1498 1499 /* Try IPersistIDList */ 1500 ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl); 1501 if(SUCCEEDED(ret)) 1502 { 1503 TRACE("IPersistIDList (%p)\n", ppersidl); 1504 ret = IPersistIDList_GetIDList(ppersidl, ppidl); 1505 IPersistIDList_Release(ppersidl); 1506 if(SUCCEEDED(ret)) 1507 return ret; 1508 } 1509 1510 /* Try IPersistFolder2 */ 1511 ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2); 1512 if(SUCCEEDED(ret)) 1513 { 1514 TRACE("IPersistFolder2 (%p)\n", ppf2); 1515 ret = IPersistFolder2_GetCurFolder(ppf2, ppidl); 1516 IPersistFolder2_Release(ppf2); 1517 if(SUCCEEDED(ret)) 1518 return ret; 1519 } 1520 1521 /* Try IDataObject */ 1522 ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo); 1523 if(SUCCEEDED(ret)) 1524 { 1525 IShellItem *psi; 1526 TRACE("IDataObject (%p)\n", pdo); 1527 ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, 1528 &IID_IShellItem, (void**)&psi); 1529 if(SUCCEEDED(ret)) 1530 { 1531 ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); 1532 IShellItem_Release(psi); 1533 } 1534 IDataObject_Release(pdo); 1535 1536 if(SUCCEEDED(ret)) 1537 return ret; 1538 } 1539 1540 /* Try IFolderView */ 1541 ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv); 1542 if(SUCCEEDED(ret)) 1543 { 1544 IShellFolder *psf; 1545 TRACE("IFolderView (%p)\n", pfv); 1546 ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf); 1547 if(SUCCEEDED(ret)) 1548 { 1549 /* We might be able to get IPersistFolder2 from a shellfolder. */ 1550 ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); 1551 } 1552 IFolderView_Release(pfv); 1553 return ret; 1554 } 1555 1556 return ret; 1557 } 1558 1559 #endif /* !__REACTOS__ */ 1560 1561 /************************************************************************** 1562 * 1563 * internal functions 1564 * 1565 * ### 1. section creating pidls ### 1566 * 1567 ************************************************************************* 1568 */ 1569 1570 /* Basic PIDL constructor. Allocates size + 5 bytes, where: 1571 * - two bytes are SHITEMID.cb 1572 * - one byte is PIDLDATA.type 1573 * - two bytes are the NULL PIDL terminator 1574 * Sets type of the returned PIDL to type. 1575 */ 1576 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) 1577 { 1578 LPITEMIDLIST pidlOut = NULL; 1579 1580 pidlOut = SHAlloc(size + 5); 1581 if(pidlOut) 1582 { 1583 LPPIDLDATA pData; 1584 LPITEMIDLIST pidlNext; 1585 1586 ZeroMemory(pidlOut, size + 5); 1587 pidlOut->mkid.cb = size + 3; 1588 1589 pData = _ILGetDataPointer(pidlOut); 1590 if (pData) 1591 pData->type = type; 1592 1593 pidlNext = ILGetNext(pidlOut); 1594 if (pidlNext) 1595 pidlNext->mkid.cb = 0x00; 1596 TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); 1597 } 1598 1599 return pidlOut; 1600 } 1601 1602 LPITEMIDLIST _ILCreateDesktop(void) 1603 { 1604 LPITEMIDLIST ret; 1605 1606 TRACE("()\n"); 1607 ret = SHAlloc(2); 1608 if (ret) 1609 ret->mkid.cb = 0; 1610 return ret; 1611 } 1612 1613 LPITEMIDLIST _ILCreateMyComputer(void) 1614 { 1615 TRACE("()\n"); 1616 return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); 1617 } 1618 1619 LPITEMIDLIST _ILCreateMyDocuments(void) 1620 { 1621 TRACE("()\n"); 1622 return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); 1623 } 1624 1625 LPITEMIDLIST _ILCreateIExplore(void) 1626 { 1627 TRACE("()\n"); 1628 return _ILCreateGuid(PT_GUID, &CLSID_Internet); 1629 } 1630 1631 LPITEMIDLIST _ILCreateControlPanel(void) 1632 { 1633 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1634 1635 TRACE("()\n"); 1636 if (parent) 1637 { 1638 LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); 1639 1640 if (cpl) 1641 { 1642 ret = ILCombine(parent, cpl); 1643 SHFree(cpl); 1644 } 1645 SHFree(parent); 1646 } 1647 return ret; 1648 } 1649 1650 LPITEMIDLIST _ILCreatePrinters(void) 1651 { 1652 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1653 1654 TRACE("()\n"); 1655 if (parent) 1656 { 1657 LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); 1658 1659 if (printers) 1660 { 1661 ret = ILCombine(parent, printers); 1662 SHFree(printers); 1663 } 1664 SHFree(parent); 1665 } 1666 return ret; 1667 } 1668 1669 LPITEMIDLIST _ILCreateNetwork(void) 1670 { 1671 TRACE("()\n"); 1672 return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); 1673 } 1674 1675 LPITEMIDLIST _ILCreateBitBucket(void) 1676 { 1677 TRACE("()\n"); 1678 return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); 1679 } 1680 1681 LPITEMIDLIST _ILCreateAdminTools(void) 1682 { 1683 TRACE("()\n"); 1684 return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME 1685 } 1686 1687 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) 1688 { 1689 LPITEMIDLIST pidlOut; 1690 1691 if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) 1692 { 1693 pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); 1694 if (pidlOut) 1695 { 1696 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1697 1698 pData->u.guid.guid = *guid; 1699 TRACE("-- create GUID-pidl %s\n", 1700 debugstr_guid(&(pData->u.guid.guid))); 1701 } 1702 } 1703 else 1704 { 1705 WARN("%d: invalid type for GUID\n", type); 1706 pidlOut = NULL; 1707 } 1708 return pidlOut; 1709 } 1710 1711 #ifndef __REACTOS__ 1712 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) 1713 { 1714 IID iid; 1715 1716 if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) 1717 { 1718 ERR("%s is not a GUID\n", szGUID); 1719 return NULL; 1720 } 1721 return _ILCreateGuid(PT_GUID, &iid); 1722 } 1723 #endif 1724 1725 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) 1726 { 1727 IID iid; 1728 1729 #ifndef __REACTOS__ 1730 if (FAILED(SHCLSIDFromStringW(szGUID, &iid))) 1731 #else 1732 if (!GUIDFromStringW(szGUID, &iid)) 1733 #endif 1734 { 1735 ERR("%s is not a GUID\n", debugstr_w(szGUID)); 1736 return NULL; 1737 } 1738 return _ILCreateGuid(PT_GUID, &iid); 1739 } 1740 1741 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) 1742 { 1743 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ 1744 DWORD len, len1, wlen, alen; 1745 LPITEMIDLIST pidl; 1746 PIDLTYPE type; 1747 1748 if (!wfd) 1749 return NULL; 1750 1751 TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); 1752 1753 /* prepare buffer with both names */ 1754 len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); 1755 len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); 1756 alen = len + len1; 1757 1758 type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; 1759 1760 wlen = lstrlenW(wfd->cFileName) + 1; 1761 pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + 1762 FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); 1763 if (pidl) 1764 { 1765 LPPIDLDATA pData = _ILGetDataPointer(pidl); 1766 FileStruct *fs = &pData->u.file; 1767 FileStructW *fsw; 1768 WORD *pOffsetW; 1769 1770 FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); 1771 fs->dwFileSize = wfd->nFileSizeLow; 1772 fs->uFileAttribs = wfd->dwFileAttributes; 1773 memcpy(fs->szNames, buff, alen); 1774 1775 fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); 1776 fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); 1777 FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); 1778 FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); 1779 memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); 1780 1781 pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); 1782 *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; 1783 TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); 1784 } 1785 return pidl; 1786 1787 } 1788 1789 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) 1790 { 1791 HANDLE hFile; 1792 WIN32_FIND_DATAW stffile; 1793 1794 if (!ppidl) 1795 return E_INVALIDARG; 1796 1797 hFile = FindFirstFileW(szPath, &stffile); 1798 if (hFile == INVALID_HANDLE_VALUE) 1799 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 1800 1801 FindClose(hFile); 1802 1803 *ppidl = _ILCreateFromFindDataW(&stffile); 1804 1805 return *ppidl ? S_OK : E_OUTOFMEMORY; 1806 } 1807 1808 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) 1809 { 1810 LPITEMIDLIST pidlOut; 1811 1812 TRACE("(%s)\n",debugstr_w(lpszNew)); 1813 1814 pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); 1815 if (pidlOut) 1816 { 1817 LPSTR pszDest; 1818 1819 pszDest = _ILGetTextPointer(pidlOut); 1820 if (pszDest) 1821 { 1822 strcpy(pszDest, "x:\\"); 1823 pszDest[0]=toupperW(lpszNew[0]); 1824 TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); 1825 } 1826 } 1827 return pidlOut; 1828 } 1829 1830 LPITEMIDLIST _ILCreateEntireNetwork(void) 1831 { 1832 LPITEMIDLIST pidlOut; 1833 1834 TRACE("\n"); 1835 1836 pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); 1837 if (pidlOut) 1838 { 1839 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1840 1841 pData->u.network.dummy = 0; 1842 strcpy(pData->u.network.szNames, "Entire Network"); 1843 } 1844 return pidlOut; 1845 } 1846 1847 /************************************************************************** 1848 * _ILGetDrive() 1849 * 1850 * Gets the text for the drive eg. 'c:\' 1851 * 1852 * RETURNS 1853 * strlen (lpszText) 1854 */ 1855 DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) 1856 { 1857 TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); 1858 1859 if(_ILIsMyComputer(pidl)) 1860 pidl = ILGetNext(pidl); 1861 1862 if (pidl && _ILIsDrive(pidl)) 1863 return _ILSimpleGetText(pidl, pOut, uSize); 1864 1865 return 0; 1866 } 1867 1868 /************************************************************************** 1869 * 1870 * ### 2. section testing pidls ### 1871 * 1872 ************************************************************************** 1873 * _ILIsUnicode() 1874 * _ILIsDesktop() 1875 * _ILIsMyComputer() 1876 * _ILIsSpecialFolder() 1877 * _ILIsDrive() 1878 * _ILIsFolder() 1879 * _ILIsValue() 1880 * _ILIsPidlSimple() 1881 */ 1882 BOOL _ILIsUnicode(LPCITEMIDLIST pidl) 1883 { 1884 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1885 1886 TRACE("(%p)\n",pidl); 1887 1888 return (pidl && lpPData && PT_VALUEW == lpPData->type); 1889 } 1890 1891 BOOL _ILIsDesktop(LPCITEMIDLIST pidl) 1892 { 1893 TRACE("(%p)\n",pidl); 1894 1895 return !pidl || !pidl->mkid.cb; 1896 } 1897 1898 BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl) 1899 { 1900 IID *iid = _ILGetGUIDPointer(pidl); 1901 1902 TRACE("(%p)\n", pidl); 1903 1904 if (iid) 1905 return IsEqualIID(iid, &CLSID_MyDocuments); 1906 return FALSE; 1907 } 1908 1909 BOOL _ILIsNetHood(LPCITEMIDLIST pidl) 1910 { 1911 IID *iid = _ILGetGUIDPointer(pidl); 1912 1913 TRACE("(%p)\n", pidl); 1914 1915 if (iid) 1916 return IsEqualIID(iid, &CLSID_NetworkPlaces); 1917 return FALSE; 1918 } 1919 1920 BOOL _ILIsControlPanel(LPCITEMIDLIST pidl) 1921 { 1922 IID *iid = _ILGetGUIDPointer(pidl); 1923 1924 TRACE("(%p)\n", pidl); 1925 1926 if (iid) 1927 return IsEqualIID(iid, &CLSID_ControlPanel); 1928 return FALSE; 1929 } 1930 1931 BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) 1932 { 1933 REFIID iid = _ILGetGUIDPointer(pidl); 1934 1935 TRACE("(%p)\n",pidl); 1936 1937 if (iid) 1938 return IsEqualIID(iid, &CLSID_MyComputer); 1939 return FALSE; 1940 } 1941 1942 BOOL _ILIsBitBucket(LPCITEMIDLIST pidl) 1943 { 1944 IID *iid = _ILGetGUIDPointer(pidl); 1945 1946 TRACE("(%p)\n", pidl); 1947 1948 if (iid) 1949 return IsEqualIID(iid, &CLSID_RecycleBin); 1950 return FALSE; 1951 } 1952 1953 BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) 1954 { 1955 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1956 1957 TRACE("(%p)\n",pidl); 1958 1959 return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || 1960 (pidl && pidl->mkid.cb == 0x00) 1961 )); 1962 } 1963 1964 BOOL _ILIsDrive(LPCITEMIDLIST pidl) 1965 { 1966 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1967 1968 TRACE("(%p)\n",pidl); 1969 1970 return (pidl && lpPData && (PT_DRIVE == lpPData->type || 1971 PT_DRIVE1 == lpPData->type || 1972 PT_DRIVE2 == lpPData->type || 1973 PT_DRIVE3 == lpPData->type)); 1974 } 1975 1976 BOOL _ILIsFolder(LPCITEMIDLIST pidl) 1977 { 1978 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1979 1980 TRACE("(%p)\n",pidl); 1981 1982 return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); 1983 } 1984 1985 BOOL _ILIsValue(LPCITEMIDLIST pidl) 1986 { 1987 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1988 1989 TRACE("(%p)\n",pidl); 1990 1991 return (pidl && lpPData && PT_VALUE == lpPData->type); 1992 } 1993 1994 BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) 1995 { 1996 LPPIDLDATA lpPData = _ILGetDataPointer(pidl); 1997 1998 TRACE("(%p)\n",pidl); 1999 2000 return (pidl && lpPData && (lpPData->type == 0)); 2001 } 2002 2003 /************************************************************************** 2004 * _ILIsPidlSimple 2005 */ 2006 BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) 2007 { 2008 BOOL ret = TRUE; 2009 2010 if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */ 2011 { 2012 WORD len = pidl->mkid.cb; 2013 LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); 2014 2015 if (pidlnext->mkid.cb) 2016 ret = FALSE; 2017 } 2018 2019 TRACE("%s\n", ret ? "Yes" : "No"); 2020 return ret; 2021 } 2022 2023 /************************************************************************** 2024 * 2025 * ### 3. section getting values from pidls ### 2026 */ 2027 2028 /************************************************************************** 2029 * _ILSimpleGetText 2030 * 2031 * gets the text for the first item in the pidl (eg. simple pidl) 2032 * 2033 * returns the length of the string 2034 */ 2035 DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) 2036 { 2037 DWORD dwReturn=0; 2038 LPSTR szSrc; 2039 LPWSTR szSrcW; 2040 GUID const * riid; 2041 char szTemp[MAX_PATH]; 2042 2043 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2044 2045 if (!pidl) 2046 return 0; 2047 2048 if (szOut) 2049 *szOut = 0; 2050 2051 if (_ILIsDesktop(pidl)) 2052 { 2053 /* desktop */ 2054 if (HCR_GetClassNameA(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2055 { 2056 if (szOut) 2057 lstrcpynA(szOut, szTemp, uOutSize); 2058 2059 dwReturn = strlen (szTemp); 2060 } 2061 } 2062 else if (( szSrc = _ILGetTextPointer(pidl) )) 2063 { 2064 /* filesystem */ 2065 if (szOut) 2066 lstrcpynA(szOut, szSrc, uOutSize); 2067 2068 dwReturn = strlen(szSrc); 2069 } 2070 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2071 { 2072 /* unicode filesystem */ 2073 WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); 2074 2075 if (szOut) 2076 lstrcpynA(szOut, szTemp, uOutSize); 2077 2078 dwReturn = strlen (szTemp); 2079 } 2080 else if (( riid = _ILGetGUIDPointer(pidl) )) 2081 { 2082 /* special folder */ 2083 if ( HCR_GetClassNameA(riid, szTemp, MAX_PATH) ) 2084 { 2085 if (szOut) 2086 lstrcpynA(szOut, szTemp, uOutSize); 2087 2088 dwReturn = strlen (szTemp); 2089 } 2090 } 2091 else 2092 { 2093 ERR("-- no text\n"); 2094 } 2095 2096 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn); 2097 return dwReturn; 2098 } 2099 2100 /************************************************************************** 2101 * _ILSimpleGetTextW 2102 * 2103 * gets the text for the first item in the pidl (eg. simple pidl) 2104 * 2105 * returns the length of the string 2106 */ 2107 DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) 2108 { 2109 DWORD dwReturn; 2110 FileStructW *pFileStructW = _ILGetFileStructW(pidl); 2111 2112 TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); 2113 2114 if (pFileStructW) { 2115 lstrcpynW(szOut, pFileStructW->wszName, uOutSize); 2116 dwReturn = lstrlenW(pFileStructW->wszName); 2117 } else { 2118 GUID const * riid; 2119 WCHAR szTemp[MAX_PATH]; 2120 LPSTR szSrc; 2121 LPWSTR szSrcW; 2122 dwReturn=0; 2123 2124 if (!pidl) 2125 return 0; 2126 2127 if (szOut) 2128 *szOut = 0; 2129 2130 if (_ILIsDesktop(pidl)) 2131 { 2132 /* desktop */ 2133 if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH)) 2134 { 2135 if (szOut) 2136 lstrcpynW(szOut, szTemp, uOutSize); 2137 2138 dwReturn = lstrlenW (szTemp); 2139 } 2140 } 2141 else if (( szSrcW = _ILGetTextPointerW(pidl) )) 2142 { 2143 /* unicode filesystem */ 2144 if (szOut) 2145 lstrcpynW(szOut, szSrcW, uOutSize); 2146 2147 dwReturn = lstrlenW(szSrcW); 2148 } 2149 else if (( szSrc = _ILGetTextPointer(pidl) )) 2150 { 2151 /* filesystem */ 2152 MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); 2153 2154 if (szOut) 2155 lstrcpynW(szOut, szTemp, uOutSize); 2156 2157 dwReturn = lstrlenW (szTemp); 2158 } 2159 else if (( riid = _ILGetGUIDPointer(pidl) )) 2160 { 2161 /* special folder */ 2162 if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) ) 2163 { 2164 if (szOut) 2165 lstrcpynW(szOut, szTemp, uOutSize); 2166 2167 dwReturn = lstrlenW (szTemp); 2168 } 2169 } 2170 else 2171 { 2172 ERR("-- no text\n"); 2173 } 2174 } 2175 2176 TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); 2177 return dwReturn; 2178 } 2179 2180 /************************************************************************** 2181 * 2182 * ### 4. getting pointers to parts of pidls ### 2183 * 2184 ************************************************************************** 2185 * _ILGetDataPointer() 2186 */ 2187 LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) 2188 { 2189 if(!_ILIsEmpty(pidl)) 2190 return (LPPIDLDATA)pidl->mkid.abID; 2191 return NULL; 2192 } 2193 2194 /************************************************************************** 2195 * _ILGetTextPointerW() 2196 * gets a pointer to the unicode long filename string stored in the pidl 2197 */ 2198 static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) 2199 { 2200 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2201 2202 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2203 2204 if (!pdata) 2205 return NULL; 2206 2207 switch (pdata->type) 2208 { 2209 case PT_GUID: 2210 case PT_SHELLEXT: 2211 case PT_YAGUID: 2212 return NULL; 2213 2214 case PT_DRIVE: 2215 case PT_DRIVE1: 2216 case PT_DRIVE2: 2217 case PT_DRIVE3: 2218 /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ 2219 return NULL; 2220 2221 case PT_FOLDER: 2222 case PT_FOLDER1: 2223 case PT_VALUE: 2224 case PT_IESPECIAL1: 2225 case PT_IESPECIAL2: 2226 /*return (LPSTR)&(pdata->u.file.szNames);*/ 2227 return NULL; 2228 2229 case PT_WORKGRP: 2230 case PT_COMP: 2231 case PT_NETWORK: 2232 case PT_NETPROVIDER: 2233 case PT_SHARE: 2234 /*return (LPSTR)&(pdata->u.network.szNames);*/ 2235 return NULL; 2236 2237 case PT_VALUEW: 2238 return (LPWSTR)pdata->u.file.szNames; 2239 2240 #ifdef __REACTOS__ /* r54423 */ 2241 case PT_CPLAPPLET: 2242 return pdata->u.cpanel.szName; 2243 #endif 2244 2245 } 2246 return NULL; 2247 } 2248 2249 2250 /************************************************************************** 2251 * _ILGetTextPointer() 2252 * gets a pointer to the long filename string stored in the pidl 2253 */ 2254 LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) 2255 { 2256 /* TRACE(pidl,"(pidl%p)\n", pidl);*/ 2257 2258 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2259 2260 if (!pdata) 2261 return NULL; 2262 2263 switch (pdata->type) 2264 { 2265 case PT_GUID: 2266 case PT_SHELLEXT: 2267 case PT_YAGUID: 2268 return NULL; 2269 2270 case PT_DRIVE: 2271 case PT_DRIVE1: 2272 case PT_DRIVE2: 2273 case PT_DRIVE3: 2274 return pdata->u.drive.szDriveName; 2275 2276 case PT_FOLDER: 2277 case PT_FOLDER1: 2278 case PT_VALUE: 2279 case PT_IESPECIAL1: 2280 case PT_IESPECIAL2: 2281 return pdata->u.file.szNames; 2282 2283 case PT_WORKGRP: 2284 case PT_COMP: 2285 case PT_NETWORK: 2286 case PT_NETPROVIDER: 2287 case PT_SHARE: 2288 return pdata->u.network.szNames; 2289 } 2290 return NULL; 2291 } 2292 2293 /************************************************************************** 2294 * _ILGetSTextPointer() 2295 * gets a pointer to the short filename string stored in the pidl 2296 */ 2297 static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) 2298 { 2299 /* TRACE(pidl,"(pidl%p)\n", pidl); */ 2300 2301 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2302 2303 if (!pdata) 2304 return NULL; 2305 2306 switch (pdata->type) 2307 { 2308 case PT_FOLDER: 2309 case PT_VALUE: 2310 case PT_IESPECIAL1: 2311 case PT_IESPECIAL2: 2312 return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; 2313 2314 case PT_WORKGRP: 2315 return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; 2316 } 2317 return NULL; 2318 } 2319 2320 /************************************************************************** 2321 * _ILGetGUIDPointer() 2322 * 2323 * returns reference to guid stored in some pidls 2324 */ 2325 IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) 2326 { 2327 LPPIDLDATA pdata =_ILGetDataPointer(pidl); 2328 2329 TRACE("%p\n", pidl); 2330 2331 if (!pdata) 2332 return NULL; 2333 2334 TRACE("pdata->type 0x%04x\n", pdata->type); 2335 switch (pdata->type) 2336 { 2337 case PT_SHELLEXT: 2338 case PT_GUID: 2339 case PT_YAGUID: 2340 return &(pdata->u.guid.guid); 2341 2342 default: 2343 TRACE("Unknown pidl type 0x%04x\n", pdata->type); 2344 break; 2345 } 2346 return NULL; 2347 } 2348 2349 /****************************************************************************** 2350 * _ILGetFileStructW [Internal] 2351 * 2352 * Get pointer the a SHITEMID's FileStructW field if present 2353 * 2354 * PARAMS 2355 * pidl [I] The SHITEMID 2356 * 2357 * RETURNS 2358 * Success: Pointer to pidl's FileStructW field. 2359 * Failure: NULL 2360 */ 2361 FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { 2362 FileStructW *pFileStructW; 2363 WORD cbOffset; 2364 2365 if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) 2366 return NULL; 2367 2368 cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); 2369 pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); 2370 2371 /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP 2372 * style with a FileStructW member. If we switch all our shellfolder-implementations to 2373 * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ 2374 if ((cbOffset & 0x1) || /* FileStructW member is word aligned in the pidl */ 2375 /* FileStructW is positioned after FileStruct */ 2376 cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || 2377 /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ 2378 cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || 2379 pidl->mkid.cb != cbOffset + pFileStructW->cbLen) 2380 { 2381 WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); 2382 return NULL; 2383 } 2384 2385 return pFileStructW; 2386 } 2387 2388 /************************************************************************* 2389 * _ILGetFileDateTime 2390 * 2391 * Given the ItemIdList, get the FileTime 2392 * 2393 * PARAMS 2394 * pidl [I] The ItemIDList 2395 * pFt [I] the resulted FILETIME of the file 2396 * 2397 * RETURNS 2398 * True if Successful 2399 * 2400 * NOTES 2401 * 2402 */ 2403 BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) 2404 { 2405 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2406 2407 if (!pdata) 2408 return FALSE; 2409 2410 switch (pdata->type) 2411 { 2412 case PT_FOLDER: 2413 case PT_VALUE: 2414 DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); 2415 break; 2416 default: 2417 return FALSE; 2418 } 2419 return TRUE; 2420 } 2421 2422 BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2423 { 2424 FILETIME ft,lft; 2425 SYSTEMTIME time; 2426 BOOL ret; 2427 2428 if (_ILGetFileDateTime( pidl, &ft )) 2429 { 2430 FileTimeToLocalFileTime(&ft, &lft); 2431 FileTimeToSystemTime (&lft, &time); 2432 2433 ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize); 2434 if (ret) 2435 { 2436 /* Append space + time without seconds */ 2437 pOut[ret-1] = ' '; 2438 GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); 2439 } 2440 } 2441 else 2442 { 2443 pOut[0] = '\0'; 2444 ret = FALSE; 2445 } 2446 return ret; 2447 } 2448 2449 /************************************************************************* 2450 * _ILGetFileSize 2451 * 2452 * Given the ItemIdList, get the FileSize 2453 * 2454 * PARAMS 2455 * pidl [I] The ItemIDList 2456 * pOut [I] The buffer to save the result 2457 * uOutsize [I] The size of the buffer 2458 * 2459 * RETURNS 2460 * The FileSize 2461 * 2462 * NOTES 2463 * pOut can be null when no string is needed 2464 * 2465 */ 2466 DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2467 { 2468 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 2469 DWORD dwSize; 2470 2471 if (!pdata) 2472 return 0; 2473 2474 switch (pdata->type) 2475 { 2476 case PT_VALUE: 2477 dwSize = pdata->u.file.dwFileSize; 2478 if (pOut) 2479 StrFormatKBSizeA(dwSize, pOut, uOutSize); 2480 return dwSize; 2481 } 2482 if (pOut) 2483 *pOut = 0x00; 2484 return 0; 2485 } 2486 2487 BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2488 { 2489 char szTemp[MAX_PATH]; 2490 const char * pPoint; 2491 LPCITEMIDLIST pidlTemp=pidl; 2492 2493 TRACE("pidl=%p\n",pidl); 2494 2495 if (!pidl) 2496 return FALSE; 2497 2498 pidlTemp = ILFindLastID(pidl); 2499 2500 if (!_ILIsValue(pidlTemp)) 2501 return FALSE; 2502 if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) 2503 return FALSE; 2504 2505 pPoint = PathFindExtensionA(szTemp); 2506 2507 if (!*pPoint) 2508 return FALSE; 2509 2510 pPoint++; 2511 lstrcpynA(pOut, pPoint, uOutSize); 2512 TRACE("%s\n",pOut); 2513 2514 return TRUE; 2515 } 2516 2517 /************************************************************************* 2518 * _ILGetFileType 2519 * 2520 * Given the ItemIdList, get the file type description 2521 * 2522 * PARAMS 2523 * pidl [I] The ItemIDList (simple) 2524 * pOut [I] The buffer to save the result 2525 * uOutsize [I] The size of the buffer 2526 * 2527 * RETURNS 2528 * nothing 2529 * 2530 * NOTES 2531 * This function copies as much as possible into the buffer. 2532 */ 2533 void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2534 { 2535 #ifdef __REACTOS__ /* r32966 */ 2536 char sType[64]; 2537 #endif 2538 2539 if(_ILIsValue(pidl)) 2540 { 2541 char sTemp[64]; 2542 2543 if(uOutSize > 0) 2544 pOut[0] = 0; 2545 #ifdef __REACTOS__ /* r32966 */ 2546 if (_ILGetExtension (pidl, sType, 64)) 2547 { 2548 if (HCR_MapTypeToValueA(sType, sTemp, 64, TRUE)) 2549 { 2550 /* retrieve description */ 2551 if(HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )) 2552 return; 2553 } 2554 /* display Ext-file as description */ 2555 _strupr(sType); 2556 /* load localized file string */ 2557 sTemp[0] = '\0'; 2558 if(LoadStringA(shell32_hInstance, IDS_ANY_FILE, sTemp, 64)) 2559 { 2560 sTemp[63] = '\0'; 2561 StringCchPrintfA(pOut, uOutSize, sTemp, sType); 2562 } 2563 } 2564 #else 2565 if (_ILGetExtension (pidl, sTemp, 64)) 2566 { 2567 if (!( HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE) 2568 && HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE ))) 2569 { 2570 lstrcpynA (pOut, sTemp, uOutSize - 6); 2571 strcat (pOut, "-file"); 2572 } 2573 } 2574 #endif 2575 } 2576 else 2577 #ifdef __REACTOS__ /* r32966 */ 2578 { 2579 pOut[0] = '\0'; 2580 LoadStringA(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize); 2581 /* make sure its null terminated */ 2582 pOut[uOutSize-1] = '\0'; 2583 } 2584 #else 2585 lstrcpynA(pOut, "Folder", uOutSize); 2586 #endif 2587 } 2588 2589 /************************************************************************* 2590 * _ILGetFileAttributes 2591 * 2592 * Given the ItemIdList, get the Attrib string format 2593 * 2594 * PARAMS 2595 * pidl [I] The ItemIDList 2596 * pOut [I] The buffer to save the result 2597 * uOutsize [I] The size of the Buffer 2598 * 2599 * RETURNS 2600 * Attributes 2601 * 2602 * FIXME 2603 * return value 0 in case of error is a valid return value 2604 * 2605 */ 2606 DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) 2607 { 2608 LPPIDLDATA pData = _ILGetDataPointer(pidl); 2609 WORD wAttrib = 0; 2610 int i; 2611 2612 if (!pData) 2613 return 0; 2614 2615 switch(pData->type) 2616 { 2617 case PT_FOLDER: 2618 case PT_VALUE: 2619 wAttrib = pData->u.file.uFileAttribs; 2620 break; 2621 } 2622 2623 if(uOutSize >= 6) 2624 { 2625 i=0; 2626 if(wAttrib & FILE_ATTRIBUTE_READONLY) 2627 pOut[i++] = 'R'; 2628 if(wAttrib & FILE_ATTRIBUTE_HIDDEN) 2629 pOut[i++] = 'H'; 2630 if(wAttrib & FILE_ATTRIBUTE_SYSTEM) 2631 pOut[i++] = 'S'; 2632 if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) 2633 pOut[i++] = 'A'; 2634 if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) 2635 pOut[i++] = 'C'; 2636 pOut[i] = 0x00; 2637 } 2638 return wAttrib; 2639 } 2640 2641 /************************************************************************* 2642 * ILFreeaPidl 2643 * 2644 * frees an aPidl struct 2645 */ 2646 void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) 2647 { 2648 UINT i; 2649 2650 if (apidl) 2651 { 2652 for (i = 0; i < cidl; i++) 2653 SHFree(apidl[i]); 2654 SHFree(apidl); 2655 } 2656 } 2657 2658 /************************************************************************* 2659 * ILCopyaPidl 2660 * 2661 * copies an aPidl struct 2662 */ 2663 PITEMID_CHILD* _ILCopyaPidl(PCUITEMID_CHILD_ARRAY apidlsrc, UINT cidl) 2664 { 2665 UINT i; 2666 PITEMID_CHILD *apidldest; 2667 2668 if (!apidlsrc) 2669 return NULL; 2670 2671 apidldest = SHAlloc(cidl * sizeof(PITEMID_CHILD)); 2672 2673 for (i = 0; i < cidl; i++) 2674 apidldest[i] = ILClone(apidlsrc[i]); 2675 2676 return apidldest; 2677 } 2678 2679 /************************************************************************* 2680 * _ILCopyCidaToaPidl 2681 * 2682 * creates aPidl from CIDA 2683 */ 2684 LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) 2685 { 2686 UINT i; 2687 LPITEMIDLIST *dst; 2688 2689 dst = SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); 2690 if (!dst) 2691 return NULL; 2692 2693 if (pidl) 2694 *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); 2695 2696 for (i = 0; i < cida->cidl; i++) 2697 dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); 2698 2699 return dst; 2700 } 2701