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