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