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