[SHELL32]
[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 /**************************************************************************
334 * CDrivesFolder::GetAttributesOf
335 */
336 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
337 {
338 static const DWORD dwComputerAttributes =
339 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
340 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
341 static const DWORD dwControlPanelAttributes =
342 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
343 static const DWORD dwDriveAttributes =
344 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
345 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
346
347 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
348 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
349
350 if (cidl && !apidl)
351 return E_INVALIDARG;
352
353 if (*rgfInOut == 0)
354 *rgfInOut = ~0;
355
356 /* FIXME: always add SFGAO_CANLINK */
357 if(cidl == 0)
358 *rgfInOut &= dwComputerAttributes;
359 else
360 {
361 for (UINT i = 0; i < cidl; ++i)
362 {
363 if (_ILIsDrive(apidl[i]))
364 *rgfInOut &= dwDriveAttributes;
365 else if (_ILIsControlPanel(apidl[i]))
366 *rgfInOut &= dwControlPanelAttributes;
367 else
368 {
369 pdump(apidl[i]);
370 SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
371 }
372 }
373 }
374
375 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
376 *rgfInOut &= ~SFGAO_VALIDATE;
377
378 TRACE ("-- result=0x%08x\n", *rgfInOut);
379 return S_OK;
380 }
381
382 /**************************************************************************
383 * CDrivesFolder::GetUIObjectOf
384 *
385 * PARAMETERS
386 * hwndOwner [in] Parent window for any output
387 * cidl [in] array size
388 * apidl [in] simple pidl array
389 * riid [in] Requested Interface
390 * prgfInOut [ ] reserved
391 * ppvObject [out] Resulting Interface
392 *
393 */
394 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
395 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
396 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
397 {
398 LPITEMIDLIST pidl;
399 IUnknown *pObj = NULL;
400 HRESULT hr = E_INVALIDARG;
401
402 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
403 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
404
405 if (!ppvOut)
406 return hr;
407
408 *ppvOut = NULL;
409
410 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
411 {
412 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
413 }
414 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
415 {
416 hr = IDataObject_Constructor (hwndOwner,
417 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
418 }
419 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
420 {
421 pidl = ILCombine (pidlRoot, apidl[0]);
422 pObj = IExtractIconA_Constructor (pidl);
423 SHFree (pidl);
424 hr = S_OK;
425 }
426 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
427 {
428 pidl = ILCombine (pidlRoot, apidl[0]);
429 pObj = IExtractIconW_Constructor (pidl);
430 SHFree (pidl);
431 hr = S_OK;
432 }
433 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
434 {
435 IDropTarget * pDt = NULL;
436 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
437 pObj = pDt;
438 }
439 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
440 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
441 {
442 pidl = ILCombine (pidlRoot, apidl[0]);
443 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
444 SHFree (pidl);
445 }
446 else
447 hr = E_NOINTERFACE;
448
449 if (SUCCEEDED(hr) && !pObj)
450 hr = E_OUTOFMEMORY;
451
452 *ppvOut = pObj;
453 TRACE ("(%p)->hr=0x%08x\n", this, hr);
454 return hr;
455 }
456
457 /**************************************************************************
458 * CDrivesFolder::GetDisplayNameOf
459 */
460 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
461 {
462 LPWSTR pszPath;
463 HRESULT hr = S_OK;
464
465 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
466 pdump (pidl);
467
468 if (!strRet)
469 return E_INVALIDARG;
470
471 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
472 if (!pszPath)
473 return E_OUTOFMEMORY;
474
475 pszPath[0] = 0;
476
477 if (!pidl->mkid.cb)
478 {
479 /* parsing name like ::{...} */
480 pszPath[0] = ':';
481 pszPath[1] = ':';
482 SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
483 }
484 else if (_ILIsPidlSimple(pidl))
485 {
486 /* take names of special folders only if its only this folder */
487 if (_ILIsSpecialFolder(pidl))
488 {
489 GUID const *clsid;
490
491 clsid = _ILGetGUIDPointer (pidl);
492 if (clsid)
493 {
494 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
495 {
496 static const WCHAR clsidW[] = L"CLSID\\";
497 static const WCHAR shellfolderW[] = L"\\shellfolder";
498 static const WCHAR wantsForParsingW[] = L"WantsForParsing";
499 BOOL bWantsForParsing = FALSE;
500 WCHAR szRegPath[100];
501 LONG r;
502
503 /*
504 * We can only get a filesystem path from a shellfolder
505 * if the value WantsFORPARSING exists in
506 * CLSID\\{...}\\shellfolder
507 * exception: the MyComputer folder has this keys not
508 * but like any filesystem backed
509 * folder it needs these behaviour
510 *
511 * Get the "WantsFORPARSING" flag from the registry
512 */
513
514 wcscpy(szRegPath, clsidW);
515 SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
516 wcscat(szRegPath, shellfolderW);
517 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
518 wantsForParsingW, NULL, NULL, NULL);
519 if (r == ERROR_SUCCESS)
520 bWantsForParsing = TRUE;
521
522 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
523 bWantsForParsing)
524 {
525 /*
526 * We need the filesystem path to the destination folder
527 * Only the folder itself can know it
528 */
529 hr = SHELL32_GetDisplayNameOfChild (this, pidl,
530 dwFlags, pszPath, MAX_PATH);
531 }
532 else
533 {
534 LPWSTR p = pszPath;
535
536 /* parsing name like ::{...} */
537 p[0] = ':';
538 p[1] = ':';
539 p += 2;
540 p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
541
542 /* \:: */
543 p[0] = '\\';
544 p[1] = ':';
545 p[2] = ':';
546 p += 3;
547 SHELL32_GUIDToStringW(*clsid, p);
548 }
549 }
550 else
551 {
552 /* user friendly name */
553
554 if (_ILIsMyComputer(pidl) && sName)
555 wcscpy(pszPath, sName);
556 else
557 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
558
559 TRACE("pszPath %s\n", debugstr_w(pszPath));
560 }
561 }
562 else
563 {
564 /* append my own path */
565 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
566 }
567 }
568 else if (_ILIsDrive(pidl))
569 {
570
571 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
572 /* long view "lw_name (C:)" */
573 if (!(dwFlags & SHGDN_FORPARSING))
574 {
575 WCHAR wszDrive[18] = {0};
576 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
577 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
578 static const WCHAR wszCloseBracket[] = {')', 0};
579
580 lstrcpynW(wszDrive, pszPath, 4);
581 pszPath[0] = L'\0';
582 GetVolumeInformationW(wszDrive, pszPath,
583 MAX_PATH - 7,
584 &dwVolumeSerialNumber,
585 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
586 pszPath[MAX_PATH-1] = L'\0';
587 if (!wcslen(pszPath))
588 {
589 UINT DriveType, ResourceId;
590 DriveType = GetDriveTypeW(wszDrive);
591 switch(DriveType)
592 {
593 case DRIVE_FIXED:
594 ResourceId = IDS_DRIVE_FIXED;
595 break;
596 case DRIVE_REMOTE:
597 ResourceId = IDS_DRIVE_NETWORK;
598 break;
599 case DRIVE_CDROM:
600 ResourceId = IDS_DRIVE_CDROM;
601 break;
602 default:
603 ResourceId = 0;
604 }
605 if (ResourceId)
606 {
607 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
608 if (dwFileSystemFlags > MAX_PATH - 7)
609 pszPath[MAX_PATH-7] = L'\0';
610 }
611 }
612 wcscat (pszPath, wszOpenBracket);
613 wszDrive[2] = L'\0';
614 wcscat (pszPath, wszDrive);
615 wcscat (pszPath, wszCloseBracket);
616 }
617 }
618 else
619 {
620 /* Neither a shell namespace extension nor a drive letter. */
621 ERR("Wrong pidl type\n");
622 CoTaskMemFree(pszPath);
623 return E_INVALIDARG;
624 }
625 }
626 else
627 {
628 /* Complex pidl. Let the child folder do the work */
629 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
630 }
631
632 if (SUCCEEDED(hr))
633 {
634 strRet->uType = STRRET_WSTR;
635 strRet->pOleStr = pszPath;
636 }
637 else
638 CoTaskMemFree(pszPath);
639
640 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
641 return hr;
642 }
643
644 /**************************************************************************
645 * CDrivesFolder::SetNameOf
646 * Changes the name of a file object or subfolder, possibly changing its item
647 * identifier in the process.
648 *
649 * PARAMETERS
650 * hwndOwner [in] Owner window for output
651 * pidl [in] simple pidl of item to change
652 * lpszName [in] the items new display name
653 * dwFlags [in] SHGNO formatting flags
654 * ppidlOut [out] simple pidl returned
655 */
656 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
657 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
658 {
659 LPWSTR sName;
660 HKEY hKey;
661 UINT length;
662 WCHAR szName[30];
663
664 TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
665 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
666
667 if (_ILIsDrive(pidl))
668 {
669 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
670 SetVolumeLabelW(szName, lpName);
671 if (pPidlOut)
672 *pPidlOut = _ILCreateDrive(szName);
673 return S_OK;
674 }
675
676
677 if (pPidlOut != NULL)
678 *pPidlOut = _ILCreateMyComputer();
679
680 length = (wcslen(lpName) + 1) * sizeof(WCHAR);
681 sName = (LPWSTR)SHAlloc(length);
682
683 if (!sName)
684 return E_OUTOFMEMORY;
685
686 if (RegOpenKeyExW(HKEY_CURRENT_USER,
687 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
688 0,
689 KEY_WRITE,
690 &hKey) != ERROR_SUCCESS)
691 {
692 WARN("Error: failed to open registry key\n");
693 }
694 else
695 {
696 RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
697 RegCloseKey(hKey);
698 }
699
700 wcscpy(sName, lpName);
701 SHFree(this->sName);
702 this->sName = sName;
703 TRACE("result %s\n", debugstr_w(sName));
704 return S_OK;
705 }
706
707 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
708 {
709 FIXME ("(%p)\n", this);
710 return E_NOTIMPL;
711 }
712
713 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
714 {
715 FIXME ("(%p)\n", this);
716 return E_NOTIMPL;
717 }
718
719 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
720 {
721 TRACE ("(%p)\n", this);
722
723 if (pSort)
724 *pSort = 0;
725 if (pDisplay)
726 *pDisplay = 0;
727 return S_OK;
728 }
729
730 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
731 {
732 TRACE ("(%p)\n", this);
733
734 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
735 return E_INVALIDARG;
736 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
737 return S_OK;
738 }
739
740 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
741 {
742 FIXME ("(%p)\n", this);
743 return E_NOTIMPL;
744 }
745
746 /* FIXME: drive size >4GB is rolling over */
747 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
748 {
749 HRESULT hr;
750
751 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
752
753 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
754 return E_INVALIDARG;
755
756 if (!pidl)
757 {
758 psd->fmt = MyComputerSFHeader[iColumn].fmt;
759 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
760 psd->str.uType = STRRET_CSTR;
761 LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
762 psd->str.cStr, MAX_PATH);
763 return S_OK;
764 }
765 else
766 {
767 char szPath[MAX_PATH];
768 ULARGE_INTEGER ulBytes;
769
770 psd->str.cStr[0] = 0x00;
771 psd->str.uType = STRRET_CSTR;
772 switch (iColumn)
773 {
774 case 0: /* name */
775 hr = GetDisplayNameOf(pidl,
776 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
777 break;
778 case 1: /* type */
779 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
780 break;
781 case 2: /* total size */
782 if (_ILIsDrive(pidl))
783 {
784 _ILSimpleGetText (pidl, szPath, MAX_PATH);
785 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
786 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
787 }
788 break;
789 case 3: /* free size */
790 if (_ILIsDrive(pidl))
791 {
792 _ILSimpleGetText (pidl, szPath, MAX_PATH);
793 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
794 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
795 }
796 break;
797 }
798 hr = S_OK;
799 }
800
801 return hr;
802 }
803
804 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
805 {
806 FIXME("(%p)\n", this);
807 return E_NOTIMPL;
808 }
809
810 /************************************************************************
811 * CDrivesFolder::GetClassID
812 */
813 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
814 {
815 TRACE ("(%p)\n", this);
816
817 if (!lpClassId)
818 return E_POINTER;
819
820 *lpClassId = CLSID_MyComputer;
821 return S_OK;
822 }
823
824 /************************************************************************
825 * CDrivesFolder::Initialize
826 *
827 * NOTES: it makes no sense to change the pidl
828 */
829 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
830 {
831 TRACE ("(%p)->(%p)\n", this, pidl);
832
833 if (pidlRoot)
834 SHFree((LPVOID)pidlRoot);
835
836 pidlRoot = ILClone(pidl);
837 return S_OK;
838 }
839
840 /**************************************************************************
841 * CDrivesFolder::GetCurFolder
842 */
843 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
844 {
845 TRACE("(%p)->(%p)\n", this, pidl);
846
847 if (!pidl)
848 return E_POINTER;
849
850 *pidl = ILClone(pidlRoot);
851 return S_OK;
852 }