[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / folders / CDrivesFolder.cpp
1 /*
2 * Virtual Workplace folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL (shell);
26
27 /*
28 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
29 the registry. The CRegFolder is aggregated by the CDrivesFolder.
30 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
31 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
32 CDrivesFolderEnum is only responsible for returning the physical items.
33
34 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
35 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
36 */
37
38 /***********************************************************************
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 GUID *guid = _ILGetGUIDPointer(pidl);
336
337 TRACE("(%p)\n", pidl);
338
339 if (guid)
340 return IsEqualIID(*guid, 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 if (_ILIsSpecialFolder(*apidl))
379 SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
380 else
381 ERR("Got unknown pidl type!\n");
382 }
383 }
384
385 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
386 *rgfInOut &= ~SFGAO_VALIDATE;
387
388 TRACE ("-- result=0x%08x\n", *rgfInOut);
389 return S_OK;
390 }
391
392 /**************************************************************************
393 * CDrivesFolder::GetUIObjectOf
394 *
395 * PARAMETERS
396 * hwndOwner [in] Parent window for any output
397 * cidl [in] array size
398 * apidl [in] simple pidl array
399 * riid [in] Requested Interface
400 * prgfInOut [ ] reserved
401 * ppvObject [out] Resulting Interface
402 *
403 */
404 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
405 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
406 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
407 {
408 LPITEMIDLIST pidl;
409 IUnknown *pObj = NULL;
410 HRESULT hr = E_INVALIDARG;
411
412 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
413 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
414
415 if (!ppvOut)
416 return hr;
417
418 *ppvOut = NULL;
419
420 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
421 {
422 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
423 }
424 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
425 {
426 hr = IDataObject_Constructor (hwndOwner,
427 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
428 }
429 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
430 {
431 pidl = ILCombine (pidlRoot, apidl[0]);
432 pObj = IExtractIconA_Constructor (pidl);
433 SHFree (pidl);
434 hr = S_OK;
435 }
436 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
437 {
438 pidl = ILCombine (pidlRoot, apidl[0]);
439 pObj = IExtractIconW_Constructor (pidl);
440 SHFree (pidl);
441 hr = S_OK;
442 }
443 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
444 {
445 IDropTarget * pDt = NULL;
446 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
447 pObj = pDt;
448 }
449 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
450 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
451 {
452 pidl = ILCombine (pidlRoot, apidl[0]);
453 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
454 SHFree (pidl);
455 }
456 else
457 hr = E_NOINTERFACE;
458
459 if (SUCCEEDED(hr) && !pObj)
460 hr = E_OUTOFMEMORY;
461
462 *ppvOut = pObj;
463 TRACE ("(%p)->hr=0x%08x\n", this, hr);
464 return hr;
465 }
466
467 /**************************************************************************
468 * CDrivesFolder::GetDisplayNameOf
469 */
470 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
471 {
472 LPWSTR pszPath;
473 HRESULT hr = S_OK;
474
475 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
476 pdump (pidl);
477
478 if (!strRet)
479 return E_INVALIDARG;
480
481 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
482 if (!pszPath)
483 return E_OUTOFMEMORY;
484
485 pszPath[0] = 0;
486
487 if (!pidl->mkid.cb)
488 {
489 /* parsing name like ::{...} */
490 pszPath[0] = ':';
491 pszPath[1] = ':';
492 SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
493 }
494 else if (_ILIsPidlSimple(pidl))
495 {
496 /* take names of special folders only if its only this folder */
497 if (_ILIsSpecialFolder(pidl))
498 {
499 GUID const *clsid;
500
501 clsid = _ILGetGUIDPointer (pidl);
502 if (clsid)
503 {
504 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
505 {
506 static const WCHAR clsidW[] = L"CLSID\\";
507 static const WCHAR shellfolderW[] = L"\\shellfolder";
508 static const WCHAR wantsForParsingW[] = L"WantsForParsing";
509 BOOL bWantsForParsing = FALSE;
510 WCHAR szRegPath[100];
511 LONG r;
512
513 /*
514 * We can only get a filesystem path from a shellfolder
515 * if the value WantsFORPARSING exists in
516 * CLSID\\{...}\\shellfolder
517 * exception: the MyComputer folder has this keys not
518 * but like any filesystem backed
519 * folder it needs these behaviour
520 *
521 * Get the "WantsFORPARSING" flag from the registry
522 */
523
524 wcscpy(szRegPath, clsidW);
525 SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
526 wcscat(szRegPath, shellfolderW);
527 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
528 wantsForParsingW, NULL, NULL, NULL);
529 if (r == ERROR_SUCCESS)
530 bWantsForParsing = TRUE;
531
532 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
533 bWantsForParsing)
534 {
535 /*
536 * We need the filesystem path to the destination folder
537 * Only the folder itself can know it
538 */
539 hr = SHELL32_GetDisplayNameOfChild (this, pidl,
540 dwFlags, pszPath, MAX_PATH);
541 }
542 else
543 {
544 LPWSTR p = pszPath;
545
546 /* parsing name like ::{...} */
547 p[0] = ':';
548 p[1] = ':';
549 p += 2;
550 p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
551
552 /* \:: */
553 p[0] = '\\';
554 p[1] = ':';
555 p[2] = ':';
556 p += 3;
557 SHELL32_GUIDToStringW(*clsid, p);
558 }
559 }
560 else
561 {
562 /* user friendly name */
563
564 if (_ILIsMyComputer(pidl) && sName)
565 wcscpy(pszPath, sName);
566 else
567 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
568
569 TRACE("pszPath %s\n", debugstr_w(pszPath));
570 }
571 }
572 else
573 {
574 /* append my own path */
575 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
576 }
577 }
578 else if (_ILIsDrive(pidl))
579 {
580
581 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
582 /* long view "lw_name (C:)" */
583 if (!(dwFlags & SHGDN_FORPARSING))
584 {
585 WCHAR wszDrive[18] = {0};
586 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
587 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
588 static const WCHAR wszCloseBracket[] = {')', 0};
589
590 lstrcpynW(wszDrive, pszPath, 4);
591 pszPath[0] = L'\0';
592 GetVolumeInformationW(wszDrive, pszPath,
593 MAX_PATH - 7,
594 &dwVolumeSerialNumber,
595 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
596 pszPath[MAX_PATH-1] = L'\0';
597 if (!wcslen(pszPath))
598 {
599 UINT DriveType, ResourceId;
600 DriveType = GetDriveTypeW(wszDrive);
601 switch(DriveType)
602 {
603 case DRIVE_FIXED:
604 ResourceId = IDS_DRIVE_FIXED;
605 break;
606 case DRIVE_REMOTE:
607 ResourceId = IDS_DRIVE_NETWORK;
608 break;
609 case DRIVE_CDROM:
610 ResourceId = IDS_DRIVE_CDROM;
611 break;
612 default:
613 ResourceId = 0;
614 }
615 if (ResourceId)
616 {
617 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
618 if (dwFileSystemFlags > MAX_PATH - 7)
619 pszPath[MAX_PATH-7] = L'\0';
620 }
621 }
622 wcscat (pszPath, wszOpenBracket);
623 wszDrive[2] = L'\0';
624 wcscat (pszPath, wszDrive);
625 wcscat (pszPath, wszCloseBracket);
626 }
627 }
628 else
629 {
630 /* Neither a shell namespace extension nor a drive letter. */
631 ERR("Wrong pidl type\n");
632 CoTaskMemFree(pszPath);
633 return E_INVALIDARG;
634 }
635 }
636 else
637 {
638 /* Complex pidl. Let the child folder do the work */
639 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
640 }
641
642 if (SUCCEEDED(hr))
643 {
644 strRet->uType = STRRET_WSTR;
645 strRet->pOleStr = pszPath;
646 }
647 else
648 CoTaskMemFree(pszPath);
649
650 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
651 return hr;
652 }
653
654 /**************************************************************************
655 * CDrivesFolder::SetNameOf
656 * Changes the name of a file object or subfolder, possibly changing its item
657 * identifier in the process.
658 *
659 * PARAMETERS
660 * hwndOwner [in] Owner window for output
661 * pidl [in] simple pidl of item to change
662 * lpszName [in] the items new display name
663 * dwFlags [in] SHGNO formatting flags
664 * ppidlOut [out] simple pidl returned
665 */
666 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
667 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
668 {
669 LPWSTR sName;
670 HKEY hKey;
671 UINT length;
672 WCHAR szName[30];
673
674 TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
675 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
676
677 if (_ILIsDrive(pidl))
678 {
679 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
680 SetVolumeLabelW(szName, lpName);
681 if (pPidlOut)
682 *pPidlOut = _ILCreateDrive(szName);
683 return S_OK;
684 }
685
686
687 if (pPidlOut != NULL)
688 *pPidlOut = _ILCreateMyComputer();
689
690 length = (wcslen(lpName) + 1) * sizeof(WCHAR);
691 sName = (LPWSTR)SHAlloc(length);
692
693 if (!sName)
694 return E_OUTOFMEMORY;
695
696 if (RegOpenKeyExW(HKEY_CURRENT_USER,
697 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
698 0,
699 KEY_WRITE,
700 &hKey) != ERROR_SUCCESS)
701 {
702 WARN("Error: failed to open registry key\n");
703 }
704 else
705 {
706 RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
707 RegCloseKey(hKey);
708 }
709
710 wcscpy(sName, lpName);
711 SHFree(this->sName);
712 this->sName = sName;
713 TRACE("result %s\n", debugstr_w(sName));
714 return S_OK;
715 }
716
717 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
718 {
719 FIXME ("(%p)\n", this);
720 return E_NOTIMPL;
721 }
722
723 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
724 {
725 FIXME ("(%p)\n", this);
726 return E_NOTIMPL;
727 }
728
729 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
730 {
731 TRACE ("(%p)\n", this);
732
733 if (pSort)
734 *pSort = 0;
735 if (pDisplay)
736 *pDisplay = 0;
737 return S_OK;
738 }
739
740 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
741 {
742 TRACE ("(%p)\n", this);
743
744 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
745 return E_INVALIDARG;
746 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
747 return S_OK;
748 }
749
750 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
751 {
752 FIXME ("(%p)\n", this);
753 return E_NOTIMPL;
754 }
755
756 /* FIXME: drive size >4GB is rolling over */
757 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
758 {
759 HRESULT hr;
760
761 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
762
763 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
764 return E_INVALIDARG;
765
766 if (!pidl)
767 {
768 psd->fmt = MyComputerSFHeader[iColumn].fmt;
769 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
770 psd->str.uType = STRRET_CSTR;
771 LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
772 psd->str.cStr, MAX_PATH);
773 return S_OK;
774 }
775 else
776 {
777 char szPath[MAX_PATH];
778 ULARGE_INTEGER ulBytes;
779
780 psd->str.cStr[0] = 0x00;
781 psd->str.uType = STRRET_CSTR;
782 switch (iColumn)
783 {
784 case 0: /* name */
785 hr = GetDisplayNameOf(pidl,
786 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
787 break;
788 case 1: /* type */
789 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
790 break;
791 case 2: /* total size */
792 if (_ILIsDrive(pidl))
793 {
794 _ILSimpleGetText (pidl, szPath, MAX_PATH);
795 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
796 StrFormatByteSize64A (ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
797 }
798 break;
799 case 3: /* free size */
800 if (_ILIsDrive(pidl))
801 {
802 _ILSimpleGetText (pidl, szPath, MAX_PATH);
803 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
804 StrFormatByteSize64A (ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
805 }
806 break;
807 }
808 hr = S_OK;
809 }
810
811 return hr;
812 }
813
814 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
815 {
816 FIXME("(%p)\n", this);
817 return E_NOTIMPL;
818 }
819
820 /************************************************************************
821 * CDrivesFolder::GetClassID
822 */
823 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
824 {
825 TRACE ("(%p)\n", this);
826
827 if (!lpClassId)
828 return E_POINTER;
829
830 *lpClassId = CLSID_MyComputer;
831 return S_OK;
832 }
833
834 /************************************************************************
835 * CDrivesFolder::Initialize
836 *
837 * NOTES: it makes no sense to change the pidl
838 */
839 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
840 {
841 TRACE ("(%p)->(%p)\n", this, pidl);
842
843 if (pidlRoot)
844 SHFree((LPVOID)pidlRoot);
845
846 pidlRoot = ILClone(pidl);
847 return S_OK;
848 }
849
850 /**************************************************************************
851 * CDrivesFolder::GetCurFolder
852 */
853 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
854 {
855 TRACE("(%p)->(%p)\n", this, pidl);
856
857 if (!pidl)
858 return E_POINTER;
859
860 *pidl = ILClone(pidlRoot);
861 return S_OK;
862 }