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