[SHELL32] -Remove IShellView_Constructor and CDefView_Constructor. Use SHCreateShellF...
[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 LPITEMIDLIST pidlChild = ILCloneFirst (pidl);
394 if (!pidlChild)
395 return E_OUTOFMEMORY;
396
397 CComPtr<IShellFolder> psf;
398 HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot,
399 NULL,
400 pidlChild,
401 &CLSID_ShellFSFolder,
402 -1,
403 IID_PPV_ARG(IShellFolder, &psf));
404
405 ILFree(pidlChild);
406
407 if (FAILED(hr))
408 return hr;
409
410 if (_ILIsPidlSimple (pidl))
411 {
412 return psf->QueryInterface(riid, ppvOut);
413 }
414 else
415 {
416 return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
417 }
418 }
419
420 /**************************************************************************
421 * CDrivesFolder::BindToStorage
422 */
423 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
424 {
425 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
426 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
427
428 *ppvOut = NULL;
429 return E_NOTIMPL;
430 }
431
432 /**************************************************************************
433 * CDrivesFolder::CompareIDs
434 */
435
436 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
437 {
438 HRESULT hres;
439
440 if (!pidl1 || !pidl2)
441 {
442 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
443 return E_INVALIDARG;
444 }
445
446 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
447 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
448
449 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
450 return E_INVALIDARG;
451
452 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
453 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
454
455 int result;
456 switch(LOWORD(lParam))
457 {
458 case 0: /* name */
459 {
460 result = stricmp(pszDrive1, pszDrive2);
461 hres = MAKE_COMPARE_HRESULT(result);
462 break;
463 }
464 case 1: /* comments */
465 hres = MAKE_COMPARE_HRESULT(0);
466 break;
467 case 2: /* Type */
468 {
469 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
470 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
471 }
472 case 3: /* Size */
473 case 4: /* Size Available */
474 {
475 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
476
477 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
478 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
479 else
480 Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
481
482 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
483 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
484 else
485 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
486
487 LARGE_INTEGER Diff;
488 if (lParam == 3) /* Size */
489 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
490 else /* Size available */
491 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
492
493 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
494 break;
495 }
496 default:
497 return E_INVALIDARG;
498 }
499
500 if (HRESULT_CODE(hres) == 0)
501 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
502
503 return hres;
504 }
505
506 /**************************************************************************
507 * CDrivesFolder::CreateViewObject
508 */
509 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
510 {
511 CComPtr<IShellView> pShellView;
512 HRESULT hr = E_INVALIDARG;
513
514 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
515 hwndOwner, shdebugstr_guid (&riid), ppvOut);
516
517 if (!ppvOut)
518 return hr;
519
520 *ppvOut = NULL;
521
522 if (IsEqualIID(riid, IID_IDropTarget))
523 {
524 WARN("IDropTarget not implemented\n");
525 hr = E_NOTIMPL;
526 }
527 else if (IsEqualIID(riid, IID_IContextMenu))
528 {
529 WARN("IContextMenu not implemented\n");
530 hr = E_NOTIMPL;
531 }
532 else if (IsEqualIID(riid, IID_IShellView))
533 {
534 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
535 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
536 }
537 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
538 return hr;
539 }
540
541 static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
542 {
543 GUID *guid = _ILGetGUIDPointer(pidl);
544
545 TRACE("(%p)\n", pidl);
546
547 if (guid)
548 return IsEqualIID(*guid, CLSID_ControlPanel);
549 return FALSE;
550 }
551
552 /**************************************************************************
553 * CDrivesFolder::GetAttributesOf
554 */
555 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
556 {
557 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
558 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
559
560 if (cidl && !apidl)
561 return E_INVALIDARG;
562
563 if (*rgfInOut == 0)
564 *rgfInOut = ~0;
565
566 /* FIXME: always add SFGAO_CANLINK */
567 if(cidl == 0)
568 *rgfInOut &= dwComputerAttributes;
569 else
570 {
571 for (UINT i = 0; i < cidl; ++i)
572 {
573 if (_ILIsDrive(apidl[i]))
574 *rgfInOut &= dwDriveAttributes;
575 else if (_ILIsControlPanel(apidl[i]))
576 *rgfInOut &= dwControlPanelAttributes;
577 else if (_ILIsSpecialFolder(*apidl))
578 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
579 else
580 ERR("Got unknown pidl type!\n");
581 }
582 }
583
584 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
585 *rgfInOut &= ~SFGAO_VALIDATE;
586
587 TRACE ("-- result=0x%08x\n", *rgfInOut);
588 return S_OK;
589 }
590
591 /**************************************************************************
592 * CDrivesFolder::GetUIObjectOf
593 *
594 * PARAMETERS
595 * hwndOwner [in] Parent window for any output
596 * cidl [in] array size
597 * apidl [in] simple pidl array
598 * riid [in] Requested Interface
599 * prgfInOut [ ] reserved
600 * ppvObject [out] Resulting Interface
601 *
602 */
603 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
604 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
605 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
606 {
607 LPVOID pObj = NULL;
608 HRESULT hr = E_INVALIDARG;
609
610 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
611 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
612
613 if (!ppvOut)
614 return hr;
615
616 *ppvOut = NULL;
617
618 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
619 {
620 if (_ILIsDrive(apidl[0]))
621 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
622 else
623 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
624 }
625 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
626 {
627 hr = IDataObject_Constructor (hwndOwner,
628 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
629 }
630 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
631 {
632 if (_ILIsDrive(apidl[0]))
633 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
634 else
635 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
636 }
637 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
638 {
639 CComPtr<IShellFolder> psfChild;
640 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
641 if (FAILED_UNEXPECTEDLY(hr))
642 return hr;
643
644 return psfChild->CreateViewObject(NULL, riid, ppvOut);
645 }
646 else
647 hr = E_NOINTERFACE;
648
649 if (SUCCEEDED(hr) && !pObj)
650 hr = E_OUTOFMEMORY;
651
652 *ppvOut = pObj;
653 TRACE ("(%p)->hr=0x%08x\n", this, hr);
654 return hr;
655 }
656
657 /**************************************************************************
658 * CDrivesFolder::GetDisplayNameOf
659 */
660 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
661 {
662 LPWSTR pszPath;
663 HRESULT hr = S_OK;
664
665 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
666 pdump (pidl);
667
668 if (!strRet)
669 return E_INVALIDARG;
670
671 if (!_ILIsPidlSimple (pidl))
672 {
673 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
674 }
675 else if (_ILIsSpecialFolder(pidl))
676 {
677 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
678 }
679 else if (!_ILIsDrive(pidl))
680 {
681 ERR("Wrong pidl type\n");
682 return E_INVALIDARG;
683 }
684
685 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
686 if (!pszPath)
687 return E_OUTOFMEMORY;
688
689 pszPath[0] = 0;
690
691 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
692 /* long view "lw_name (C:)" */
693 if (!(dwFlags & SHGDN_FORPARSING))
694 {
695 WCHAR wszDrive[18] = {0};
696 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
697 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
698 static const WCHAR wszCloseBracket[] = {')', 0};
699
700 lstrcpynW(wszDrive, pszPath, 4);
701 pszPath[0] = L'\0';
702 GetVolumeInformationW(wszDrive, pszPath,
703 MAX_PATH - 7,
704 &dwVolumeSerialNumber,
705 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
706 pszPath[MAX_PATH-1] = L'\0';
707 if (!wcslen(pszPath))
708 {
709 UINT DriveType, ResourceId;
710 DriveType = GetDriveTypeW(wszDrive);
711 switch(DriveType)
712 {
713 case DRIVE_FIXED:
714 ResourceId = IDS_DRIVE_FIXED;
715 break;
716 case DRIVE_REMOTE:
717 ResourceId = IDS_DRIVE_NETWORK;
718 break;
719 case DRIVE_CDROM:
720 ResourceId = IDS_DRIVE_CDROM;
721 break;
722 default:
723 ResourceId = 0;
724 }
725 if (ResourceId)
726 {
727 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
728 if (dwFileSystemFlags > MAX_PATH - 7)
729 pszPath[MAX_PATH-7] = L'\0';
730 }
731 }
732 wcscat (pszPath, wszOpenBracket);
733 wszDrive[2] = L'\0';
734 wcscat (pszPath, wszDrive);
735 wcscat (pszPath, wszCloseBracket);
736 }
737
738 if (SUCCEEDED(hr))
739 {
740 strRet->uType = STRRET_WSTR;
741 strRet->pOleStr = pszPath;
742 }
743 else
744 CoTaskMemFree(pszPath);
745
746 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
747 return hr;
748 }
749
750 /**************************************************************************
751 * CDrivesFolder::SetNameOf
752 * Changes the name of a file object or subfolder, possibly changing its item
753 * identifier in the process.
754 *
755 * PARAMETERS
756 * hwndOwner [in] Owner window for output
757 * pidl [in] simple pidl of item to change
758 * lpszName [in] the items new display name
759 * dwFlags [in] SHGNO formatting flags
760 * ppidlOut [out] simple pidl returned
761 */
762 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
763 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
764 {
765 WCHAR szName[30];
766
767 if (_ILIsDrive(pidl))
768 {
769 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
770 SetVolumeLabelW(szName, lpName);
771 if (pPidlOut)
772 *pPidlOut = _ILCreateDrive(szName);
773 return S_OK;
774 }
775
776 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
777 }
778
779 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
780 {
781 FIXME ("(%p)\n", this);
782 return E_NOTIMPL;
783 }
784
785 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
786 {
787 FIXME ("(%p)\n", this);
788 return E_NOTIMPL;
789 }
790
791 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
792 {
793 TRACE ("(%p)\n", this);
794
795 if (pSort)
796 *pSort = 0;
797 if (pDisplay)
798 *pDisplay = 0;
799 return S_OK;
800 }
801
802 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
803 {
804 TRACE ("(%p)\n", this);
805
806 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
807 return E_INVALIDARG;
808 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
809 return S_OK;
810 }
811
812 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
813 {
814 FIXME ("(%p)\n", this);
815 return E_NOTIMPL;
816 }
817
818 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
819 {
820 HRESULT hr;
821
822 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
823
824 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
825 return E_INVALIDARG;
826
827 if (!pidl)
828 {
829 psd->fmt = MyComputerSFHeader[iColumn].fmt;
830 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
831 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
832 }
833 else if (!_ILIsDrive(pidl))
834 {
835 return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
836 }
837 else
838 {
839 ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
840 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
841 UINT DriveType = GetDriveTypeA(pszDrive);
842 if (DriveType > DRIVE_RAMDISK)
843 DriveType = DRIVE_FIXED;
844
845 switch (iColumn)
846 {
847 case 0: /* name */
848 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
849 break;
850 case 1: /* FIXME: comments */
851 hr = SHSetStrRet(&psd->str, "");
852 break;
853 case 2: /* type */
854 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
855 break;
856 case 3: /* total size */
857 case 4: /* free size */
858 psd->str.cStr[0] = 0x00;
859 psd->str.uType = STRRET_CSTR;
860 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0))
861 {
862 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
863 if (iColumn == 2)
864 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
865 else
866 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
867 }
868 hr = S_OK;
869 break;
870 }
871 }
872
873 return hr;
874 }
875
876 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
877 {
878 FIXME("(%p)\n", this);
879 return E_NOTIMPL;
880 }
881
882 /************************************************************************
883 * CDrivesFolder::GetClassID
884 */
885 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
886 {
887 TRACE ("(%p)\n", this);
888
889 if (!lpClassId)
890 return E_POINTER;
891
892 *lpClassId = CLSID_MyComputer;
893 return S_OK;
894 }
895
896 /************************************************************************
897 * CDrivesFolder::Initialize
898 *
899 * NOTES: it makes no sense to change the pidl
900 */
901 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
902 {
903 return S_OK;
904 }
905
906 /**************************************************************************
907 * CDrivesFolder::GetCurFolder
908 */
909 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
910 {
911 TRACE("(%p)->(%p)\n", this, pidl);
912
913 if (!pidl)
914 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
915
916 *pidl = ILClone(pidlRoot);
917 return S_OK;
918 }