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 #ifndef __REACTOS__ /* We don't know all pidl formats, must allow loading unknown */ 337 SHFree(*ppPidl); 338 *ppPidl = NULL; 339 #endif 340 } 341 342 IStream_Release (pStream); 343 TRACE("done\n"); 344 return ret; 345 } 346 347 /************************************************************************* 348 * ILSaveToStream (SHELL32.27) 349 * 350 * NOTES 351 * the first two bytes are the len, the pidl is following then 352 */ 353 HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl) 354 { 355 WORD wLen = 0; 356 HRESULT ret = E_FAIL; 357 358 TRACE_(shell)("%p %p\n", pStream, pPidl); 359 360 IStream_AddRef (pStream); 361 362 wLen = ILGetSize(pPidl); 363 364 if (SUCCEEDED(IStream_Write(pStream, &wLen, 2, NULL))) 365 { 366 if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL))) 367 ret = S_OK; 368 } 369 IStream_Release (pStream); 370 371 return ret; 372 } 373 374 /************************************************************************* 375 * SHILCreateFromPath [SHELL32.28] 376 * 377 * Create an ItemIDList from a path 378 * 379 * PARAMS 380 * path [I] 381 * ppidl [O] 382 * attributes [I/O] requested attributes on call and actual attributes when 383 * the function returns 384 * 385 * RETURNS 386 * NO_ERROR if successful, or an OLE errer code otherwise 387 * 388 * NOTES 389 * Wrapper for IShellFolder_ParseDisplayName(). 390 */ 391 HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) 392 { 393 WCHAR lpszDisplayName[MAX_PATH]; 394 395 TRACE_(shell)("%s %p 0x%08x\n", path, ppidl, attributes ? *attributes : 0); 396 397 if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH)) 398 lpszDisplayName[MAX_PATH-1] = 0; 399 400 return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes); 401 } 402 403 HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) 404 { 405 LPSHELLFOLDER sf; 406 DWORD pchEaten; 407 HRESULT ret = E_FAIL; 408 409 TRACE_(shell)("%s %p 0x%08x\n", debugstr_w(path), ppidl, attributes ? *attributes : 0); 410 411 if (SUCCEEDED (SHGetDesktopFolder(&sf))) 412 { 413 ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes); 414 IShellFolder_Release(sf); 415 } 416 return ret; 417 } 418 419 HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes) 420 { 421 if ( SHELL_OsIsUnicode()) 422 return SHILCreateFromPathW (path, ppidl, attributes); 423 return SHILCreateFromPathA (path, ppidl, attributes); 424 } 425 426 /************************************************************************* 427 * SHCloneSpecialIDList [SHELL32.89] 428 * 429 * Create an ItemIDList to one of the special folders. 430 431 * PARAMS 432 * hwndOwner [in] 433 * nFolder [in] CSIDL_xxxxx 434 * fCreate [in] Create folder if it does not exist 435 * 436 * RETURNS 437 * Success: The newly created pidl 438 * Failure: NULL, if inputs are invalid. 439 * 440 * NOTES 441 * exported by ordinal. 442 * Caller is responsible for deallocating the returned ItemIDList with the 443 * shells IMalloc interface, aka ILFree. 444 */ 445 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate) 446 { 447 LPITEMIDLIST ppidl; 448 TRACE_(shell)("(hwnd=%p,csidl=0x%x,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F"); 449 450 if (fCreate) 451 nFolder |= CSIDL_FLAG_CREATE; 452 453 SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl); 454 return ppidl; 455 } 456 457 /************************************************************************* 458 * ILGlobalClone [SHELL32.20] 459 * 460 * Clones an ItemIDList using Alloc. 461 * 462 * PARAMS 463 * pidl [I] ItemIDList to clone 464 * 465 * RETURNS 466 * Newly allocated ItemIDList. 467 * 468 * NOTES 469 * exported by ordinal. 470 */ 471 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl) 472 { 473 DWORD len; 474 LPITEMIDLIST newpidl; 475 476 if (!pidl) 477 return NULL; 478 479 len = ILGetSize(pidl); 480 newpidl = Alloc(len); 481 if (newpidl) 482 memcpy(newpidl,pidl,len); 483 484 TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); 485 pdump(pidl); 486 487 return newpidl; 488 } 489 490 #ifdef __REACTOS__ 491 static inline LPITEMIDLIST _ILUnsafeNext(LPCITEMIDLIST pidl) 492 { 493 return (LPITEMIDLIST)(((BYTE*)pidl) + pidl->mkid.cb); 494 } 495 496 UINT _ILGetDepth(LPCITEMIDLIST pidl) 497 { 498 for (UINT i = 0;; ++i) 499 { 500 if (!pidl || !pidl->mkid.cb) 501 return i; 502 pidl = _ILUnsafeNext(pidl); 503 } 504 } 505 506 static BOOL _ILMemCmpEqualIDList(LPCITEMIDLIST p1, LPCITEMIDLIST p2) 507 { 508 for (;; p1 = _ILUnsafeNext(p1), p2 = _ILUnsafeNext(p2)) 509 { 510 DWORD cb1 = p1 ? p1->mkid.cb : 0x80000000; /* Empty != NULL */ 511 DWORD cb2 = p2 ? p2->mkid.cb : 0x80000000; 512 if (cb1 != cb2) 513 return FALSE; 514 if (LOWORD(cb1) == 0) 515 return cb1 == cb2; 516 if (memcmp(p1, p2, cb1)) 517 return FALSE; 518 } 519 } 520 #else /* __REACTOS__ */ 521 BOOL _ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1, LPCITEMIDLIST pidltemp2) 522 { 523 LPPIDLDATA pdata1 = _ILGetDataPointer(pidltemp1); 524 LPPIDLDATA pdata2 = _ILGetDataPointer(pidltemp2); 525 526 IID *iid1 = _ILGetGUIDPointer(pidltemp1); 527 IID *iid2 = _ILGetGUIDPointer(pidltemp2); 528 529 FileStructW* pDataW1 = _ILGetFileStructW(pidltemp1); 530 FileStructW* pDataW2 = _ILGetFileStructW(pidltemp2); 531 532 if (_ILIsDesktop(pidltemp1) && _ILIsDesktop(pidltemp2)) 533 { 534 return TRUE; 535 } 536 else if (_ILIsDesktop(pidltemp1) || _ILIsDesktop(pidltemp2)) 537 { 538 return FALSE; 539 } 540 else if (iid1 || iid2) 541 { 542 if (!iid1 || !iid2 || memcmp(iid1, iid2, sizeof(GUID))) 543 return FALSE; 544 } 545 else if (pDataW1 || pDataW2) 546 { 547 if (!pDataW1 || !pDataW2 || wcsicmp(pDataW1->wszName, pDataW2->wszName)) 548 return FALSE; 549 } 550 else if (_ILIsFolder(pidltemp1) || _ILIsFolder(pidltemp2)) 551 { 552 if (!_ILIsFolder(pidltemp1) || !_ILIsFolder(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames)) 553 return FALSE; 554 } 555 else if (_ILIsValue(pidltemp1) || _ILIsValue(pidltemp2)) 556 { 557 if (!_ILIsValue(pidltemp1) || !_ILIsValue(pidltemp2) || strcmp(pdata1->u.file.szNames, pdata2->u.file.szNames)) 558 return FALSE; 559 } 560 else if (_ILIsDrive(pidltemp1) || _ILIsDrive(pidltemp2)) 561 { 562 if (!_ILIsDrive(pidltemp1) || !_ILIsDrive(pidltemp2) || pdata1->u.drive.szDriveName[0] != pdata2->u.drive.szDriveName[0]) 563 return FALSE; 564 } 565 else 566 { 567 if ((pidltemp1->mkid.cb != pidltemp2->mkid.cb) || 568 !RtlEqualMemory((BYTE*)&pidltemp1->mkid, (BYTE*)&pidltemp2->mkid, pidltemp1->mkid.cb)) 569 { 570 return FALSE; 571 } 572 } 573 574 return TRUE; 575 } 576 #endif /* __REACTOS__ */ 577 578 /************************************************************************* 579 * ILIsEqual [SHELL32.21] 580 * 581 */ 582 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 583 { 584 LPCITEMIDLIST pidltemp1 = pidl1; 585 LPCITEMIDLIST pidltemp2 = pidl2; 586 587 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); 588 589 #ifdef __REACTOS__ 590 IShellFolder *psfDesktop; 591 UINT depth1; 592 593 if (pidl1 == pidl2 || _ILMemCmpEqualIDList(pidltemp1, pidltemp2)) 594 return TRUE; 595 596 depth1 = _ILGetDepth(pidl1); 597 if (depth1 && depth1 == _ILGetDepth(pidl2) && SUCCEEDED(SHGetDesktopFolder(&psfDesktop))) 598 { 599 HRESULT hr = IShellFolder_CompareIDs(psfDesktop, SHCIDS_CANONICALONLY, pidl1, pidl2); 600 IShellFolder_Release(psfDesktop); 601 return hr == 0; 602 } 603 #else /* __REACTOS__ */ 604 /* 605 * Explorer reads from registry directly (StreamMRU), 606 * so we can only check here 607 */ 608 if (!pcheck(pidl1) || !pcheck (pidl2)) 609 #ifdef __REACTOS__ 610 { 611 /* We don't understand the PIDL content but that does not mean it's invalid */ 612 } 613 #else 614 return FALSE; 615 #endif 616 617 pdump (pidl1); 618 pdump (pidl2); 619 620 if (!pidl1 || !pidl2) 621 return FALSE; 622 623 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) 624 { 625 if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2)) 626 return FALSE; 627 628 pidltemp1 = ILGetNext(pidltemp1); 629 pidltemp2 = ILGetNext(pidltemp2); 630 } 631 632 if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb) 633 return TRUE; 634 #endif /* __REACTOS__ */ 635 return FALSE; 636 } 637 638 LPCITEMIDLIST _ILIsParentEx(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate) 639 { 640 LPCITEMIDLIST pParentRoot = pidlParent, pChildRoot = pidlChild, pResult = NULL; 641 LPITEMIDLIST pidl; 642 SIZE_T cb = 0; 643 644 if (!pidlParent || !pidlChild) 645 return pResult; 646 647 while (pidlParent->mkid.cb) 648 { 649 cb += pidlChild->mkid.cb; 650 if (!pidlChild->mkid.cb) 651 { 652 if (pidlParent->mkid.cb) 653 return pResult; /* The child is shorter than the parent */ 654 else 655 break; 656 } 657 pidlChild = _ILUnsafeNext(pidlChild); 658 pidlParent = _ILUnsafeNext(pidlParent); 659 } 660 661 if (bImmediate && (!pidlChild->mkid.cb || _ILUnsafeNext(pidlChild)->mkid.cb)) 662 return pResult; /* Same as parent or a deeper grandchild */ 663 664 if ((pidl = SHAlloc(cb + sizeof(WORD))) != NULL) 665 { 666 CopyMemory(pidl, pChildRoot, cb); 667 ZeroMemory((BYTE*)pidl + cb, sizeof(WORD)); 668 if (ILIsEqual(pParentRoot, pidl)) 669 pResult = pidlChild; 670 ILFree(pidl); 671 } 672 return pResult; 673 } 674 675 /************************************************************************* 676 * ILIsParent [SHELL32.23] 677 * 678 * Verifies that pidlParent is indeed the (immediate) parent of pidlChild. 679 * 680 * PARAMS 681 * pidlParent [I] 682 * pidlChild [I] 683 * bImmediate [I] only return true if the parent is the direct parent 684 * of the child 685 * 686 * RETURNS 687 * True if the parent ItemIDlist is a complete part of the child ItemIdList, 688 * False otherwise. 689 * 690 * NOTES 691 * parent = a/b, child = a/b/c -> true, c is in folder a/b 692 * child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b 693 * child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b 694 * child = a/b -> false if bImmediate is true 695 * child = a/b -> true if bImmediate is false 696 */ 697 BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate) 698 { 699 LPCITEMIDLIST pParent = pidlParent; 700 LPCITEMIDLIST pChild = pidlChild; 701 702 TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate); 703 704 #ifdef __REACTOS__ 705 return _ILIsParentEx(pParent, pChild, bImmediate) != NULL; 706 #else /* __REACTOS__ */ 707 if (!pParent || !pChild) 708 return FALSE; 709 710 while (pParent->mkid.cb && pChild->mkid.cb) 711 { 712 if (!_ILHACKCompareSimpleIds(pParent, pChild)) 713 return FALSE; 714 715 pParent = ILGetNext(pParent); 716 pChild = ILGetNext(pChild); 717 } 718 719 /* child has shorter name than parent */ 720 if (pParent->mkid.cb) 721 return FALSE; 722 723 /* not immediate descent */ 724 if ((!pChild->mkid.cb || ILGetNext(pChild)->mkid.cb) && bImmediate) 725 return FALSE; 726 727 return TRUE; 728 #endif /* __REACTOS__ */ 729 } 730 731 /************************************************************************* 732 * ILFindChild [SHELL32.24] 733 * 734 * Compares elements from pidl1 and pidl2. 735 * 736 * PARAMS 737 * pidl1 [I] 738 * pidl2 [I] 739 * 740 * RETURNS 741 * pidl1 is desktop pidl2 742 * pidl1 shorter pidl2 pointer to first different element of pidl2 743 * if there was at least one equal element 744 * pidl2 shorter pidl1 0 745 * pidl2 equal pidl1 pointer to last 0x00-element of pidl2 746 * 747 * NOTES 748 * exported by ordinal. 749 */ 750 PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2) 751 { 752 #ifdef __REACTOS__ 753 TRACE("pidl1=%p pidl2=%p\n", pidl1, pidl2); 754 755 if (_ILIsDesktop(pidl1)) 756 return (PUIDLIST_RELATIVE)pidl2; 757 return (PUIDLIST_RELATIVE)_ILIsParentEx(pidl1, pidl2, FALSE); 758 #else /* __REACTOS__ */ 759 LPCITEMIDLIST pidltemp1 = pidl1; 760 LPCITEMIDLIST pidltemp2 = pidl2; 761 LPCITEMIDLIST ret=NULL; 762 763 TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); 764 765 /* explorer reads from registry directly (StreamMRU), 766 so we can only check here */ 767 if ((!pcheck (pidl1)) || (!pcheck (pidl2))) 768 return FALSE; 769 770 pdump (pidl1); 771 pdump (pidl2); 772 773 if (_ILIsDesktop(pidl1)) 774 { 775 ret = pidl2; 776 } 777 else 778 { 779 while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) 780 { 781 if (!_ILHACKCompareSimpleIds(pidltemp1, pidltemp2)) 782 return FALSE; 783 784 pidltemp1 = ILGetNext(pidltemp1); 785 pidltemp2 = ILGetNext(pidltemp2); 786 ret = pidltemp2; 787 } 788 789 if (pidltemp1->mkid.cb) 790 ret = NULL; /* elements of pidl1 left*/ 791 } 792 TRACE_(shell)("--- %p\n", ret); 793 return (PUIDLIST_RELATIVE)ret; /* pidl 1 is shorter */ 794 #endif /* __REACTOS__ */ 795 } 796 797 /************************************************************************* 798 * ILCombine [SHELL32.25] 799 * 800 * Concatenates two complex ItemIDLists. 801 * 802 * PARAMS 803 * pidl1 [I] first complex ItemIDLists 804 * pidl2 [I] complex ItemIDLists to append 805 * 806 * RETURNS 807 * if both pidl's == NULL NULL 808 * if pidl1 == NULL cloned pidl2 809 * if pidl2 == NULL cloned pidl1 810 * otherwise new pidl with pidl2 appended to pidl1 811 * 812 * NOTES 813 * exported by ordinal. 814 * Does not destroy the passed in ItemIDLists! 815 */ 816 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 817 { 818 DWORD len1,len2; 819 LPITEMIDLIST pidlNew; 820 821 TRACE("pidl=%p pidl=%p\n",pidl1,pidl2); 822 823 if (!pidl1 && !pidl2) return NULL; 824 825 pdump (pidl1); 826 pdump (pidl2); 827 828 if (!pidl1) 829 { 830 pidlNew = ILClone(pidl2); 831 return pidlNew; 832 } 833 834 if (!pidl2) 835 { 836 pidlNew = ILClone(pidl1); 837 return pidlNew; 838 } 839 840 len1 = ILGetSize(pidl1)-2; 841 len2 = ILGetSize(pidl2); 842 pidlNew = SHAlloc(len1+len2); 843 844 if (pidlNew) 845 { 846 memcpy(pidlNew,pidl1,len1); 847 memcpy(((BYTE *)pidlNew)+len1,pidl2,len2); 848 } 849 850 /* TRACE(pidl,"--new pidl=%p\n",pidlNew);*/ 851 return pidlNew; 852 } 853 854 #ifndef __REACTOS__ /* See ..\utils.cpp */ 855 /************************************************************************* 856 * SHGetRealIDL [SHELL32.98] 857 * 858 * NOTES 859 */ 860 HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal) 861 { 862 IDataObject* pDataObj; 863 HRESULT hr; 864 865 hr = IShellFolder_GetUIObjectOf(lpsf, 0, 1, &pidlSimple, 866 &IID_IDataObject, 0, (LPVOID*)&pDataObj); 867 if (SUCCEEDED(hr)) 868 { 869 STGMEDIUM medium; 870 FORMATETC fmt; 871 872 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); 873 fmt.ptd = NULL; 874 fmt.dwAspect = DVASPECT_CONTENT; 875 fmt.lindex = -1; 876 fmt.tymed = TYMED_HGLOBAL; 877 878 hr = IDataObject_GetData(pDataObj, &fmt, &medium); 879 880 IDataObject_Release(pDataObj); 881 882 if (SUCCEEDED(hr)) 883 { 884 /*assert(pida->cidl==1);*/ 885 LPIDA pida = GlobalLock(medium.u.hGlobal); 886 887 LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); 888 LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); 889 890 *pidlReal = ILCombine(pidl_folder, pidl_child); 891 892 if (!*pidlReal) 893 hr = E_OUTOFMEMORY; 894 895 GlobalUnlock(medium.u.hGlobal); 896 GlobalFree(medium.u.hGlobal); 897 } 898 } 899 900 return hr; 901 } 902 #endif 903 904 /************************************************************************* 905 * SHLogILFromFSIL [SHELL32.95] 906 * 907 * NOTES 908 * pild = CSIDL_DESKTOP ret = 0 909 * pild = CSIDL_DRIVES ret = 0 910 */ 911 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl) 912 { 913 FIXME("(pidl=%p)\n",pidl); 914 915 pdump(pidl); 916 917 return 0; 918 } 919 920 /************************************************************************* 921 * ILGetSize [SHELL32.152] 922 * 923 * Gets the byte size of an ItemIDList including zero terminator 924 * 925 * PARAMS 926 * pidl [I] ItemIDList 927 * 928 * RETURNS 929 * size of pidl in bytes 930 * 931 * NOTES 932 * exported by ordinal 933 */ 934 UINT WINAPI ILGetSize(LPCITEMIDLIST pidl) 935 { 936 LPCSHITEMID si; 937 UINT len=0; 938 939 if (pidl) 940 { 941 si = &(pidl->mkid); 942 943 while (si->cb) 944 { 945 len += si->cb; 946 si = (LPCSHITEMID)(((const BYTE*)si)+si->cb); 947 } 948 len += 2; 949 } 950 TRACE("pidl=%p size=%u\n",pidl, len); 951 return len; 952 } 953 954 /************************************************************************* 955 * ILGetNext [SHELL32.153] 956 * 957 * Gets the next ItemID of an ItemIDList 958 * 959 * PARAMS 960 * pidl [I] ItemIDList 961 * 962 * RETURNS 963 * null -> null 964 * desktop -> null 965 * simple pidl -> pointer to 0x0000 element 966 * 967 * NOTES 968 * exported by ordinal. 969 */ 970 LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl) 971 { 972 WORD len; 973 974 TRACE("%p\n", pidl); 975 976 if (pidl) 977 { 978 len = pidl->mkid.cb; 979 if (len) 980 { 981 pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len); 982 TRACE("-- %p\n", pidl); 983 return (LPITEMIDLIST)pidl; 984 } 985 } 986 return NULL; 987 } 988 989 /************************************************************************* 990 * ILAppendID [SHELL32.154] 991 * 992 * Adds the single ItemID item to the ItemIDList indicated by pidl. 993 * If bEnd is FALSE, inserts the item in the front of the list, 994 * otherwise it adds the item to the end. (???) 995 * 996 * PARAMS 997 * pidl [I] ItemIDList to extend 998 * item [I] ItemID to prepend/append 999 * bEnd [I] Indicates if the item should be appended 1000 * 1001 * NOTES 1002 * Destroys the passed in idlist! (???) 1003 */ 1004 LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID item, BOOL bEnd) 1005 { 1006 LPITEMIDLIST idlRet; 1007 LPCITEMIDLIST itemid = (LPCITEMIDLIST)item; 1008 1009 WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd); 1010 1011 pdump (pidl); 1012 pdump (itemid); 1013 1014 if (_ILIsDesktop(pidl)) 1015 { 1016 idlRet = ILClone(itemid); 1017 SHFree (pidl); 1018 return idlRet; 1019 } 1020 1021 if (bEnd) 1022 idlRet = ILCombine(pidl, itemid); 1023 else 1024 idlRet = ILCombine(itemid, pidl); 1025 1026 SHFree(pidl); 1027 return idlRet; 1028 } 1029 1030 /************************************************************************* 1031 * ILFree [SHELL32.155] 1032 * 1033 * Frees memory (if not NULL) allocated by SHMalloc allocator 1034 * 1035 * PARAMS 1036 * pidl [I] 1037 * 1038 * RETURNS 1039 * Nothing 1040 * 1041 * NOTES 1042 * exported by ordinal 1043 */ 1044 void WINAPI ILFree(LPITEMIDLIST pidl) 1045 { 1046 TRACE("(pidl=%p)\n",pidl); 1047 SHFree(pidl); 1048 } 1049 1050 /************************************************************************* 1051 * ILGlobalFree [SHELL32.156] 1052 * 1053 * Frees memory (if not NULL) allocated by Alloc allocator 1054 * 1055 * PARAMS 1056 * pidl [I] 1057 * 1058 * RETURNS 1059 * Nothing 1060 * 1061 * NOTES 1062 * exported by ordinal. 1063 */ 1064 void WINAPI ILGlobalFree( LPITEMIDLIST pidl) 1065 { 1066 TRACE("%p\n", pidl); 1067 1068 Free(pidl); 1069 } 1070 1071 /************************************************************************* 1072 * ILCreateFromPathA [SHELL32.189] 1073 * 1074 * Creates a complex ItemIDList from a path and returns it. 1075 * 1076 * PARAMS 1077 * path [I] 1078 * 1079 * RETURNS 1080 * the newly created complex ItemIDList or NULL if failed 1081 * 1082 * NOTES 1083 * exported by ordinal. 1084 */ 1085 LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) 1086 { 1087 LPITEMIDLIST pidlnew = NULL; 1088 1089 TRACE_(shell)("%s\n", debugstr_a(path)); 1090 1091 if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL))) 1092 return pidlnew; 1093 return NULL; 1094 } 1095 1096 /************************************************************************* 1097 * ILCreateFromPathW [SHELL32.190] 1098 * 1099 * See ILCreateFromPathA. 1100 */ 1101 LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) 1102 { 1103 LPITEMIDLIST pidlnew = NULL; 1104 1105 TRACE_(shell)("%s\n", debugstr_w(path)); 1106 1107 if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL))) 1108 return pidlnew; 1109 return NULL; 1110 } 1111 1112 /************************************************************************* 1113 * ILCreateFromPath [SHELL32.157] 1114 */ 1115 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) 1116 { 1117 if ( SHELL_OsIsUnicode()) 1118 return ILCreateFromPathW (path); 1119 return ILCreateFromPathA (path); 1120 } 1121 1122 /************************************************************************* 1123 * _ILParsePathW [internal] 1124 * 1125 * Creates an ItemIDList from a path and returns it. 1126 * 1127 * PARAMS 1128 * path [I] path to parse and convert into an ItemIDList 1129 * lpFindFile [I] pointer to buffer to initialize the FileSystem 1130 * Bind Data object with 1131 * bBindCtx [I] indicates to create a BindContext and assign a 1132 * FileSystem Bind Data object 1133 * ppidl [O] the newly create ItemIDList 1134 * prgfInOut [I/O] requested attributes on input and actual 1135 * attributes on return 1136 * 1137 * RETURNS 1138 * NO_ERROR on success or an OLE error code 1139 * 1140 * NOTES 1141 * If either lpFindFile is non-NULL or bBindCtx is TRUE, this function 1142 * creates a BindContext object and assigns a FileSystem Bind Data object 1143 * to it, passing the BindContext to IShellFolder_ParseDisplayName. Each 1144 * IShellFolder uses that FileSystem Bind Data object of the BindContext 1145 * to pass data about the current path element to the next object. This 1146 * is used to avoid having to verify the current path element on disk, so 1147 * that creating an ItemIDList from a nonexistent path still can work. 1148 */ 1149 static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile, 1150 BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut) 1151 { 1152 LPSHELLFOLDER pSF = NULL; 1153 LPBC pBC = NULL; 1154 HRESULT ret; 1155 1156 TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx, 1157 ppidl, ppidl ? *ppidl : NULL, 1158 prgfInOut, prgfInOut ? *prgfInOut : 0); 1159 1160 ret = SHGetDesktopFolder(&pSF); 1161 if (FAILED(ret)) 1162 return ret; 1163 1164 if (lpFindFile || bBindCtx) 1165 ret = IFileSystemBindData_Constructor(lpFindFile, &pBC); 1166 1167 if (SUCCEEDED(ret)) 1168 { 1169 ret = IShellFolder_ParseDisplayName(pSF, 0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut); 1170 } 1171 1172 if (pBC) 1173 { 1174 IBindCtx_Release(pBC); 1175 pBC = NULL; 1176 } 1177 1178 IShellFolder_Release(pSF); 1179 1180 if (FAILED(ret) && ppidl) 1181 *ppidl = NULL; 1182 1183 TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0); 1184 1185 return ret; 1186 } 1187 1188 LPITEMIDLIST SHELL32_CreateSimpleIDListFromPath(LPCWSTR pszPath, DWORD dwAttributes) 1189 { 1190 WIN32_FIND_DATAW data = { dwAttributes }; 1191 LPITEMIDLIST pidl = NULL; 1192 _ILParsePathW(pszPath, &data, TRUE, &pidl, NULL); 1193 return pidl; 1194 } 1195 1196 /************************************************************************* 1197 * SHSimpleIDListFromPath [SHELL32.162] 1198 * 1199 * Creates a simple ItemIDList from a path and returns it. This function 1200 * does not fail on nonexistent paths. 1201 * 1202 * PARAMS 1203 * path [I] path to parse and convert into an ItemIDList 1204 * 1205 * RETURNS 1206 * the newly created simple ItemIDList 1207 * 1208 * NOTES 1209 * Simple in the name does not mean a relative ItemIDList but rather a 1210 * fully qualified list, where only the file name is filled in and the 1211 * directory flag for those ItemID elements this is known about, eg. 1212 * it is not the last element in the ItemIDList or the actual directory 1213 * exists on disk. 1214 * exported by ordinal. 1215 */ 1216 LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) 1217 { 1218 LPITEMIDLIST pidl = NULL; 1219 LPWSTR wPath = NULL; 1220 int len; 1221 1222 TRACE("%s\n", debugstr_a(lpszPath)); 1223 1224 if (lpszPath) 1225 { 1226 len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0); 1227 wPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1228 MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); 1229 } 1230 1231 _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); 1232 1233 HeapFree(GetProcessHeap(), 0, wPath); 1234 TRACE("%s %p\n", debugstr_a(lpszPath), pidl); 1235 return pidl; 1236 } 1237 1238 LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) 1239 { 1240 LPITEMIDLIST pidl = NULL; 1241 1242 TRACE("%s\n", debugstr_w(lpszPath)); 1243 1244 _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); 1245 1246 TRACE("%s %p\n", debugstr_w(lpszPath), pidl); 1247 return pidl; 1248 } 1249 1250 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) 1251 { 1252 if ( SHELL_OsIsUnicode()) 1253 return SHSimpleIDListFromPathW (lpszPath); 1254 return SHSimpleIDListFromPathA (lpszPath); 1255 } 1256 1257 /************************************************************************* 1258 * SHGetDataFromIDListA [SHELL32.247] 1259 * 1260 * NOTES 1261 * the pidl can be a simple one. since we can't get the path out of the pidl 1262 * we have to take all data from the pidl 1263 */ 1264 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1265 int nFormat, LPVOID dest, int len) 1266 { 1267 LPSTR filename, shortname; 1268 WIN32_FIND_DATAA * pfd; 1269 1270 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1271 1272 pdump(pidl); 1273 if (!psf || !dest) 1274 return E_INVALIDARG; 1275 1276 switch (nFormat) 1277 { 1278 case SHGDFIL_FINDDATA: 1279 pfd = dest; 1280 1281 if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) 1282 return E_INVALIDARG; 1283 1284 if (len < sizeof(WIN32_FIND_DATAA)) 1285 return E_INVALIDARG; 1286 1287 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); 1288 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1289 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1290 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1291 1292 filename = _ILGetTextPointer(pidl); 1293 shortname = _ILGetSTextPointer(pidl); 1294 1295 if (filename) 1296 lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); 1297 else 1298 pfd->cFileName[0] = '\0'; 1299 1300 if (shortname) 1301 lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); 1302 else 1303 pfd->cAlternateFileName[0] = '\0'; 1304 return S_OK; 1305 1306 case SHGDFIL_NETRESOURCE: 1307 case SHGDFIL_DESCRIPTIONID: 1308 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1309 break; 1310 1311 default: 1312 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1313 } 1314 1315 return E_INVALIDARG; 1316 } 1317 1318 /************************************************************************* 1319 * SHGetDataFromIDListW [SHELL32.248] 1320 * 1321 */ 1322 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, 1323 int nFormat, LPVOID dest, int len) 1324 { 1325 LPSTR filename, shortname; 1326 WIN32_FIND_DATAW * pfd = dest; 1327 1328 TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); 1329 1330 pdump(pidl); 1331 1332 if (!psf || !dest) 1333 return E_INVALIDARG; 1334 1335 switch (nFormat) 1336 { 1337 case SHGDFIL_FINDDATA: 1338 pfd = dest; 1339 1340 if (_ILIsDrive(pidl)) 1341 return E_INVALIDARG; 1342 1343 if (len < sizeof(WIN32_FIND_DATAW)) 1344 return E_INVALIDARG; 1345 1346 ZeroMemory(pfd, sizeof (WIN32_FIND_DATAW)); 1347 _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); 1348 pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 1349 pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); 1350 1351 filename = _ILGetTextPointer(pidl); 1352 shortname = _ILGetSTextPointer(pidl); 1353 1354 if (!filename) 1355 pfd->cFileName[0] = '\0'; 1356 else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) 1357 pfd->cFileName[MAX_PATH-1] = 0; 1358 1359 if (!shortname) 1360 pfd->cAlternateFileName[0] = '\0'; 1361 else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) 1362 pfd->cAlternateFileName[13] = 0; 1363 return S_OK; 1364 1365 case SHGDFIL_NETRESOURCE: 1366 case SHGDFIL_DESCRIPTIONID: 1367 FIXME_(shell)("SHGDFIL %i stub\n", nFormat); 1368 break; 1369 1370 default: 1371 ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); 1372 } 1373 1374 return E_INVALIDARG; 1375 } 1376 1377 /************************************************************************* 1378 * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220] 1379 * 1380 * PARAMETERS 1381 * pidl, [IN] pidl 1382 * pszPath [OUT] path 1383 * 1384 * RETURNS 1385 * path from a passed PIDL. 1386 * 1387 * NOTES 1388 * NULL returns FALSE 1389 * desktop pidl gives path to desktop directory back 1390 * special pidls returning FALSE 1391 */ 1392 BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) 1393 { 1394 WCHAR wszPath[MAX_PATH]; 1395 BOOL bSuccess; 1396 1397 bSuccess = SHGetPathFromIDListW(pidl, wszPath); 1398 WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); 1399 1400 return bSuccess; 1401 } 1402 1403 /************************************************************************* 1404 * SHGetPathFromIDListW [SHELL32.@] 1405 * 1406 * See SHGetPathFromIDListA. 1407 */ 1408 HRESULT WINAPI 1409 SHGetPathCchFromIDListW( 1410 _In_ LPCITEMIDLIST pidl, 1411 _Out_writes_(cchPathMax) LPWSTR pszPath, 1412 _In_ SIZE_T cchPathMax) 1413 { 1414 HRESULT hr; 1415 LPCITEMIDLIST pidlLast; 1416 LPSHELLFOLDER psfFolder; 1417 DWORD dwAttributes; 1418 STRRET strret; 1419 1420 TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); 1421 pdump(pidl); 1422 1423 *pszPath = UNICODE_NULL; 1424 if (!pidl) 1425 return E_FAIL; 1426 1427 hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); 1428 if (FAILED(hr)) 1429 { 1430 ERR("SHBindToParent failed: %x\n", hr); 1431 return hr; 1432 } 1433 1434 dwAttributes = SFGAO_FILESYSTEM; 1435 hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); 1436 if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) 1437 { 1438 WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr); 1439 IShellFolder_Release(psfFolder); 1440 return E_FAIL; 1441 } 1442 1443 hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); 1444 IShellFolder_Release(psfFolder); 1445 if (FAILED(hr)) 1446 return hr; 1447 1448 hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax); 1449 1450 TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); 1451 return hr; 1452 } 1453 1454 BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) 1455 { 1456 return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH)); 1457 } 1458 1459 /************************************************************************* 1460 * SHBindToParent [shell version 5.0] 1461 */ 1462 HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) 1463 { 1464 IShellFolder * psfDesktop; 1465 HRESULT hr=E_FAIL; 1466 1467 TRACE_(shell)("pidl=%p\n", pidl); 1468 pdump(pidl); 1469 1470 if (!pidl || !ppv) 1471 return E_INVALIDARG; 1472 1473 *ppv = NULL; 1474 if (ppidlLast) 1475 *ppidlLast = NULL; 1476 1477 hr = SHGetDesktopFolder(&psfDesktop); 1478 if (FAILED(hr)) 1479 return hr; 1480 1481 if (_ILIsPidlSimple(pidl)) 1482 { 1483 /* we are on desktop level */ 1484 hr = IShellFolder_QueryInterface(psfDesktop, riid, ppv); 1485 } 1486 else 1487 { 1488 LPITEMIDLIST pidlParent = ILClone(pidl); 1489 ILRemoveLastID(pidlParent); 1490 hr = IShellFolder_BindToObject(psfDesktop, pidlParent, NULL, riid, ppv); 1491 SHFree (pidlParent); 1492 } 1493 1494 IShellFolder_Release(psfDesktop); 1495 1496 if (SUCCEEDED(hr) && ppidlLast) 1497 *ppidlLast = ILFindLastID(pidl); 1498 1499 TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); 1500 return hr; 1501 } 1502 1503 /************************************************************************* 1504 * SHParseDisplayName [shell version 6.0] 1505 */ 1506 HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, 1507 LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) 1508 { 1509 HRESULT hr; 1510 LPWSTR pszNameDup; 1511 IShellFolder *psfDesktop; 1512 IBindCtx *pBindCtx = NULL; 1513 1514 TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut); 1515 1516 *ppidl = NULL; 1517 1518 if (psfgaoOut) 1519 *psfgaoOut = 0; 1520 1521 pszNameDup = StrDupW(pszName); 1522 if (!pszNameDup) 1523 return E_OUTOFMEMORY; 1524 1525 psfDesktop = NULL; 1526 hr = SHGetDesktopFolder(&psfDesktop); 1527 if (FAILED(hr)) 1528 { 1529 LocalFree(pszNameDup); 1530 return hr; 1531 } 1532 1533 if (!pbc) 1534 { 1535 hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx); 1536 pbc = pBindCtx; 1537 } 1538 1539 if (SUCCEEDED(hr)) 1540 { 1541 ULONG sfgao = sfgaoIn, cchEaten; 1542 HWND hwndUI = BindCtx_GetUIWindow(pbc); 1543 hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop, 1544 hwndUI, 1545 pbc, 1546 pszNameDup, 1547 &cchEaten, 1548 ppidl, 1549 (psfgaoOut ? &sfgao : NULL)); 1550 if (SUCCEEDED(hr) && psfgaoOut) 1551 *psfgaoOut = (sfgao & sfgaoIn); 1552 } 1553 1554 LocalFree(pszNameDup); 1555 1556 if (psfDesktop) 1557 psfDesktop->lpVtbl->Release(psfDesktop); 1558 1559 if (pBindCtx) 1560 pBindCtx->lpVtbl->Release(pBindCtx); 1561 1562 return hr; 1563 } 1564 1565 /************************************************************************* 1566 * SHGetNameFromIDList [SHELL32.@] 1567 */ 1568 HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName) 1569 { 1570 IShellFolder *psfparent; 1571 LPCITEMIDLIST child_pidl; 1572 STRRET disp_name; 1573 HRESULT ret; 1574 1575 TRACE("%p 0x%08x %p\n", pidl, sigdnName, ppszName); 1576 1577 *ppszName = NULL; 1578 ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl); 1579 if(SUCCEEDED(ret)) 1580 { 1581 switch(sigdnName) 1582 { 1583 /* sigdnName & 0xffff */ 1584 case SIGDN_NORMALDISPLAY: /* SHGDN_NORMAL */ 1585 case SIGDN_PARENTRELATIVEPARSING: /* SHGDN_INFOLDER | SHGDN_FORPARSING */ 1586 case SIGDN_PARENTRELATIVEEDITING: /* SHGDN_INFOLDER | SHGDN_FOREDITING */ 1587 case SIGDN_DESKTOPABSOLUTEPARSING: /* SHGDN_FORPARSING */ 1588 case SIGDN_DESKTOPABSOLUTEEDITING: /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/ 1589 case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */ 1590 case SIGDN_PARENTRELATIVE: /* SIGDN_INFOLDER */ 1591 1592 disp_name.uType = STRRET_WSTR; 1593 ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl, 1594 sigdnName & 0xffff, 1595 &disp_name); 1596 if(SUCCEEDED(ret)) 1597 ret = StrRetToStrW(&disp_name, pidl, ppszName); 1598 1599 break; 1600 1601 case SIGDN_FILESYSPATH: 1602 *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH); 1603 if(SHGetPathFromIDListW(pidl, *ppszName)) 1604 { 1605 TRACE("Got string %s\n", debugstr_w(*ppszName)); 1606 ret = S_OK; 1607 } 1608 else 1609 { 1610 CoTaskMemFree(*ppszName); 1611 ret = E_INVALIDARG; 1612 } 1613 break; 1614 1615 case SIGDN_URL: 1616 default: 1617 FIXME("Unsupported SIGDN %x\n", sigdnName); 1618 ret = E_FAIL; 1619 } 1620 1621 IShellFolder_Release(psfparent); 1622 } 1623 return ret; 1624 } 1625 1626 #ifndef __REACTOS__ 1627 1628 /************************************************************************* 1629 * SHGetIDListFromObject [SHELL32.@] 1630 */ 1631 HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) 1632 { 1633 IPersistIDList *ppersidl; 1634 IPersistFolder2 *ppf2; 1635 IDataObject *pdo; 1636 IFolderView *pfv; 1637 HRESULT ret; 1638 1639 if(!punk) 1640 return E_NOINTERFACE; 1641 1642 *ppidl = NULL; 1643 1644 /* Try IPersistIDList */ 1645 ret = IUnknown_QueryInterface(punk, &IID_IPersistIDList, (void**)&ppersidl); 1646 if(SUCCEEDED(ret)) 1647 { 1648 TRACE("IPersistIDList (%p)\n", ppersidl); 1649 ret = IPersistIDList_GetIDList(ppersidl, ppidl); 1650 IPersistIDList_Release(ppersidl); 1651 if(SUCCEEDED(ret)) 1652 return ret; 1653 } 1654 1655 /* Try IPersistFolder2 */ 1656 ret = IUnknown_QueryInterface(punk, &IID_IPersistFolder2, (void**)&ppf2); 1657 if(SUCCEEDED(ret)) 1658 { 1659 TRACE("IPersistFolder2 (%p)\n", ppf2); 1660 ret = IPersistFolder2_GetCurFolder(ppf2, ppidl); 1661 IPersistFolder2_Release(ppf2); 1662 if(SUCCEEDED(ret)) 1663 return ret; 1664 } 1665 1666 /* Try IDataObject */ 1667 ret = IUnknown_QueryInterface(punk, &IID_IDataObject, (void**)&pdo); 1668 if(SUCCEEDED(ret)) 1669 { 1670 IShellItem *psi; 1671 TRACE("IDataObject (%p)\n", pdo); 1672 ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, 1673 &IID_IShellItem, (void**)&psi); 1674 if(SUCCEEDED(ret)) 1675 { 1676 ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); 1677 IShellItem_Release(psi); 1678 } 1679 IDataObject_Release(pdo); 1680 1681 if(SUCCEEDED(ret)) 1682 return ret; 1683 } 1684 1685 /* Try IFolderView */ 1686 ret = IUnknown_QueryInterface(punk, &IID_IFolderView, (void**)&pfv); 1687 if(SUCCEEDED(ret)) 1688 { 1689 IShellFolder *psf; 1690 TRACE("IFolderView (%p)\n", pfv); 1691 ret = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf); 1692 if(SUCCEEDED(ret)) 1693 { 1694 /* We might be able to get IPersistFolder2 from a shellfolder. */ 1695 ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); 1696 } 1697 IFolderView_Release(pfv); 1698 return ret; 1699 } 1700 1701 return ret; 1702 } 1703 1704 #endif /* !__REACTOS__ */ 1705 1706 /************************************************************************** 1707 * 1708 * internal functions 1709 * 1710 * ### 1. section creating pidls ### 1711 * 1712 ************************************************************************* 1713 */ 1714 1715 /* Basic PIDL constructor. Allocates size + 5 bytes, where: 1716 * - two bytes are SHITEMID.cb 1717 * - one byte is PIDLDATA.type 1718 * - two bytes are the NULL PIDL terminator 1719 * Sets type of the returned PIDL to type. 1720 */ 1721 static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) 1722 { 1723 LPITEMIDLIST pidlOut = NULL; 1724 1725 pidlOut = SHAlloc(size + 5); 1726 if(pidlOut) 1727 { 1728 LPPIDLDATA pData; 1729 LPITEMIDLIST pidlNext; 1730 1731 ZeroMemory(pidlOut, size + 5); 1732 pidlOut->mkid.cb = size + 3; 1733 1734 pData = _ILGetDataPointer(pidlOut); 1735 if (pData) 1736 pData->type = type; 1737 1738 pidlNext = ILGetNext(pidlOut); 1739 if (pidlNext) 1740 pidlNext->mkid.cb = 0x00; 1741 TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); 1742 } 1743 1744 return pidlOut; 1745 } 1746 1747 LPITEMIDLIST _ILCreateDesktop(void) 1748 { 1749 LPITEMIDLIST ret; 1750 1751 TRACE("()\n"); 1752 ret = SHAlloc(2); 1753 if (ret) 1754 ret->mkid.cb = 0; 1755 return ret; 1756 } 1757 1758 LPITEMIDLIST _ILCreateMyComputer(void) 1759 { 1760 TRACE("()\n"); 1761 return _ILCreateGuid(PT_GUID, &CLSID_MyComputer); 1762 } 1763 1764 LPITEMIDLIST _ILCreateMyDocuments(void) 1765 { 1766 TRACE("()\n"); 1767 return _ILCreateGuid(PT_GUID, &CLSID_MyDocuments); 1768 } 1769 1770 LPITEMIDLIST _ILCreateIExplore(void) 1771 { 1772 TRACE("()\n"); 1773 return _ILCreateGuid(PT_GUID, &CLSID_Internet); 1774 } 1775 1776 LPITEMIDLIST _ILCreateControlPanel(void) 1777 { 1778 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1779 1780 TRACE("()\n"); 1781 if (parent) 1782 { 1783 LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, &CLSID_ControlPanel); 1784 1785 if (cpl) 1786 { 1787 ret = ILCombine(parent, cpl); 1788 SHFree(cpl); 1789 } 1790 SHFree(parent); 1791 } 1792 return ret; 1793 } 1794 1795 LPITEMIDLIST _ILCreatePrinters(void) 1796 { 1797 #ifdef __REACTOS__ 1798 // Note: Wine returns the PIDL as it was in Windows 95, NT5 moved it into CSIDL_CONTROLS 1799 extern HRESULT SHGetFolderLocationHelper(HWND hwnd, int nFolder, REFCLSID clsid, LPITEMIDLIST *ppidl); 1800 LPITEMIDLIST pidl; 1801 SHGetFolderLocationHelper(NULL, CSIDL_CONTROLS, &CLSID_Printers, &pidl); 1802 return pidl; 1803 #else 1804 LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, &CLSID_MyComputer), ret = NULL; 1805 1806 TRACE("()\n"); 1807 if (parent) 1808 { 1809 LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, &CLSID_Printers); 1810 1811 if (printers) 1812 { 1813 ret = ILCombine(parent, printers); 1814 SHFree(printers); 1815 } 1816 SHFree(parent); 1817 } 1818 return ret; 1819 #endif 1820 } 1821 1822 LPITEMIDLIST _ILCreateNetwork(void) 1823 { 1824 TRACE("()\n"); 1825 return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); 1826 } 1827 1828 LPITEMIDLIST _ILCreateBitBucket(void) 1829 { 1830 TRACE("()\n"); 1831 return _ILCreateGuid(PT_GUID, &CLSID_RecycleBin); 1832 } 1833 1834 LPITEMIDLIST _ILCreateAdminTools(void) 1835 { 1836 TRACE("()\n"); 1837 return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME 1838 } 1839 1840 LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) 1841 { 1842 LPITEMIDLIST pidlOut; 1843 1844 if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) 1845 { 1846 pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); 1847 if (pidlOut) 1848 { 1849 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1850 1851 pData->u.guid.guid = *guid; 1852 TRACE("-- create GUID-pidl %s\n", 1853 debugstr_guid(&(pData->u.guid.guid))); 1854 } 1855 } 1856 else 1857 { 1858 WARN("%d: invalid type for GUID\n", type); 1859 pidlOut = NULL; 1860 } 1861 return pidlOut; 1862 } 1863 1864 #ifndef __REACTOS__ 1865 LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) 1866 { 1867 IID iid; 1868 1869 if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) 1870 { 1871 ERR("%s is not a GUID\n", szGUID); 1872 return NULL; 1873 } 1874 return _ILCreateGuid(PT_GUID, &iid); 1875 } 1876 1877 LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) 1878 { 1879 IID iid; 1880 1881 #ifndef __REACTOS__ 1882 if (FAILED(SHCLSIDFromStringW(szGUID, &iid))) 1883 #else 1884 if (!GUIDFromStringW(szGUID, &iid)) 1885 #endif 1886 { 1887 ERR("%s is not a GUID\n", debugstr_w(szGUID)); 1888 return NULL; 1889 } 1890 return _ILCreateGuid(PT_GUID, &iid); 1891 } 1892 #endif /* __REACTOS__ */ 1893 1894 LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) 1895 { 1896 char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ 1897 DWORD len, len1, wlen, alen; 1898 LPITEMIDLIST pidl; 1899 PIDLTYPE type; 1900 1901 if (!wfd) 1902 return NULL; 1903 1904 TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); 1905 1906 /* prepare buffer with both names */ 1907 len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); 1908 len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); 1909 alen = len + len1; 1910 1911 type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; 1912 1913 wlen = lstrlenW(wfd->cFileName) + 1; 1914 pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + 1915 FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); 1916 if (pidl) 1917 { 1918 LPPIDLDATA pData = _ILGetDataPointer(pidl); 1919 FileStruct *fs = &pData->u.file; 1920 FileStructW *fsw; 1921 WORD *pOffsetW; 1922 1923 FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); 1924 fs->dwFileSize = wfd->nFileSizeLow; 1925 fs->uFileAttribs = wfd->dwFileAttributes; 1926 memcpy(fs->szNames, buff, alen); 1927 1928 fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); 1929 fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); 1930 FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); 1931 FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); 1932 memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); 1933 1934 pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); 1935 *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; 1936 TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); 1937 } 1938 return pidl; 1939 1940 } 1941 1942 HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) 1943 { 1944 HANDLE hFile; 1945 WIN32_FIND_DATAW stffile; 1946 1947 if (!ppidl) 1948 return E_INVALIDARG; 1949 1950 hFile = FindFirstFileW(szPath, &stffile); 1951 if (hFile == INVALID_HANDLE_VALUE) 1952 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 1953 1954 FindClose(hFile); 1955 1956 *ppidl = _ILCreateFromFindDataW(&stffile); 1957 1958 return *ppidl ? S_OK : E_OUTOFMEMORY; 1959 } 1960 1961 LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) 1962 { 1963 LPITEMIDLIST pidlOut; 1964 1965 TRACE("(%s)\n",debugstr_w(lpszNew)); 1966 1967 pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); 1968 if (pidlOut) 1969 { 1970 LPSTR pszDest = _ILGetTextPointer(pidlOut); 1971 if (pszDest) 1972 { 1973 lstrcpyA(pszDest, "x:\\"); 1974 pszDest[0] = toupper(lpszNew[0]); 1975 TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); 1976 } 1977 } 1978 return pidlOut; 1979 } 1980 1981 LPITEMIDLIST _ILCreateEntireNetwork(void) 1982 { 1983 LPITEMIDLIST pidlOut; 1984 1985 TRACE("\n"); 1986 1987 pidlOut = _ILAlloc(PT_NETWORK, FIELD_OFFSET(PIDLDATA, u.network.szNames[sizeof("Entire Network")])); 1988 if (pidlOut) 1989 { 1990 LPPIDLDATA pData = _ILGetDataPointer(pidlOut); 1991 1992 pData->u.network.dummy = 0; 1993 strcpy(pData->u.network.szNames, "Entire Network"); 1994 } 1995 return pidlOut; 1996 } 1997 1998 /************************************************************************** 1999 * _ILGetDrive() 2000 * 2001 * Gets the text for the drive eg. 'c:\' 2002 * 2003 * RETURNS 2004 * strlen (lpszText) 2005 */ 2006 DWORD _ILGetDrive(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uSize) 2007 { 2008 TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); 2009 2010 if(_ILIsMyComputer(pidl)) 2011 pidl = ILGetNext(pidl); 2012 2013 if (pidl && _ILIsDrive(pidl)) 2014 return _ILSimpleGetTextW(pidl, pOut, uSize); 2015 2016 return 0; 2017 } 2018 2019 /************************************************************************** 2020 * 2021 * ### 2. section testing pidls ### 2022 * 2023 ************************************************************************** 2024 * _ILIsUnicode() 2025 * _ILIsDesktop() 2026 * _ILIsMyComputer() 2027 * _ILIsSpecialFolder() 2028 * _ILIsDrive() 2029 * _ILIsFolder() 2030 * _ILIsValue() 2031 * _ILIsPidlSimple() 2032 */ 2033 BOOL _ILIsUnicode(LPCITEMIDLIST pidl) 2034 { 2035 TRACE("(%p)\n",pidl); 2036 2037 return (_ILGetFSType(pidl) & PT_FS_UNICODE_FLAG) != 0; 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