[SHELL32] -CDrivesFolder: Implement returning the appropriate type string in GetDetai...
[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_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
186 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
187 {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
188 {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
189 };
190
191 #define MYCOMPUTERSHELLVIEWCOLUMNS 4
192
193 static const DWORD dwComputerAttributes =
194 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
195 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
196 static const DWORD dwControlPanelAttributes =
197 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
198 static const DWORD dwDriveAttributes =
199 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
200 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
201
202 CDrivesFolderEnum::CDrivesFolderEnum()
203 {
204 }
205
206 CDrivesFolderEnum::~CDrivesFolderEnum()
207 {
208 }
209
210 HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
211 {
212 if (CreateMyCompEnumList(dwFlags) == FALSE)
213 return E_FAIL;
214
215 return S_OK;
216 }
217
218 /**************************************************************************
219 * CDrivesFolderEnum::CreateMyCompEnumList()
220 */
221
222 BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
223 {
224 BOOL bRet = TRUE;
225 static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
226
227 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
228
229 /* enumerate the folders */
230 if (dwFlags & SHCONTF_FOLDERS)
231 {
232 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
233 DWORD dwDrivemap = GetLogicalDrives();
234 HKEY hKey;
235 UINT i;
236
237 while (bRet && wszDriveName[0] <= 'Z')
238 {
239 if(dwDrivemap & 0x00000001L)
240 bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
241 wszDriveName[0]++;
242 dwDrivemap = dwDrivemap >> 1;
243 }
244
245 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
246 for (i = 0; i < 2; i++)
247 {
248 if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
249 MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
250 {
251 WCHAR wszBuf[50];
252 DWORD dwSize, j = 0;
253 LONG ErrorCode;
254 LPITEMIDLIST pidl;
255
256 while (bRet)
257 {
258 dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
259 ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
260 if (ERROR_SUCCESS == ErrorCode)
261 {
262 if (wszBuf[0] != L'{')
263 {
264 dwSize = sizeof(wszBuf);
265 RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
266 }
267
268 /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
269 pidl = _ILCreateGuidFromStrW(wszBuf);
270 if (pidl != NULL)
271 bRet = AddToEnumList(pidl);
272 else
273 ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
274 j++;
275 }
276 else if (ERROR_NO_MORE_ITEMS == ErrorCode)
277 break;
278 else
279 bRet = FALSE;
280 }
281 RegCloseKey(hKey);
282 }
283 }
284 }
285 return bRet;
286 }
287
288 CDrivesFolder::CDrivesFolder()
289 {
290 pidlRoot = NULL;
291 }
292
293 CDrivesFolder::~CDrivesFolder()
294 {
295 TRACE ("-- destroying IShellFolder(%p)\n", this);
296 SHFree(pidlRoot);
297 }
298
299 HRESULT WINAPI CDrivesFolder::FinalConstruct()
300 {
301 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
302 if (pidlRoot == NULL)
303 return E_OUTOFMEMORY;
304
305 HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer,
306 pidlRoot,
307 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
308 IID_PPV_ARG(IShellFolder2, &m_regFolder));
309
310 return hr;
311 }
312
313 /**************************************************************************
314 * CDrivesFolder::ParseDisplayName
315 */
316 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
317 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
318 {
319 HRESULT hr = E_INVALIDARG;
320 LPCWSTR szNext = NULL;
321 LPITEMIDLIST pidlTemp = NULL;
322
323 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
324 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
325 pchEaten, ppidl, pdwAttributes);
326
327 *ppidl = 0;
328 if (pchEaten)
329 *pchEaten = 0; /* strange but like the original */
330
331 /* handle CLSID paths */
332 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
333 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
334
335 if (PathGetDriveNumberW(lpszDisplayName) < 0)
336 return E_INVALIDARG;
337
338 pidlTemp = _ILCreateDrive(lpszDisplayName);
339 if (!pidlTemp)
340 return E_OUTOFMEMORY;
341
342 if (lpszDisplayName[2] == L'\\')
343 {
344 szNext = &lpszDisplayName[3];
345 }
346
347 if (szNext && *szNext)
348 {
349 hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
350 (LPOLESTR) szNext, pchEaten, pdwAttributes);
351 }
352 else
353 {
354 hr = S_OK;
355 if (pdwAttributes && *pdwAttributes)
356 {
357 if (_ILIsDrive(pidlTemp))
358 *pdwAttributes &= dwDriveAttributes;
359 else if (_ILIsSpecialFolder(pidlTemp))
360 m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
361 else
362 ERR("Got an unkown pidl here!\n");
363 }
364 }
365
366 *ppidl = pidlTemp;
367
368 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
369
370 return hr;
371 }
372
373 /**************************************************************************
374 * CDrivesFolder::EnumObjects
375 */
376 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
377 {
378 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
379 }
380
381 /**************************************************************************
382 * CDrivesFolder::BindToObject
383 */
384 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
385 {
386 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
387 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
388
389 if (_ILIsSpecialFolder(pidl))
390 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
391
392 LPITEMIDLIST pidlChild = ILCloneFirst (pidl);
393 if (!pidlChild)
394 return E_OUTOFMEMORY;
395
396 CComPtr<IShellFolder> psf;
397 HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot,
398 NULL,
399 pidlChild,
400 &CLSID_ShellFSFolder,
401 -1,
402 IID_PPV_ARG(IShellFolder, &psf));
403
404 ILFree(pidlChild);
405
406 if (FAILED(hr))
407 return hr;
408
409 if (_ILIsPidlSimple (pidl))
410 {
411 return psf->QueryInterface(riid, ppvOut);
412 }
413 else
414 {
415 return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
416 }
417 }
418
419 /**************************************************************************
420 * CDrivesFolder::BindToStorage
421 */
422 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
423 {
424 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
425 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
426
427 *ppvOut = NULL;
428 return E_NOTIMPL;
429 }
430
431 /**************************************************************************
432 * CDrivesFolder::CompareIDs
433 */
434
435 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
436 {
437 HRESULT hres;
438
439 if (!pidl1 || !pidl2)
440 {
441 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
442 return E_INVALIDARG;
443 }
444
445 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
446 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
447
448 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
449 return E_INVALIDARG;
450
451 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
452 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
453
454 int result;
455 switch(LOWORD(lParam))
456 {
457 case 0: /* name */
458 {
459 result = stricmp(pszDrive1, pszDrive2);
460 hres = MAKE_COMPARE_HRESULT(result);
461 break;
462 }
463 case 1: /* Type */
464 {
465 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
466 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
467 }
468 case 2: /* Size */
469 case 3: /* Size Available */
470 {
471 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
472
473 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
474 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
475 else
476 Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
477
478 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
479 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
480 else
481 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
482
483 LARGE_INTEGER Diff;
484 if (lParam == 2) /* Size */
485 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
486 else /* Size available */
487 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
488
489 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
490 break;
491 }
492 default:
493 return E_INVALIDARG;
494 }
495
496 if (HRESULT_CODE(hres) == 0)
497 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
498
499 return hres;
500 }
501
502 /**************************************************************************
503 * CDrivesFolder::CreateViewObject
504 */
505 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
506 {
507 CComPtr<IShellView> pShellView;
508 HRESULT hr = E_INVALIDARG;
509
510 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
511 hwndOwner, shdebugstr_guid (&riid), ppvOut);
512
513 if (!ppvOut)
514 return hr;
515
516 *ppvOut = NULL;
517
518 if (IsEqualIID(riid, IID_IDropTarget))
519 {
520 WARN("IDropTarget not implemented\n");
521 hr = E_NOTIMPL;
522 }
523 else if (IsEqualIID(riid, IID_IContextMenu))
524 {
525 WARN("IContextMenu not implemented\n");
526 hr = E_NOTIMPL;
527 }
528 else if (IsEqualIID(riid, IID_IShellView))
529 {
530 hr = CDefView_Constructor(this, riid, ppvOut);
531 }
532 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
533 return hr;
534 }
535
536 static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
537 {
538 GUID *guid = _ILGetGUIDPointer(pidl);
539
540 TRACE("(%p)\n", pidl);
541
542 if (guid)
543 return IsEqualIID(*guid, CLSID_ControlPanel);
544 return FALSE;
545 }
546
547 /**************************************************************************
548 * CDrivesFolder::GetAttributesOf
549 */
550 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
551 {
552 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
553 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
554
555 if (cidl && !apidl)
556 return E_INVALIDARG;
557
558 if (*rgfInOut == 0)
559 *rgfInOut = ~0;
560
561 /* FIXME: always add SFGAO_CANLINK */
562 if(cidl == 0)
563 *rgfInOut &= dwComputerAttributes;
564 else
565 {
566 for (UINT i = 0; i < cidl; ++i)
567 {
568 if (_ILIsDrive(apidl[i]))
569 *rgfInOut &= dwDriveAttributes;
570 else if (_ILIsControlPanel(apidl[i]))
571 *rgfInOut &= dwControlPanelAttributes;
572 else if (_ILIsSpecialFolder(*apidl))
573 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
574 else
575 ERR("Got unknown pidl type!\n");
576 }
577 }
578
579 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
580 *rgfInOut &= ~SFGAO_VALIDATE;
581
582 TRACE ("-- result=0x%08x\n", *rgfInOut);
583 return S_OK;
584 }
585
586 /**************************************************************************
587 * CDrivesFolder::GetUIObjectOf
588 *
589 * PARAMETERS
590 * hwndOwner [in] Parent window for any output
591 * cidl [in] array size
592 * apidl [in] simple pidl array
593 * riid [in] Requested Interface
594 * prgfInOut [ ] reserved
595 * ppvObject [out] Resulting Interface
596 *
597 */
598 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
599 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
600 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
601 {
602 LPVOID pObj = NULL;
603 HRESULT hr = E_INVALIDARG;
604
605 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
606 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
607
608 if (!ppvOut)
609 return hr;
610
611 *ppvOut = NULL;
612
613 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
614 {
615 if (_ILIsDrive(apidl[0]))
616 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
617 else
618 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
619 }
620 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
621 {
622 hr = IDataObject_Constructor (hwndOwner,
623 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
624 }
625 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
626 {
627 if (_ILIsDrive(apidl[0]))
628 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
629 else
630 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
631 }
632 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
633 {
634 CComPtr<IShellFolder> psfChild;
635 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
636 if (FAILED_UNEXPECTEDLY(hr))
637 return hr;
638
639 return psfChild->CreateViewObject(NULL, riid, ppvOut);
640 }
641 else
642 hr = E_NOINTERFACE;
643
644 if (SUCCEEDED(hr) && !pObj)
645 hr = E_OUTOFMEMORY;
646
647 *ppvOut = pObj;
648 TRACE ("(%p)->hr=0x%08x\n", this, hr);
649 return hr;
650 }
651
652 /**************************************************************************
653 * CDrivesFolder::GetDisplayNameOf
654 */
655 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
656 {
657 LPWSTR pszPath;
658 HRESULT hr = S_OK;
659
660 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
661 pdump (pidl);
662
663 if (!strRet)
664 return E_INVALIDARG;
665
666 if (!_ILIsPidlSimple (pidl))
667 {
668 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
669 }
670 else if (_ILIsSpecialFolder(pidl))
671 {
672 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
673 }
674 else if (!_ILIsDrive(pidl))
675 {
676 ERR("Wrong pidl type\n");
677 return E_INVALIDARG;
678 }
679
680 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
681 if (!pszPath)
682 return E_OUTOFMEMORY;
683
684 pszPath[0] = 0;
685
686 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
687 /* long view "lw_name (C:)" */
688 if (!(dwFlags & SHGDN_FORPARSING))
689 {
690 WCHAR wszDrive[18] = {0};
691 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
692 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
693 static const WCHAR wszCloseBracket[] = {')', 0};
694
695 lstrcpynW(wszDrive, pszPath, 4);
696 pszPath[0] = L'\0';
697 GetVolumeInformationW(wszDrive, pszPath,
698 MAX_PATH - 7,
699 &dwVolumeSerialNumber,
700 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
701 pszPath[MAX_PATH-1] = L'\0';
702 if (!wcslen(pszPath))
703 {
704 UINT DriveType, ResourceId;
705 DriveType = GetDriveTypeW(wszDrive);
706 switch(DriveType)
707 {
708 case DRIVE_FIXED:
709 ResourceId = IDS_DRIVE_FIXED;
710 break;
711 case DRIVE_REMOTE:
712 ResourceId = IDS_DRIVE_NETWORK;
713 break;
714 case DRIVE_CDROM:
715 ResourceId = IDS_DRIVE_CDROM;
716 break;
717 default:
718 ResourceId = 0;
719 }
720 if (ResourceId)
721 {
722 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
723 if (dwFileSystemFlags > MAX_PATH - 7)
724 pszPath[MAX_PATH-7] = L'\0';
725 }
726 }
727 wcscat (pszPath, wszOpenBracket);
728 wszDrive[2] = L'\0';
729 wcscat (pszPath, wszDrive);
730 wcscat (pszPath, wszCloseBracket);
731 }
732
733 if (SUCCEEDED(hr))
734 {
735 strRet->uType = STRRET_WSTR;
736 strRet->pOleStr = pszPath;
737 }
738 else
739 CoTaskMemFree(pszPath);
740
741 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
742 return hr;
743 }
744
745 /**************************************************************************
746 * CDrivesFolder::SetNameOf
747 * Changes the name of a file object or subfolder, possibly changing its item
748 * identifier in the process.
749 *
750 * PARAMETERS
751 * hwndOwner [in] Owner window for output
752 * pidl [in] simple pidl of item to change
753 * lpszName [in] the items new display name
754 * dwFlags [in] SHGNO formatting flags
755 * ppidlOut [out] simple pidl returned
756 */
757 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
758 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
759 {
760 WCHAR szName[30];
761
762 if (_ILIsDrive(pidl))
763 {
764 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
765 SetVolumeLabelW(szName, lpName);
766 if (pPidlOut)
767 *pPidlOut = _ILCreateDrive(szName);
768 return S_OK;
769 }
770
771 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
772 }
773
774 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
775 {
776 FIXME ("(%p)\n", this);
777 return E_NOTIMPL;
778 }
779
780 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
781 {
782 FIXME ("(%p)\n", this);
783 return E_NOTIMPL;
784 }
785
786 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
787 {
788 TRACE ("(%p)\n", this);
789
790 if (pSort)
791 *pSort = 0;
792 if (pDisplay)
793 *pDisplay = 0;
794 return S_OK;
795 }
796
797 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
798 {
799 TRACE ("(%p)\n", this);
800
801 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
802 return E_INVALIDARG;
803 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
804 return S_OK;
805 }
806
807 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
808 {
809 FIXME ("(%p)\n", this);
810 return E_NOTIMPL;
811 }
812
813 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
814 {
815 HRESULT hr;
816
817 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
818
819 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
820 return E_INVALIDARG;
821
822 if (!pidl)
823 {
824 psd->fmt = MyComputerSFHeader[iColumn].fmt;
825 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
826 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
827 }
828 else if (!_ILIsDrive(pidl))
829 {
830 return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
831 }
832 else
833 {
834 ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
835 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
836 UINT DriveType = GetDriveTypeA(pszDrive);
837 if (DriveType > DRIVE_RAMDISK)
838 DriveType = DRIVE_FIXED;
839
840 switch (iColumn)
841 {
842 case 0: /* name */
843 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
844 break;
845 case 1: /* type */
846 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
847 break;
848 case 2: /* total size */
849 case 3: /* free size */
850 psd->str.cStr[0] = 0x00;
851 psd->str.uType = STRRET_CSTR;
852 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0))
853 {
854 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
855 if (iColumn == 2)
856 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
857 else
858 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
859 }
860 hr = S_OK;
861 break;
862 }
863 }
864
865 return hr;
866 }
867
868 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
869 {
870 FIXME("(%p)\n", this);
871 return E_NOTIMPL;
872 }
873
874 /************************************************************************
875 * CDrivesFolder::GetClassID
876 */
877 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
878 {
879 TRACE ("(%p)\n", this);
880
881 if (!lpClassId)
882 return E_POINTER;
883
884 *lpClassId = CLSID_MyComputer;
885 return S_OK;
886 }
887
888 /************************************************************************
889 * CDrivesFolder::Initialize
890 *
891 * NOTES: it makes no sense to change the pidl
892 */
893 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
894 {
895 return S_OK;
896 }
897
898 /**************************************************************************
899 * CDrivesFolder::GetCurFolder
900 */
901 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
902 {
903 TRACE("(%p)->(%p)\n", this, pidl);
904
905 if (!pidl)
906 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
907
908 *pidl = ILClone(pidlRoot);
909 return S_OK;
910 }