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