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