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