[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / folders / CDrivesFolder.cpp
1 /*
2 * Virtual Workplace folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL (shell);
26
27 /*
28 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
29 the registry. The CRegFolder is aggregated by the CDrivesFolder.
30 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
31 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
32 CDrivesFolderEnum is only responsible for returning the physical items.
33
34 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
35 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
36 */
37
38 static int iDriveIconIds[7] = { IDI_SHELL_DRIVE, /* DRIVE_UNKNOWN */
39 IDI_SHELL_CDROM, /* DRIVE_NO_ROOT_DIR*/
40 IDI_SHELL_3_14_FLOPPY, /* DRIVE_REMOVABLE*/
41 IDI_SHELL_DRIVE, /* DRIVE_FIXED*/
42 IDI_SHELL_NETDRIVE, /* DRIVE_REMOTE*/
43 IDI_SHELL_CDROM, /* DRIVE_CDROM*/
44 IDI_SHELL_RAMDISK /* DRIVE_RAMDISK*/
45 };
46
47 static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */
48 IDS_DRIVE_FIXED, /* DRIVE_NO_ROOT_DIR*/
49 IDS_DRIVE_FLOPPY, /* DRIVE_REMOVABLE*/
50 IDS_DRIVE_FIXED, /* DRIVE_FIXED*/
51 IDS_DRIVE_NETWORK, /* DRIVE_REMOTE*/
52 IDS_DRIVE_CDROM, /* DRIVE_CDROM*/
53 IDS_DRIVE_FIXED /* DRIVE_RAMDISK*/
54 };
55
56 /***********************************************************************
57 * IShellFolder implementation
58 */
59
60 HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf,
61 HWND hwnd,
62 IDataObject *pdtobj,
63 UINT uMsg,
64 WPARAM wParam,
65 LPARAM lParam)
66 {
67 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
68 return S_OK;
69
70 PIDLIST_ABSOLUTE pidlFolder;
71 PUITEMID_CHILD *apidl;
72 UINT cidl;
73 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
74 if (FAILED_UNEXPECTEDLY(hr))
75 return hr;
76
77 char szDrive[8] = {0};
78 if (!_ILGetDrive(apidl[0], szDrive, sizeof(szDrive)))
79 {
80 ERR("pidl is not a drive\n");
81 SHFree(pidlFolder);
82 _ILFreeaPidl(apidl, cidl);
83 return E_FAIL;
84 }
85
86 if (uMsg == DFM_MERGECONTEXTMENU)
87 {
88 QCMINFO *pqcminfo = (QCMINFO *)lParam;
89 DWORD dwFlags;
90
91 if (GetVolumeInformationA(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0))
92 {
93 /* Disable format if read only */
94 if (!(dwFlags & FILE_READ_ONLY_VOLUME) && GetDriveTypeA(szDrive) != DRIVE_REMOTE)
95 {
96 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
97 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
98 }
99 }
100 }
101 else if (uMsg == DFM_INVOKECOMMAND)
102 {
103 if (wParam == DFM_CMD_PROPERTIES)
104 {
105 WCHAR wszBuf[4];
106 wcscpy(wszBuf, L"A:\\");
107 wszBuf[0] = (WCHAR)szDrive[0];
108 if (!SH_ShowDriveProperties(wszBuf, pidlFolder, apidl))
109 hr = E_FAIL;
110 }
111 else
112 {
113 SHFormatDrive(hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
114 }
115 }
116
117 SHFree(pidlFolder);
118 _ILFreeaPidl(apidl, cidl);
119
120 return hr;
121 }
122
123 HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
124 HWND hwnd,
125 UINT cidl,
126 PCUITEMID_CHILD_ARRAY apidl,
127 IShellFolder *psf,
128 IContextMenu **ppcm)
129 {
130 HKEY hKeys[2];
131 UINT cKeys = 0;
132 AddClassKeyToArray(L"Drive", hKeys, &cKeys);
133 AddClassKeyToArray(L"Folder", hKeys, &cKeys);
134
135 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
136 }
137
138 HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
139 {
140 CComPtr<IDefaultExtractIconInit> initIcon;
141 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
142 if (FAILED_UNEXPECTEDLY(hr))
143 return hr;
144
145 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
146 UINT DriveType = GetDriveTypeA(pszDrive);
147 if (DriveType > DRIVE_RAMDISK)
148 DriveType = DRIVE_FIXED;
149
150 WCHAR wTemp[MAX_PATH];
151 int icon_idx;
152 if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) &&
153 (HCR_GetIconW(L"Drive", wTemp, NULL, MAX_PATH, &icon_idx)))
154 {
155 initIcon->SetNormalIcon(wTemp, icon_idx);
156 }
157 else
158 {
159 icon_idx = iDriveIconIds[DriveType];
160 initIcon->SetNormalIcon(swShell32Name, -icon_idx);
161 }
162
163 return initIcon->QueryInterface(riid, ppvOut);
164 }
165
166 class CDrivesFolderEnum :
167 public CEnumIDListBase
168 {
169 public:
170 CDrivesFolderEnum();
171 ~CDrivesFolderEnum();
172 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
173 BOOL CreateMyCompEnumList(DWORD dwFlags);
174
175 BEGIN_COM_MAP(CDrivesFolderEnum)
176 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
177 END_COM_MAP()
178 };
179
180 /***********************************************************************
181 * IShellFolder [MyComputer] implementation
182 */
183
184 static const shvheader MyComputerSFHeader[] = {
185 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
186 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10},
187 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
188 {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
189 {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
190 };
191
192 #define MYCOMPUTERSHELLVIEWCOLUMNS 5
193
194 static const DWORD dwComputerAttributes =
195 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
196 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
197 static const DWORD dwControlPanelAttributes =
198 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
199 static const DWORD dwDriveAttributes =
200 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
201 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
202
203 CDrivesFolderEnum::CDrivesFolderEnum()
204 {
205 }
206
207 CDrivesFolderEnum::~CDrivesFolderEnum()
208 {
209 }
210
211 HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
212 {
213 if (CreateMyCompEnumList(dwFlags) == FALSE)
214 return E_FAIL;
215
216 return S_OK;
217 }
218
219 /**************************************************************************
220 * CDrivesFolderEnum::CreateMyCompEnumList()
221 */
222
223 BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
224 {
225 BOOL bRet = TRUE;
226 static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
227
228 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
229
230 /* enumerate the folders */
231 if (dwFlags & SHCONTF_FOLDERS)
232 {
233 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
234 DWORD dwDrivemap = GetLogicalDrives();
235 HKEY hKey;
236 UINT i;
237
238 while (bRet && wszDriveName[0] <= 'Z')
239 {
240 if(dwDrivemap & 0x00000001L)
241 bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
242 wszDriveName[0]++;
243 dwDrivemap = dwDrivemap >> 1;
244 }
245
246 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
247 for (i = 0; i < 2; i++)
248 {
249 if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
250 MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
251 {
252 WCHAR wszBuf[50];
253 DWORD dwSize, j = 0;
254 LONG ErrorCode;
255 LPITEMIDLIST pidl;
256
257 while (bRet)
258 {
259 dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
260 ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
261 if (ERROR_SUCCESS == ErrorCode)
262 {
263 if (wszBuf[0] != L'{')
264 {
265 dwSize = sizeof(wszBuf);
266 RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
267 }
268
269 /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
270 pidl = _ILCreateGuidFromStrW(wszBuf);
271 if (pidl != NULL)
272 bRet = AddToEnumList(pidl);
273 else
274 ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
275 j++;
276 }
277 else if (ERROR_NO_MORE_ITEMS == ErrorCode)
278 break;
279 else
280 bRet = FALSE;
281 }
282 RegCloseKey(hKey);
283 }
284 }
285 }
286 return bRet;
287 }
288
289 CDrivesFolder::CDrivesFolder()
290 {
291 pidlRoot = NULL;
292 }
293
294 CDrivesFolder::~CDrivesFolder()
295 {
296 TRACE ("-- destroying IShellFolder(%p)\n", this);
297 SHFree(pidlRoot);
298 }
299
300 HRESULT WINAPI CDrivesFolder::FinalConstruct()
301 {
302 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
303 if (pidlRoot == NULL)
304 return E_OUTOFMEMORY;
305
306 HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer,
307 pidlRoot,
308 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
309 IID_PPV_ARG(IShellFolder2, &m_regFolder));
310
311 return hr;
312 }
313
314 /**************************************************************************
315 * CDrivesFolder::ParseDisplayName
316 */
317 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
318 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
319 {
320 HRESULT hr = E_INVALIDARG;
321 LPCWSTR szNext = NULL;
322 LPITEMIDLIST pidlTemp = NULL;
323
324 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
325 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
326 pchEaten, ppidl, pdwAttributes);
327
328 *ppidl = 0;
329 if (pchEaten)
330 *pchEaten = 0; /* strange but like the original */
331
332 /* handle CLSID paths */
333 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
334 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
335
336 if (PathGetDriveNumberW(lpszDisplayName) < 0)
337 return E_INVALIDARG;
338
339 pidlTemp = _ILCreateDrive(lpszDisplayName);
340 if (!pidlTemp)
341 return E_OUTOFMEMORY;
342
343 if (lpszDisplayName[2] == L'\\')
344 {
345 szNext = &lpszDisplayName[3];
346 }
347
348 if (szNext && *szNext)
349 {
350 hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
351 (LPOLESTR) szNext, pchEaten, pdwAttributes);
352 }
353 else
354 {
355 hr = S_OK;
356 if (pdwAttributes && *pdwAttributes)
357 {
358 if (_ILIsDrive(pidlTemp))
359 *pdwAttributes &= dwDriveAttributes;
360 else if (_ILIsSpecialFolder(pidlTemp))
361 m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
362 else
363 ERR("Got an unkown pidl here!\n");
364 }
365 }
366
367 *ppidl = pidlTemp;
368
369 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
370
371 return hr;
372 }
373
374 /**************************************************************************
375 * CDrivesFolder::EnumObjects
376 */
377 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
378 {
379 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
380 }
381
382 /**************************************************************************
383 * CDrivesFolder::BindToObject
384 */
385 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
386 {
387 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
388 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
389
390 if (_ILIsSpecialFolder(pidl))
391 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
392
393 CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
394
395 PERSIST_FOLDER_TARGET_INFO pfti = {0};
396 pfti.dwAttributes = -1;
397 pfti.csidl = -1;
398 pfti.szTargetParsingName[0] = *pchDrive;
399 pfti.szTargetParsingName[1] = L':';
400 pfti.szTargetParsingName[2] = L'\\';
401
402 HRESULT hr = SHELL32_BindToSF(pidlRoot,
403 &pfti,
404 pidl,
405 &CLSID_ShellFSFolder,
406 riid,
407 ppvOut);
408 if (FAILED_UNEXPECTEDLY(hr))
409 return hr;
410
411 return S_OK;
412 }
413
414 /**************************************************************************
415 * CDrivesFolder::BindToStorage
416 */
417 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
418 {
419 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
420 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
421
422 *ppvOut = NULL;
423 return E_NOTIMPL;
424 }
425
426 /**************************************************************************
427 * CDrivesFolder::CompareIDs
428 */
429
430 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
431 {
432 HRESULT hres;
433
434 if (!pidl1 || !pidl2)
435 {
436 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
437 return E_INVALIDARG;
438 }
439
440 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
441 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
442
443 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
444 return E_INVALIDARG;
445
446 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
447 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
448
449 int result;
450 switch(LOWORD(lParam))
451 {
452 case 0: /* name */
453 {
454 result = stricmp(pszDrive1, pszDrive2);
455 hres = MAKE_COMPARE_HRESULT(result);
456 break;
457 }
458 case 1: /* comments */
459 hres = MAKE_COMPARE_HRESULT(0);
460 break;
461 case 2: /* Type */
462 {
463 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
464 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
465 }
466 case 3: /* Size */
467 case 4: /* Size Available */
468 {
469 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
470
471 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
472 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
473 else
474 Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
475
476 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
477 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
478 else
479 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
480
481 LARGE_INTEGER Diff;
482 if (lParam == 3) /* Size */
483 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
484 else /* Size available */
485 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
486
487 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
488 break;
489 }
490 default:
491 return E_INVALIDARG;
492 }
493
494 if (HRESULT_CODE(hres) == 0)
495 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
496
497 return hres;
498 }
499
500 /**************************************************************************
501 * CDrivesFolder::CreateViewObject
502 */
503 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
504 {
505 CComPtr<IShellView> pShellView;
506 HRESULT hr = E_INVALIDARG;
507
508 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
509 hwndOwner, shdebugstr_guid (&riid), ppvOut);
510
511 if (!ppvOut)
512 return hr;
513
514 *ppvOut = NULL;
515
516 if (IsEqualIID(riid, IID_IDropTarget))
517 {
518 WARN("IDropTarget not implemented\n");
519 hr = E_NOTIMPL;
520 }
521 else if (IsEqualIID(riid, IID_IContextMenu))
522 {
523 WARN("IContextMenu not implemented\n");
524 hr = E_NOTIMPL;
525 }
526 else if (IsEqualIID(riid, IID_IShellView))
527 {
528 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
529 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
530 }
531 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
532 return hr;
533 }
534
535 static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
536 {
537 GUID *guid = _ILGetGUIDPointer(pidl);
538
539 TRACE("(%p)\n", pidl);
540
541 if (guid)
542 return IsEqualIID(*guid, CLSID_ControlPanel);
543 return FALSE;
544 }
545
546 /**************************************************************************
547 * CDrivesFolder::GetAttributesOf
548 */
549 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
550 {
551 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
552 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
553
554 if (cidl && !apidl)
555 return E_INVALIDARG;
556
557 if (*rgfInOut == 0)
558 *rgfInOut = ~0;
559
560 /* FIXME: always add SFGAO_CANLINK */
561 if(cidl == 0)
562 *rgfInOut &= dwComputerAttributes;
563 else
564 {
565 for (UINT i = 0; i < cidl; ++i)
566 {
567 if (_ILIsDrive(apidl[i]))
568 *rgfInOut &= dwDriveAttributes;
569 else if (_ILIsControlPanel(apidl[i]))
570 *rgfInOut &= dwControlPanelAttributes;
571 else if (_ILIsSpecialFolder(*apidl))
572 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
573 else
574 ERR("Got unknown pidl type!\n");
575 }
576 }
577
578 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
579 *rgfInOut &= ~SFGAO_VALIDATE;
580
581 TRACE ("-- result=0x%08x\n", *rgfInOut);
582 return S_OK;
583 }
584
585 /**************************************************************************
586 * CDrivesFolder::GetUIObjectOf
587 *
588 * PARAMETERS
589 * hwndOwner [in] Parent window for any output
590 * cidl [in] array size
591 * apidl [in] simple pidl array
592 * riid [in] Requested Interface
593 * prgfInOut [ ] reserved
594 * ppvObject [out] Resulting Interface
595 *
596 */
597 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
598 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
599 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
600 {
601 LPVOID pObj = NULL;
602 HRESULT hr = E_INVALIDARG;
603
604 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
605 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
606
607 if (!ppvOut)
608 return hr;
609
610 *ppvOut = NULL;
611
612 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
613 {
614 if (_ILIsDrive(apidl[0]))
615 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
616 else
617 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
618 }
619 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
620 {
621 hr = IDataObject_Constructor (hwndOwner,
622 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
623 }
624 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
625 {
626 if (_ILIsDrive(apidl[0]))
627 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
628 else
629 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
630 }
631 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
632 {
633 CComPtr<IShellFolder> psfChild;
634 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
635 if (FAILED_UNEXPECTEDLY(hr))
636 return hr;
637
638 return psfChild->CreateViewObject(NULL, riid, ppvOut);
639 }
640 else
641 hr = E_NOINTERFACE;
642
643 if (SUCCEEDED(hr) && !pObj)
644 hr = E_OUTOFMEMORY;
645
646 *ppvOut = pObj;
647 TRACE ("(%p)->hr=0x%08x\n", this, hr);
648 return hr;
649 }
650
651 /**************************************************************************
652 * CDrivesFolder::GetDisplayNameOf
653 */
654 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
655 {
656 LPWSTR pszPath;
657 HRESULT hr = S_OK;
658
659 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
660 pdump (pidl);
661
662 if (!strRet)
663 return E_INVALIDARG;
664
665 if (!_ILIsPidlSimple (pidl))
666 {
667 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
668 }
669 else if (_ILIsSpecialFolder(pidl))
670 {
671 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
672 }
673 else if (!_ILIsDrive(pidl))
674 {
675 ERR("Wrong pidl type\n");
676 return E_INVALIDARG;
677 }
678
679 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
680 if (!pszPath)
681 return E_OUTOFMEMORY;
682
683 pszPath[0] = 0;
684
685 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
686 /* long view "lw_name (C:)" */
687 if (!(dwFlags & SHGDN_FORPARSING))
688 {
689 WCHAR wszDrive[18] = {0};
690 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
691 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
692 static const WCHAR wszCloseBracket[] = {')', 0};
693
694 lstrcpynW(wszDrive, pszPath, 4);
695 pszPath[0] = L'\0';
696 GetVolumeInformationW(wszDrive, pszPath,
697 MAX_PATH - 7,
698 &dwVolumeSerialNumber,
699 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
700 pszPath[MAX_PATH-1] = L'\0';
701 if (!wcslen(pszPath))
702 {
703 UINT DriveType, ResourceId;
704 DriveType = GetDriveTypeW(wszDrive);
705 switch(DriveType)
706 {
707 case DRIVE_FIXED:
708 ResourceId = IDS_DRIVE_FIXED;
709 break;
710 case DRIVE_REMOTE:
711 ResourceId = IDS_DRIVE_NETWORK;
712 break;
713 case DRIVE_CDROM:
714 ResourceId = IDS_DRIVE_CDROM;
715 break;
716 default:
717 ResourceId = 0;
718 }
719 if (ResourceId)
720 {
721 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
722 if (dwFileSystemFlags > MAX_PATH - 7)
723 pszPath[MAX_PATH-7] = L'\0';
724 }
725 }
726 wcscat (pszPath, wszOpenBracket);
727 wszDrive[2] = L'\0';
728 wcscat (pszPath, wszDrive);
729 wcscat (pszPath, wszCloseBracket);
730 }
731
732 if (SUCCEEDED(hr))
733 {
734 strRet->uType = STRRET_WSTR;
735 strRet->pOleStr = pszPath;
736 }
737 else
738 CoTaskMemFree(pszPath);
739
740 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
741 return hr;
742 }
743
744 /**************************************************************************
745 * CDrivesFolder::SetNameOf
746 * Changes the name of a file object or subfolder, possibly changing its item
747 * identifier in the process.
748 *
749 * PARAMETERS
750 * hwndOwner [in] Owner window for output
751 * pidl [in] simple pidl of item to change
752 * lpszName [in] the items new display name
753 * dwFlags [in] SHGNO formatting flags
754 * ppidlOut [out] simple pidl returned
755 */
756 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
757 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
758 {
759 WCHAR szName[30];
760
761 if (_ILIsDrive(pidl))
762 {
763 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
764 SetVolumeLabelW(szName, lpName);
765 if (pPidlOut)
766 *pPidlOut = _ILCreateDrive(szName);
767 return S_OK;
768 }
769
770 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
771 }
772
773 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
774 {
775 FIXME ("(%p)\n", this);
776 return E_NOTIMPL;
777 }
778
779 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
780 {
781 FIXME ("(%p)\n", this);
782 return E_NOTIMPL;
783 }
784
785 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
786 {
787 TRACE ("(%p)\n", this);
788
789 if (pSort)
790 *pSort = 0;
791 if (pDisplay)
792 *pDisplay = 0;
793 return S_OK;
794 }
795
796 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
797 {
798 TRACE ("(%p)\n", this);
799
800 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
801 return E_INVALIDARG;
802 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
803 return S_OK;
804 }
805
806 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
807 {
808 FIXME ("(%p)\n", this);
809 return E_NOTIMPL;
810 }
811
812 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
813 {
814 HRESULT hr;
815
816 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
817
818 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
819 return E_INVALIDARG;
820
821 if (!pidl)
822 {
823 psd->fmt = MyComputerSFHeader[iColumn].fmt;
824 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
825 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
826 }
827 else if (!_ILIsDrive(pidl))
828 {
829 return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
830 }
831 else
832 {
833 ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
834 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
835 UINT DriveType = GetDriveTypeA(pszDrive);
836 if (DriveType > DRIVE_RAMDISK)
837 DriveType = DRIVE_FIXED;
838
839 switch (iColumn)
840 {
841 case 0: /* name */
842 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
843 break;
844 case 1: /* FIXME: comments */
845 hr = SHSetStrRet(&psd->str, "");
846 break;
847 case 2: /* type */
848 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
849 break;
850 case 3: /* total size */
851 case 4: /* free size */
852 psd->str.cStr[0] = 0x00;
853 psd->str.uType = STRRET_CSTR;
854 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0))
855 {
856 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
857 if (iColumn == 2)
858 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
859 else
860 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
861 }
862 hr = S_OK;
863 break;
864 }
865 }
866
867 return hr;
868 }
869
870 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
871 {
872 FIXME("(%p)\n", this);
873 return E_NOTIMPL;
874 }
875
876 /************************************************************************
877 * CDrivesFolder::GetClassID
878 */
879 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
880 {
881 TRACE ("(%p)\n", this);
882
883 if (!lpClassId)
884 return E_POINTER;
885
886 *lpClassId = CLSID_MyComputer;
887 return S_OK;
888 }
889
890 /************************************************************************
891 * CDrivesFolder::Initialize
892 *
893 * NOTES: it makes no sense to change the pidl
894 */
895 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
896 {
897 return S_OK;
898 }
899
900 /**************************************************************************
901 * CDrivesFolder::GetCurFolder
902 */
903 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
904 {
905 TRACE("(%p)->(%p)\n", this, pidl);
906
907 if (!pidl)
908 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
909
910 *pidl = ILClone(pidlRoot);
911 return S_OK;
912 }