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