9262f5fed73708a37f35e4045255ff22c7cd047a
[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 /***********************************************************************
39 * IShellFolder implementation
40 */
41
42 HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf,
43 HWND hwnd,
44 IDataObject *pdtobj,
45 UINT uMsg,
46 WPARAM wParam,
47 LPARAM lParam)
48 {
49 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
50 return S_OK;
51
52 PIDLIST_ABSOLUTE pidlFolder;
53 PUITEMID_CHILD *apidl;
54 UINT cidl;
55 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
56 if (FAILED_UNEXPECTEDLY(hr))
57 return hr;
58
59 char szDrive[8] = {0};
60 if (!_ILGetDrive(apidl[0], szDrive, sizeof(szDrive)))
61 {
62 ERR("pidl is not a drive\n");
63 SHFree(pidlFolder);
64 _ILFreeaPidl(apidl, cidl);
65 return E_FAIL;
66 }
67
68 if (uMsg == DFM_MERGECONTEXTMENU)
69 {
70 QCMINFO *pqcminfo = (QCMINFO *)lParam;
71 DWORD dwFlags;
72
73 if (GetVolumeInformationA(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0))
74 {
75 /* Disable format if read only */
76 if (!(dwFlags & FILE_READ_ONLY_VOLUME) && GetDriveTypeA(szDrive) != DRIVE_REMOTE)
77 {
78 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
79 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
80 }
81 }
82 }
83 else if (uMsg == DFM_INVOKECOMMAND)
84 {
85 if(wParam == 0x7ABC)
86 {
87 SHFormatDrive(hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
88 }
89 else if (wParam == DFM_CMD_PROPERTIES)
90 {
91 WCHAR wszBuf[4];
92 wcscpy(wszBuf, L"A:\\");
93 wszBuf[0] = (WCHAR)szDrive[0];
94 if (!SH_ShowDriveProperties(wszBuf, pidlFolder, apidl))
95 hr = E_FAIL;
96 }
97 }
98
99 SHFree(pidlFolder);
100 _ILFreeaPidl(apidl, cidl);
101
102 return hr;
103 }
104
105 HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
106 HWND hwnd,
107 UINT cidl,
108 PCUITEMID_CHILD_ARRAY apidl,
109 IShellFolder *psf,
110 IContextMenu **ppcm)
111 {
112 HKEY hKeys[2];
113 UINT cKeys = 0;
114 AddClassKeyToArray(L"Drive", hKeys, &cKeys);
115 AddClassKeyToArray(L"Folder", hKeys, &cKeys);
116
117 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
118 }
119
120 HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
121 {
122 CComPtr<IDefaultExtractIconInit> initIcon;
123 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
124 if (FAILED_UNEXPECTEDLY(hr))
125 return hr;
126
127 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
128 WCHAR wTemp[MAX_PATH];
129 int icon_idx = -1;
130
131 if (pszDrive)
132 {
133 switch(GetDriveTypeA(pszDrive))
134 {
135 case DRIVE_REMOVABLE:
136 icon_idx = IDI_SHELL_3_14_FLOPPY;
137 break;
138 case DRIVE_CDROM:
139 icon_idx = IDI_SHELL_CDROM;
140 break;
141 case DRIVE_REMOTE:
142 icon_idx = IDI_SHELL_NETDRIVE;
143 break;
144 case DRIVE_RAMDISK:
145 icon_idx = IDI_SHELL_RAMDISK;
146 break;
147 case DRIVE_NO_ROOT_DIR:
148 icon_idx = IDI_SHELL_CDROM;
149 break;
150 }
151 }
152
153 if (icon_idx != -1)
154 {
155 initIcon->SetNormalIcon(swShell32Name, -icon_idx);
156 }
157 else
158 {
159 if (HCR_GetIconW(L"Drive", wTemp, NULL, MAX_PATH, &icon_idx))
160 initIcon->SetNormalIcon(wTemp, icon_idx);
161 else
162 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DRIVE);
163 }
164
165 return initIcon->QueryInterface(riid, ppvOut);
166 }
167
168 class CDrivesFolderEnum :
169 public CEnumIDListBase
170 {
171 public:
172 CDrivesFolderEnum();
173 ~CDrivesFolderEnum();
174 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
175 BOOL CreateMyCompEnumList(DWORD dwFlags);
176
177 BEGIN_COM_MAP(CDrivesFolderEnum)
178 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
179 END_COM_MAP()
180 };
181
182 /***********************************************************************
183 * IShellFolder [MyComputer] implementation
184 */
185
186 static const shvheader MyComputerSFHeader[] = {
187 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
188 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
189 {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
190 {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
191 };
192
193 #define MYCOMPUTERSHELLVIEWCOLUMNS 4
194
195 static const DWORD dwComputerAttributes =
196 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
197 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
198 static const DWORD dwControlPanelAttributes =
199 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
200 static const DWORD dwDriveAttributes =
201 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
202 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
203
204 CDrivesFolderEnum::CDrivesFolderEnum()
205 {
206 }
207
208 CDrivesFolderEnum::~CDrivesFolderEnum()
209 {
210 }
211
212 HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
213 {
214 if (CreateMyCompEnumList(dwFlags) == FALSE)
215 return E_FAIL;
216
217 return S_OK;
218 }
219
220 /**************************************************************************
221 * CDrivesFolderEnum::CreateMyCompEnumList()
222 */
223
224 BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
225 {
226 BOOL bRet = TRUE;
227 static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
228
229 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
230
231 /* enumerate the folders */
232 if (dwFlags & SHCONTF_FOLDERS)
233 {
234 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
235 DWORD dwDrivemap = GetLogicalDrives();
236 HKEY hKey;
237 UINT i;
238
239 while (bRet && wszDriveName[0] <= 'Z')
240 {
241 if(dwDrivemap & 0x00000001L)
242 bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
243 wszDriveName[0]++;
244 dwDrivemap = dwDrivemap >> 1;
245 }
246
247 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
248 for (i = 0; i < 2; i++)
249 {
250 if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
251 MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
252 {
253 WCHAR wszBuf[50];
254 DWORD dwSize, j = 0;
255 LONG ErrorCode;
256 LPITEMIDLIST pidl;
257
258 while (bRet)
259 {
260 dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
261 ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
262 if (ERROR_SUCCESS == ErrorCode)
263 {
264 if (wszBuf[0] != L'{')
265 {
266 dwSize = sizeof(wszBuf);
267 RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
268 }
269
270 /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
271 pidl = _ILCreateGuidFromStrW(wszBuf);
272 if (pidl != NULL)
273 bRet = AddToEnumList(pidl);
274 else
275 ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
276 j++;
277 }
278 else if (ERROR_NO_MORE_ITEMS == ErrorCode)
279 break;
280 else
281 bRet = FALSE;
282 }
283 RegCloseKey(hKey);
284 }
285 }
286 }
287 return bRet;
288 }
289
290 CDrivesFolder::CDrivesFolder()
291 {
292 pidlRoot = NULL;
293 }
294
295 CDrivesFolder::~CDrivesFolder()
296 {
297 TRACE ("-- destroying IShellFolder(%p)\n", this);
298 SHFree(pidlRoot);
299 }
300
301 HRESULT WINAPI CDrivesFolder::FinalConstruct()
302 {
303 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
304 if (pidlRoot == NULL)
305 return E_OUTOFMEMORY;
306
307 HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer,
308 pidlRoot,
309 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
310 IID_PPV_ARG(IShellFolder2, &m_regFolder));
311
312 return hr;
313 }
314
315 /**************************************************************************
316 * CDrivesFolder::ParseDisplayName
317 */
318 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
319 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
320 {
321 HRESULT hr = E_INVALIDARG;
322 LPCWSTR szNext = NULL;
323 LPITEMIDLIST pidlTemp = NULL;
324
325 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
326 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
327 pchEaten, ppidl, pdwAttributes);
328
329 *ppidl = 0;
330 if (pchEaten)
331 *pchEaten = 0; /* strange but like the original */
332
333 /* handle CLSID paths */
334 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
335 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
336
337 if (PathGetDriveNumberW(lpszDisplayName) < 0)
338 return E_INVALIDARG;
339
340 pidlTemp = _ILCreateDrive(lpszDisplayName);
341 if (!pidlTemp)
342 return E_OUTOFMEMORY;
343
344 if (lpszDisplayName[2] == L'\\')
345 {
346 szNext = &lpszDisplayName[3];
347 }
348
349 if (szNext && *szNext)
350 {
351 hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
352 (LPOLESTR) szNext, pchEaten, pdwAttributes);
353 }
354 else
355 {
356 hr = S_OK;
357 if (pdwAttributes && *pdwAttributes)
358 {
359 if (_ILIsDrive(pidlTemp))
360 *pdwAttributes &= dwDriveAttributes;
361 else if (_ILIsSpecialFolder(pidlTemp))
362 m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
363 else
364 ERR("Got an unkown pidl here!\n");
365 }
366 }
367
368 *ppidl = pidlTemp;
369
370 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
371
372 return hr;
373 }
374
375 /**************************************************************************
376 * CDrivesFolder::EnumObjects
377 */
378 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
379 {
380 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
381 }
382
383 /**************************************************************************
384 * CDrivesFolder::BindToObject
385 */
386 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
387 {
388 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
389 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
390
391 if (_ILIsSpecialFolder(pidl))
392 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
393
394 LPITEMIDLIST pidlChild = ILCloneFirst (pidl);
395 if (!pidlChild)
396 return E_OUTOFMEMORY;
397
398 CComPtr<IShellFolder> psf;
399 HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot,
400 NULL,
401 pidlChild,
402 &CLSID_ShellFSFolder,
403 -1,
404 IID_PPV_ARG(IShellFolder, &psf));
405
406 ILFree(pidlChild);
407
408 if (FAILED(hr))
409 return hr;
410
411 if (_ILIsPidlSimple (pidl))
412 {
413 return psf->QueryInterface(riid, ppvOut);
414 }
415 else
416 {
417 return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
418 }
419 }
420
421 /**************************************************************************
422 * CDrivesFolder::BindToStorage
423 */
424 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
425 {
426 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
427 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
428
429 *ppvOut = NULL;
430 return E_NOTIMPL;
431 }
432
433 /**************************************************************************
434 * CDrivesFolder::CompareIDs
435 */
436
437 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
438 {
439 HRESULT hres;
440
441 if (!pidl1 || !pidl2)
442 {
443 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
444 return E_INVALIDARG;
445 }
446
447 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
448 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
449
450 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
451 return E_INVALIDARG;
452
453 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
454 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
455
456 int result;
457 switch(LOWORD(lParam))
458 {
459 case 0: /* name */
460 {
461 result = stricmp(pszDrive1, pszDrive2);
462 hres = MAKE_COMPARE_HRESULT(result);
463 break;
464 }
465 case 1: /* Type */
466 {
467 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
468 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
469 }
470 case 2: /* Size */
471 case 3: /* Size Available */
472 {
473 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
474
475 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
476 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
477 else
478 Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
479
480 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
481 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
482 else
483 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
484
485 LARGE_INTEGER Diff;
486 if (lParam == 2) /* Size */
487 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
488 else /* Size available */
489 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
490
491 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
492 break;
493 }
494 default:
495 return E_INVALIDARG;
496 }
497
498 if (HRESULT_CODE(hres) == 0)
499 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
500
501 return hres;
502 }
503
504 /**************************************************************************
505 * CDrivesFolder::CreateViewObject
506 */
507 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
508 {
509 CComPtr<IShellView> pShellView;
510 HRESULT hr = E_INVALIDARG;
511
512 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
513 hwndOwner, shdebugstr_guid (&riid), ppvOut);
514
515 if (!ppvOut)
516 return hr;
517
518 *ppvOut = NULL;
519
520 if (IsEqualIID(riid, IID_IDropTarget))
521 {
522 WARN("IDropTarget not implemented\n");
523 hr = E_NOTIMPL;
524 }
525 else if (IsEqualIID(riid, IID_IContextMenu))
526 {
527 WARN("IContextMenu not implemented\n");
528 hr = E_NOTIMPL;
529 }
530 else if (IsEqualIID(riid, IID_IShellView))
531 {
532 hr = CDefView_Constructor(this, riid, ppvOut);
533 }
534 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
535 return hr;
536 }
537
538 static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
539 {
540 GUID *guid = _ILGetGUIDPointer(pidl);
541
542 TRACE("(%p)\n", pidl);
543
544 if (guid)
545 return IsEqualIID(*guid, CLSID_ControlPanel);
546 return FALSE;
547 }
548
549 /**************************************************************************
550 * CDrivesFolder::GetAttributesOf
551 */
552 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
553 {
554 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
555 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
556
557 if (cidl && !apidl)
558 return E_INVALIDARG;
559
560 if (*rgfInOut == 0)
561 *rgfInOut = ~0;
562
563 /* FIXME: always add SFGAO_CANLINK */
564 if(cidl == 0)
565 *rgfInOut &= dwComputerAttributes;
566 else
567 {
568 for (UINT i = 0; i < cidl; ++i)
569 {
570 if (_ILIsDrive(apidl[i]))
571 *rgfInOut &= dwDriveAttributes;
572 else if (_ILIsControlPanel(apidl[i]))
573 *rgfInOut &= dwControlPanelAttributes;
574 else if (_ILIsSpecialFolder(*apidl))
575 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
576 else
577 ERR("Got unknown pidl type!\n");
578 }
579 }
580
581 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
582 *rgfInOut &= ~SFGAO_VALIDATE;
583
584 TRACE ("-- result=0x%08x\n", *rgfInOut);
585 return S_OK;
586 }
587
588 /**************************************************************************
589 * CDrivesFolder::GetUIObjectOf
590 *
591 * PARAMETERS
592 * hwndOwner [in] Parent window for any output
593 * cidl [in] array size
594 * apidl [in] simple pidl array
595 * riid [in] Requested Interface
596 * prgfInOut [ ] reserved
597 * ppvObject [out] Resulting Interface
598 *
599 */
600 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
601 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
602 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
603 {
604 LPVOID pObj = NULL;
605 HRESULT hr = E_INVALIDARG;
606
607 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
608 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
609
610 if (!ppvOut)
611 return hr;
612
613 *ppvOut = NULL;
614
615 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
616 {
617 if (_ILIsDrive(apidl[0]))
618 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
619 else
620 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
621 }
622 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
623 {
624 hr = IDataObject_Constructor (hwndOwner,
625 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
626 }
627 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
628 {
629 if (_ILIsDrive(apidl[0]))
630 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
631 else
632 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
633 }
634 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
635 {
636 IDropTarget * pDt = NULL;
637 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
638 pObj = pDt;
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 (_ILIsSpecialFolder(pidl))
828 {
829 return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
830 }
831 else
832 {
833 char szPath[MAX_PATH];
834 ULARGE_INTEGER ulBytes;
835
836 psd->str.cStr[0] = 0x00;
837 psd->str.uType = STRRET_CSTR;
838 switch (iColumn)
839 {
840 case 0: /* name */
841 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
842 break;
843 case 1: /* type */
844 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
845 break;
846 case 2: /* total size */
847 _ILSimpleGetText (pidl, szPath, MAX_PATH);
848 if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
849 {
850 GetDiskFreeSpaceExA(szPath, NULL, &ulBytes, NULL);
851 StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
852 }
853 break;
854 case 3: /* free size */
855 _ILSimpleGetText (pidl, szPath, MAX_PATH);
856 if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
857 {
858 GetDiskFreeSpaceExA(szPath, &ulBytes, NULL, NULL);
859 StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
860 }
861 break;
862 }
863 hr = S_OK;
864 }
865
866 return hr;
867 }
868
869 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
870 {
871 FIXME("(%p)\n", this);
872 return E_NOTIMPL;
873 }
874
875 /************************************************************************
876 * CDrivesFolder::GetClassID
877 */
878 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
879 {
880 TRACE ("(%p)\n", this);
881
882 if (!lpClassId)
883 return E_POINTER;
884
885 *lpClassId = CLSID_MyComputer;
886 return S_OK;
887 }
888
889 /************************************************************************
890 * CDrivesFolder::Initialize
891 *
892 * NOTES: it makes no sense to change the pidl
893 */
894 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
895 {
896 return S_OK;
897 }
898
899 /**************************************************************************
900 * CDrivesFolder::GetCurFolder
901 */
902 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
903 {
904 TRACE("(%p)->(%p)\n", this, pidl);
905
906 if (!pidl)
907 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
908
909 *pidl = ILClone(pidlRoot);
910 return S_OK;
911 }