1 /*
2 * Virtual Workplace folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 * Copyright 2017-2024 Katayama Hirofumi MZ
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #include <precomp.h>
25 #include <process.h>
26
27 WINE_DEFAULT_DEBUG_CHANNEL(shell);
28
29 /*
30 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
31 the registry. The CRegFolder is aggregated by the CDrivesFolder.
32 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
33 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
34 CDrivesFolderEnum is only responsible for returning the physical items.
35
36 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
37 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
38 */
39
40 static int iDriveIconIds[7] = { IDI_SHELL_DRIVE, /* DRIVE_UNKNOWN */
41 IDI_SHELL_CDROM, /* DRIVE_NO_ROOT_DIR*/
42 IDI_SHELL_3_14_FLOPPY, /* DRIVE_REMOVABLE*/
43 IDI_SHELL_DRIVE, /* DRIVE_FIXED*/
44 IDI_SHELL_NETDRIVE, /* DRIVE_REMOTE*/
45 IDI_SHELL_CDROM, /* DRIVE_CDROM*/
46 IDI_SHELL_RAMDISK /* DRIVE_RAMDISK*/
47 };
48
49 static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */
50 IDS_DRIVE_FIXED, /* DRIVE_NO_ROOT_DIR*/
51 IDS_DRIVE_FLOPPY, /* DRIVE_REMOVABLE*/
52 IDS_DRIVE_FIXED, /* DRIVE_FIXED*/
53 IDS_DRIVE_NETWORK, /* DRIVE_REMOTE*/
54 IDS_DRIVE_CDROM, /* DRIVE_CDROM*/
55 IDS_DRIVE_FIXED /* DRIVE_RAMDISK*/
56 };
57
58 static const REQUIREDREGITEM g_RequiredItems[] =
59 {
60 { CLSID_ControlPanel, 0, 0x50 },
61 };
62 static const REGFOLDERINFO g_RegFolderInfo =
63 {
64 PT_COMPUTER_REGITEM,
65 _countof(g_RequiredItems), g_RequiredItems,
66 CLSID_MyComputer,
67 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
68 L"MyComputer",
69 };
70
IsRegItem(PCUITEMID_CHILD pidl)71 static const CLSID* IsRegItem(PCUITEMID_CHILD pidl)
72 {
73 if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID))
74 {
75 if (pidl->mkid.abID[0] == PT_SHELLEXT || pidl->mkid.abID[0] == PT_GUID) // FIXME: Remove PT_GUID when CRegFolder is fixed
76 return (const CLSID*)(&pidl->mkid.abID[2]);
77 }
78 return NULL;
79 }
80
_ILGetDriveType(LPCITEMIDLIST pidl)81 BOOL _ILGetDriveType(LPCITEMIDLIST pidl)
82 {
83 WCHAR szDrive[8];
84 if (!_ILGetDrive(pidl, szDrive, _countof(szDrive)))
85 {
86 ERR("pidl %p is not a drive\n", pidl);
87 return DRIVE_UNKNOWN;
88 }
89 return ::GetDriveTypeW(szDrive);
90 }
91
SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey,REFCLSID Clsid)92 BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Clsid)
93 {
94 // If this function returns true, the item should be hidden in DefView but not in the Explorer folder tree.
95 WCHAR path[MAX_PATH], name[CHARS_IN_GUID];
96 wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, SubKey);
97 SHELL32_GUIDToStringW(Clsid, name);
98 DWORD data = 0, size = sizeof(data);
99 return !RegGetValueW(HKEY_CURRENT_USER, path, name, RRF_RT_DWORD, NULL, &data, &size) && data;
100 }
101
102 /***********************************************************************
103 * IShellFolder implementation
104 */
105
106 #define RETRY_COUNT 3
107 #define RETRY_SLEEP 250
TryToLockOrUnlockDrive(HANDLE hDrive,BOOL bLock)108 static BOOL TryToLockOrUnlockDrive(HANDLE hDrive, BOOL bLock)
109 {
110 DWORD dwError, dwBytesReturned;
111 DWORD dwCode = (bLock ? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME);
112 for (DWORD i = 0; i < RETRY_COUNT; ++i)
113 {
114 if (DeviceIoControl(hDrive, dwCode, NULL, 0, NULL, 0, &dwBytesReturned, NULL))
115 return TRUE;
116
117 dwError = GetLastError();
118 if (dwError == ERROR_INVALID_FUNCTION)
119 break; /* don't sleep if function is not implemented */
120
121 Sleep(RETRY_SLEEP);
122 }
123 SetLastError(dwError);
124 return FALSE;
125 }
126
127 // NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp
DoEjectDrive(const WCHAR * physical,UINT nDriveType,INT * pnStringID)128 static BOOL DoEjectDrive(const WCHAR *physical, UINT nDriveType, INT *pnStringID)
129 {
130 /* GENERIC_WRITE isn't needed for umount */
131 DWORD dwAccessMode = GENERIC_READ;
132 DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
133
134 HANDLE hDrive = CreateFile(physical, dwAccessMode, dwShareMode, 0, OPEN_EXISTING, 0, NULL);
135 if (hDrive == INVALID_HANDLE_VALUE)
136 return FALSE;
137
138 BOOL bResult, bNeedUnlock = FALSE;
139 DWORD dwBytesReturned, dwError = NO_ERROR;
140 PREVENT_MEDIA_REMOVAL removal;
141 do
142 {
143 bResult = TryToLockOrUnlockDrive(hDrive, TRUE);
144 if (!bResult)
145 {
146 dwError = GetLastError();
147 *pnStringID = IDS_CANTLOCKVOLUME; /* Unable to lock volume */
148 break;
149 }
150 bResult = DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
151 if (!bResult)
152 {
153 dwError = GetLastError();
154 *pnStringID = IDS_CANTDISMOUNTVOLUME; /* Unable to dismount volume */
155 bNeedUnlock = TRUE;
156 break;
157 }
158 removal.PreventMediaRemoval = FALSE;
159 bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_MEDIA_REMOVAL, &removal, sizeof(removal), NULL,
160 0, &dwBytesReturned, NULL);
161 if (!bResult)
162 {
163 *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
164 dwError = GetLastError();
165 bNeedUnlock = TRUE;
166 break;
167 }
168 bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
169 if (!bResult)
170 {
171 *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
172 dwError = GetLastError();
173 bNeedUnlock = TRUE;
174 break;
175 }
176 } while (0);
177
178 if (bNeedUnlock)
179 {
180 TryToLockOrUnlockDrive(hDrive, FALSE);
181 }
182
183 CloseHandle(hDrive);
184
185 SetLastError(dwError);
186 return bResult;
187 }
188
DoFormatDriveThread(LPVOID args)189 static DWORD CALLBACK DoFormatDriveThread(LPVOID args)
190 {
191 UINT nDrive = PtrToUlong(args);
192 WCHAR szPath[] = { LOWORD(L'A' + nDrive), L'\0' }; // Arbitrary, just needs to include nDrive
193 CStubWindow32 stub;
194 HRESULT hr = stub.CreateStub(CStubWindow32::TYPE_FORMATDRIVE, szPath, NULL);
195 if (FAILED(hr))
196 return hr;
197 SHFormatDrive(stub, nDrive, SHFMT_ID_DEFAULT, 0);
198 return stub.DestroyWindow();
199 }
200
DoFormatDriveAsync(HWND hwnd,UINT nDrive)201 static HRESULT DoFormatDriveAsync(HWND hwnd, UINT nDrive)
202 {
203 BOOL succ = SHCreateThread(DoFormatDriveThread, UlongToPtr(nDrive), CTF_PROCESS_REF, NULL);
204 return succ ? S_OK : E_FAIL;
205 }
206
DrivesContextMenuCallback(IShellFolder * psf,HWND hwnd,IDataObject * pdtobj,UINT uMsg,WPARAM wParam,LPARAM lParam)207 HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf,
208 HWND hwnd,
209 IDataObject *pdtobj,
210 UINT uMsg,
211 WPARAM wParam,
212 LPARAM lParam)
213 {
214 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
215 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg);
216
217 PIDLIST_ABSOLUTE pidlFolder;
218 PUITEMID_CHILD *apidl;
219 UINT cidl;
220 UINT nDriveType;
221 DWORD dwFlags;
222 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
223 if (FAILED_UNEXPECTEDLY(hr))
224 return hr;
225
226 WCHAR szDrive[8] = {0};
227 if (!_ILGetDrive(apidl[0], szDrive, _countof(szDrive)))
228 {
229 ERR("pidl is not a drive\n");
230 SHFree(pidlFolder);
231 _ILFreeaPidl(apidl, cidl);
232 return E_FAIL;
233 }
234 nDriveType = GetDriveTypeW(szDrive);
235 GetVolumeInformationW(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0);
236
237 // custom command IDs
238 #if 0 // Disabled until our menu building system is fixed
239 #define CMDID_FORMAT 0
240 #define CMDID_EJECT 1
241 #define CMDID_DISCONNECT 2
242 #else
243 /* FIXME: These IDs should start from 0, however there is difference
244 * between ours and Windows' menu building systems, which should be fixed. */
245 #define CMDID_FORMAT 1
246 #define CMDID_EJECT 2
247 #define CMDID_DISCONNECT 3
248 #endif
249
250 if (uMsg == DFM_MERGECONTEXTMENU)
251 {
252 QCMINFO *pqcminfo = (QCMINFO *)lParam;
253
254 UINT idCmdFirst = pqcminfo->idCmdFirst;
255 UINT idCmd = 0;
256 if (!(dwFlags & FILE_READ_ONLY_VOLUME) && nDriveType != DRIVE_REMOTE)
257 {
258 /* add separator and Format */
259 idCmd = idCmdFirst + CMDID_FORMAT;
260 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
261 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
262 }
263 if (nDriveType == DRIVE_REMOVABLE || nDriveType == DRIVE_CDROM)
264 {
265 /* add separator and Eject */
266 idCmd = idCmdFirst + CMDID_EJECT;
267 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
268 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_EJECT), MFS_ENABLED);
269 }
270 if (nDriveType == DRIVE_REMOTE)
271 {
272 /* add separator and Disconnect */
273 idCmd = idCmdFirst + CMDID_DISCONNECT;
274 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
275 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_DISCONNECT), MFS_ENABLED);
276 }
277
278 if (idCmd)
279 #if 0 // see FIXME above
280 pqcminfo->idCmdFirst = ++idCmd;
281 #else
282 pqcminfo->idCmdFirst = (idCmd + 2);
283 #endif
284 hr = S_OK;
285 }
286 else if (uMsg == DFM_INVOKECOMMAND)
287 {
288 WCHAR wszBuf[4] = L"A:\\";
289 wszBuf[0] = (WCHAR)szDrive[0];
290
291 INT nStringID = 0;
292 DWORD dwError = NO_ERROR;
293
294 if (wParam == DFM_CMD_PROPERTIES)
295 {
296 ATLASSERT(pdtobj);
297 hr = SHELL32_ShowFilesystemItemPropertiesDialogAsync(pdtobj);
298 // Not setting nStringID because SHOpenPropSheet already displayed an error box
299 }
300 else
301 {
302 if (wParam == CMDID_FORMAT)
303 {
304 hr = DoFormatDriveAsync(hwnd, szDrive[0] - 'A');
305 }
306 else if (wParam == CMDID_EJECT)
307 {
308 /* do eject */
309 WCHAR physical[10];
310 wsprintfW(physical, _T("\\\\.\\%c:"), szDrive[0]);
311
312 if (DoEjectDrive(physical, nDriveType, &nStringID))
313 {
314 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
315 }
316 else
317 {
318 dwError = GetLastError();
319 }
320 }
321 else if (wParam == CMDID_DISCONNECT)
322 {
323 /* do disconnect */
324 wszBuf[2] = UNICODE_NULL;
325 dwError = WNetCancelConnection2W(wszBuf, 0, FALSE);
326 if (dwError == NO_ERROR)
327 {
328 SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
329 }
330 else
331 {
332 nStringID = IDS_CANTDISCONNECT;
333 }
334 }
335 }
336
337 if (nStringID != 0)
338 {
339 /* show error message */
340 WCHAR szFormat[128], szMessage[128];
341 LoadStringW(shell32_hInstance, nStringID, szFormat, _countof(szFormat));
342 wsprintfW(szMessage, szFormat, dwError);
343 MessageBoxW(hwnd, szMessage, NULL, MB_ICONERROR);
344 }
345 }
346
347 SHFree(pidlFolder);
348 _ILFreeaPidl(apidl, cidl);
349
350 return hr;
351 }
352
CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,HWND hwnd,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,IShellFolder * psf,IContextMenu ** ppcm)353 HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
354 HWND hwnd,
355 UINT cidl,
356 PCUITEMID_CHILD_ARRAY apidl,
357 IShellFolder *psf,
358 IContextMenu **ppcm)
359 {
360 HKEY hKeys[2];
361 UINT cKeys = 0;
362 AddClassKeyToArray(L"Drive", hKeys, &cKeys);
363 AddClassKeyToArray(L"Folder", hKeys, &cKeys);
364
365 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
366 }
367
368 static HRESULT
getIconLocationForDrive(IShellFolder * psf,PCITEMID_CHILD pidl,UINT uFlags,LPWSTR szIconFile,UINT cchMax,int * piIndex,UINT * pwFlags)369 getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags,
370 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
371 {
372 WCHAR wszPath[MAX_PATH];
373 WCHAR wszAutoRunInfPath[MAX_PATH];
374 WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH];
375
376 // get path
377 if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0))
378 return E_FAIL;
379 if (!PathIsDirectoryW(wszPath))
380 return E_FAIL;
381
382 // build the full path of autorun.inf
383 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath);
384 PathAppendW(wszAutoRunInfPath, L"autorun.inf");
385
386 // autorun.inf --> wszValue
387 if (GetPrivateProfileStringW(L"autorun", L"icon", NULL, wszValue, _countof(wszValue),
388 wszAutoRunInfPath) && wszValue[0] != 0)
389 {
390 // wszValue --> wszTemp
391 ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp));
392
393 // parse the icon location
394 *piIndex = PathParseIconLocationW(wszTemp);
395
396 // wszPath + wszTemp --> wszPath
397 if (PathIsRelativeW(wszTemp))
398 PathAppendW(wszPath, wszTemp);
399 else
400 StringCchCopyW(wszPath, _countof(wszPath), wszTemp);
401
402 // wszPath --> szIconFile
403 GetFullPathNameW(wszPath, cchMax, szIconFile, NULL);
404
405 return S_OK;
406 }
407
408 return E_FAIL;
409 }
410
411 static HRESULT
getLabelForDrive(LPWSTR wszPath,LPWSTR wszLabel)412 getLabelForDrive(LPWSTR wszPath, LPWSTR wszLabel)
413 {
414 WCHAR wszAutoRunInfPath[MAX_PATH];
415 WCHAR wszTemp[MAX_PATH];
416
417 if (!PathIsDirectoryW(wszPath))
418 return E_FAIL;
419
420 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath);
421 PathAppendW(wszAutoRunInfPath, L"autorun.inf");
422
423 if (GetPrivateProfileStringW(L"autorun", L"label", NULL, wszTemp, _countof(wszTemp),
424 wszAutoRunInfPath) && wszTemp[0] != 0)
425 {
426 StringCchCopyW(wszLabel, _countof(wszTemp), wszTemp);
427 return S_OK;
428 }
429
430 return E_FAIL;
431 }
432
433 BOOL IsDriveFloppyA(LPCSTR pszDriveRoot);
434
CDrivesExtractIcon_CreateInstance(IShellFolder * psf,LPCITEMIDLIST pidl,REFIID riid,LPVOID * ppvOut)435 HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
436 {
437 CComPtr<IDefaultExtractIconInit> initIcon;
438 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
439 if (FAILED_UNEXPECTEDLY(hr))
440 return hr;
441
442 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
443 UINT DriveType = GetDriveTypeA(pszDrive);
444 if (DriveType > DRIVE_RAMDISK)
445 DriveType = DRIVE_FIXED;
446
447 WCHAR wTemp[MAX_PATH];
448 int icon_idx, reg_idx;
449 UINT flags = 0;
450
451 switch (DriveType)
452 {
453 case DRIVE_FIXED:
454 case DRIVE_UNKNOWN:
455 reg_idx = IDI_SHELL_DRIVE;
456 break;
457 case DRIVE_CDROM:
458 reg_idx = IDI_SHELL_CDROM;
459 break;
460 case DRIVE_REMOTE:
461 reg_idx = IDI_SHELL_NETDRIVE;
462 break;
463 case DRIVE_REMOVABLE:
464 if (!IsDriveFloppyA(pszDrive))
465 reg_idx = IDI_SHELL_REMOVEABLE;
466 else
467 reg_idx = IDI_SHELL_3_14_FLOPPY;
468 break;
469 case DRIVE_RAMDISK:
470 reg_idx = IDI_SHELL_RAMDISK;
471 break;
472 case DRIVE_NO_ROOT_DIR:
473 default:
474 reg_idx = IDI_SHELL_DOCUMENT;
475 break;
476 }
477
478 hr = getIconLocationForDrive(psf, pidl, 0, wTemp, _countof(wTemp),
479 &icon_idx, &flags);
480 if (SUCCEEDED(hr))
481 {
482 initIcon->SetNormalIcon(wTemp, icon_idx);
483 }
484 else if (HLM_GetIconW(reg_idx - 1, wTemp, _countof(wTemp), &icon_idx))
485 {
486 initIcon->SetNormalIcon(wTemp, icon_idx);
487 }
488 else if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) &&
489 (HCR_GetIconW(L"Drive", wTemp, NULL, _countof(wTemp), &icon_idx)))
490 {
491 initIcon->SetNormalIcon(wTemp, icon_idx);
492 }
493 else
494 {
495 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive))
496 {
497 icon_idx = IDI_SHELL_REMOVEABLE;
498 }
499 else
500 {
501 icon_idx = iDriveIconIds[DriveType];
502 }
503 initIcon->SetNormalIcon(swShell32Name, -icon_idx);
504 }
505
506 return initIcon->QueryInterface(riid, ppvOut);
507 }
508
509 class CDrivesFolderEnum :
510 public CEnumIDListBase
511 {
512 public:
Initialize(HWND hwndOwner,DWORD dwFlags,IEnumIDList * pRegEnumerator)513 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags, IEnumIDList* pRegEnumerator)
514 {
515 /* enumerate the folders */
516 if (dwFlags & SHCONTF_FOLDERS)
517 {
518 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
519 DWORD dwDrivemap = GetLogicalDrives();
520
521 while (wszDriveName[0] <= 'Z')
522 {
523 if(dwDrivemap & 0x00000001L)
524 AddToEnumList(_ILCreateDrive(wszDriveName));
525 wszDriveName[0]++;
526 dwDrivemap = dwDrivemap >> 1;
527 }
528 }
529
530 /* Enumerate the items of the reg folder */
531 AppendItemsFromEnumerator(pRegEnumerator);
532
533 return S_OK;
534 }
535
536 BEGIN_COM_MAP(CDrivesFolderEnum)
537 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
538 END_COM_MAP()
539 };
540
541 /***********************************************************************
542 * IShellFolder [MyComputer] implementation
543 */
544
545 static const shvheader MyComputerSFHeader[] = {
546 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
547 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
548 {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
549 {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
550 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10},
551 };
552
553 static const DWORD dwComputerAttributes =
554 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
555 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
556 static const DWORD dwControlPanelAttributes =
557 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
558 static const DWORD dwDriveAttributes =
559 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
560 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
561
CDrivesFolder()562 CDrivesFolder::CDrivesFolder()
563 {
564 pidlRoot = NULL;
565 }
566
~CDrivesFolder()567 CDrivesFolder::~CDrivesFolder()
568 {
569 TRACE("-- destroying IShellFolder(%p)\n", this);
570 SHFree(pidlRoot);
571 }
572
FinalConstruct()573 HRESULT WINAPI CDrivesFolder::FinalConstruct()
574 {
575 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
576 if (pidlRoot == NULL)
577 return E_OUTOFMEMORY;
578
579 REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo };
580 HRESULT hr = CRegFolder_CreateInstance(&RegInit,
581 pidlRoot,
582 IID_PPV_ARG(IShellFolder2, &m_regFolder));
583
584 return hr;
585 }
586
587 /**************************************************************************
588 * CDrivesFolder::ParseDisplayName
589 */
ParseDisplayName(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)590 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
591 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
592 {
593 HRESULT hr = E_INVALIDARG;
594
595 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
596 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
597 pchEaten, ppidl, pdwAttributes);
598
599 if (!ppidl)
600 return hr;
601
602 *ppidl = NULL;
603
604 if (!lpszDisplayName)
605 return hr;
606
607 /* handle CLSID paths */
608 if (lpszDisplayName[0] == L':' && lpszDisplayName[1] == L':')
609 {
610 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl,
611 pdwAttributes);
612 }
613
614 if (lpszDisplayName[0] &&
615 ((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') ||
616 (L'a' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'z')) &&
617 lpszDisplayName[1] == L':' && lpszDisplayName[2] == L'\\')
618 {
619 // "C:\..."
620 WCHAR szRoot[8];
621 PathBuildRootW(szRoot, ((*lpszDisplayName - 1) & 0x1F));
622
623 if (SHIsFileSysBindCtx(pbc, NULL) != S_OK && !(BindCtx_GetMode(pbc, 0) & STGM_CREATE))
624 {
625 if (::GetDriveType(szRoot) == DRIVE_NO_ROOT_DIR)
626 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
627 }
628
629 CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateDrive(szRoot));
630 if (!pidlTemp)
631 return E_OUTOFMEMORY;
632
633 if (lpszDisplayName[3])
634 {
635 CComPtr<IShellFolder> pChildFolder;
636 hr = BindToObject(pidlTemp, pbc, IID_PPV_ARG(IShellFolder, &pChildFolder));
637 if (FAILED_UNEXPECTEDLY(hr))
638 return hr;
639
640 ULONG chEaten;
641 CComHeapPtr<ITEMIDLIST> pidlChild;
642 hr = pChildFolder->ParseDisplayName(hwndOwner, pbc, &lpszDisplayName[3], &chEaten,
643 &pidlChild, pdwAttributes);
644 if (FAILED_UNEXPECTEDLY(hr))
645 return hr;
646
647 hr = SHILCombine(pidlTemp, pidlChild, ppidl);
648 }
649 else
650 {
651 *ppidl = pidlTemp.Detach();
652 if (pdwAttributes && *pdwAttributes)
653 GetAttributesOf(1, (PCUITEMID_CHILD_ARRAY)ppidl, pdwAttributes);
654 hr = S_OK;
655 }
656 }
657
658 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr);
659
660 return hr;
661 }
662
663 /**************************************************************************
664 * CDrivesFolder::EnumObjects
665 */
EnumObjects(HWND hwndOwner,DWORD dwFlags,LPENUMIDLIST * ppEnumIDList)666 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
667 {
668 CComPtr<IEnumIDList> pRegEnumerator;
669 m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator);
670
671 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
672 }
673
674 /**************************************************************************
675 * CDrivesFolder::BindToObject
676 */
BindToObject(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)677 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
678 {
679 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
680 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
681
682 if (!pidl)
683 return E_INVALIDARG;
684
685 if (_ILIsSpecialFolder(pidl))
686 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
687
688 CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
689
690 PERSIST_FOLDER_TARGET_INFO pfti = {0};
691 pfti.dwAttributes = -1;
692 pfti.csidl = -1;
693 pfti.szTargetParsingName[0] = *pchDrive;
694 pfti.szTargetParsingName[1] = L':';
695 pfti.szTargetParsingName[2] = L'\\';
696
697 HRESULT hr = SHELL32_BindToSF(pidlRoot,
698 &pfti,
699 pidl,
700 &CLSID_ShellFSFolder,
701 riid,
702 ppvOut);
703 if (FAILED_UNEXPECTEDLY(hr))
704 return hr;
705
706 return S_OK;
707 }
708
709 /**************************************************************************
710 * CDrivesFolder::BindToStorage
711 */
BindToStorage(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)712 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
713 {
714 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
715 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
716
717 *ppvOut = NULL;
718 return E_NOTIMPL;
719 }
720
721 /**************************************************************************
722 * CDrivesFolder::CompareIDs
723 */
724
CompareIDs(LPARAM lParam,PCUIDLIST_RELATIVE pidl1,PCUIDLIST_RELATIVE pidl2)725 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
726 {
727 HRESULT hres;
728
729 if (!pidl1 || !pidl2)
730 {
731 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
732 return E_INVALIDARG;
733 }
734
735 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
736 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
737
738 UINT iColumn = LOWORD(lParam);
739 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || iColumn >= _countof(MyComputerSFHeader))
740 return E_INVALIDARG;
741
742 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
743 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
744
745 int result;
746 switch (MyComputerSFHeader[iColumn].colnameid)
747 {
748 case IDS_SHV_COLUMN_NAME:
749 {
750 result = _stricmp(pszDrive1, pszDrive2);
751 hres = MAKE_COMPARE_HRESULT(result);
752 break;
753 }
754 case IDS_SHV_COLUMN_TYPE:
755 {
756 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
757 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
758 }
759 case IDS_SHV_COLUMN_DISK_CAPACITY:
760 case IDS_SHV_COLUMN_DISK_AVAILABLE:
761 {
762 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
763
764 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
765 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
766 else
767 Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
768
769 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
770 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
771 else
772 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
773
774 LARGE_INTEGER Diff;
775 if (lParam == 3) /* Size */
776 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
777 else /* Size available */
778 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
779
780 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
781 break;
782 }
783 case IDS_SHV_COLUMN_COMMENTS:
784 hres = MAKE_COMPARE_HRESULT(0);
785 break;
786 DEFAULT_UNREACHABLE;
787 }
788
789 if (HRESULT_CODE(hres) == 0)
790 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
791
792 return hres;
793 }
794
795 /**************************************************************************
796 * CDrivesFolder::CreateViewObject
797 */
CreateViewObject(HWND hwndOwner,REFIID riid,LPVOID * ppvOut)798 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
799 {
800 CComPtr<IShellView> pShellView;
801 HRESULT hr = E_INVALIDARG;
802
803 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
804 hwndOwner, shdebugstr_guid (&riid), ppvOut);
805
806 if (!ppvOut)
807 return hr;
808
809 *ppvOut = NULL;
810
811 if (IsEqualIID(riid, IID_IDropTarget))
812 {
813 WARN("IDropTarget not implemented\n");
814 hr = E_NOTIMPL;
815 }
816 else if (IsEqualIID(riid, IID_IContextMenu))
817 {
818 DEFCONTEXTMENU dcm = { hwndOwner, this, pidlRoot, this };
819 hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
820 }
821 else if (IsEqualIID(riid, IID_IShellView))
822 {
823 SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this, NULL, static_cast<IShellFolderViewCB*>(this) };
824 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
825 }
826 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
827 return hr;
828 }
829
830 /**************************************************************************
831 * CDrivesFolder::GetAttributesOf
832 */
GetAttributesOf(UINT cidl,PCUITEMID_CHILD_ARRAY apidl,DWORD * rgfInOut)833 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
834 {
835 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
836 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
837
838 if (cidl && !apidl)
839 return E_INVALIDARG;
840
841 if (*rgfInOut == 0)
842 *rgfInOut = ~0;
843
844 /* FIXME: always add SFGAO_CANLINK */
845 if(cidl == 0)
846 *rgfInOut &= dwComputerAttributes;
847 else
848 {
849 for (UINT i = 0; i < cidl; ++i)
850 {
851 if (_ILIsDrive(apidl[i]))
852 {
853 *rgfInOut &= dwDriveAttributes;
854
855 if (_ILGetDriveType(apidl[i]) == DRIVE_CDROM)
856 *rgfInOut &= ~SFGAO_CANRENAME; // CD-ROM drive cannot rename
857 }
858 else if (_ILIsControlPanel(apidl[i]))
859 {
860 *rgfInOut &= dwControlPanelAttributes;
861 }
862 else if (_ILIsSpecialFolder(*apidl))
863 {
864 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
865 }
866 else
867 {
868 ERR("Got unknown pidl type!\n");
869 }
870 }
871 }
872
873 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
874 *rgfInOut &= ~SFGAO_VALIDATE;
875
876 TRACE("-- result=0x%08x\n", *rgfInOut);
877 return S_OK;
878 }
879
880 /**************************************************************************
881 * CDrivesFolder::GetUIObjectOf
882 *
883 * PARAMETERS
884 * hwndOwner [in] Parent window for any output
885 * cidl [in] array size
886 * apidl [in] simple pidl array
887 * riid [in] Requested Interface
888 * prgfInOut [ ] reserved
889 * ppvObject [out] Resulting Interface
890 *
891 */
GetUIObjectOf(HWND hwndOwner,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,REFIID riid,UINT * prgfInOut,LPVOID * ppvOut)892 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
893 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
894 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
895 {
896 LPVOID pObj = NULL;
897 HRESULT hr = E_INVALIDARG;
898
899 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
900 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
901
902 if (!ppvOut)
903 return hr;
904
905 *ppvOut = NULL;
906
907 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
908 {
909 if (_ILIsDrive(apidl[0]))
910 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
911 else
912 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
913 }
914 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
915 {
916 hr = IDataObject_Constructor(hwndOwner,
917 pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj);
918 }
919 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
920 {
921 if (_ILIsDrive(apidl[0]))
922 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
923 else
924 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
925 }
926 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
927 {
928 CComPtr<IShellFolder> psfChild;
929 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
930 if (FAILED_UNEXPECTEDLY(hr))
931 return hr;
932
933 return psfChild->CreateViewObject(NULL, riid, ppvOut);
934 }
935 else
936 hr = E_NOINTERFACE;
937
938 if (SUCCEEDED(hr) && !pObj)
939 hr = E_OUTOFMEMORY;
940
941 *ppvOut = pObj;
942 TRACE("(%p)->hr=0x%08x\n", this, hr);
943 return hr;
944 }
945
946 /**************************************************************************
947 * CDrivesFolder::GetDisplayNameOf
948 */
GetDisplayNameOf(PCUITEMID_CHILD pidl,DWORD dwFlags,LPSTRRET strRet)949 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
950 {
951 LPWSTR pszPath;
952 HRESULT hr = S_OK;
953
954 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
955 pdump (pidl);
956
957 if (!strRet)
958 return E_INVALIDARG;
959
960 if (!_ILIsPidlSimple (pidl))
961 {
962 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
963 }
964 else if (_ILIsSpecialFolder(pidl))
965 {
966 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
967 }
968 else if (!_ILIsDrive(pidl))
969 {
970 ERR("Wrong pidl type\n");
971 return E_INVALIDARG;
972 }
973
974 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
975 if (!pszPath)
976 return E_OUTOFMEMORY;
977
978 pszPath[0] = 0;
979
980 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
981 /* long view "lw_name (C:)" */
982 if (!(dwFlags & SHGDN_FORPARSING))
983 {
984 WCHAR wszDrive[18] = {0};
985
986 lstrcpynW(wszDrive, pszPath, 4);
987 pszPath[0] = L'\0';
988
989 if (!SUCCEEDED(getLabelForDrive(wszDrive, pszPath)))
990 {
991 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
992
993 GetVolumeInformationW(wszDrive, pszPath,
994 MAX_PATH - 7,
995 &dwVolumeSerialNumber,
996 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
997 pszPath[MAX_PATH-1] = L'\0';
998
999 if (!wcslen(pszPath))
1000 {
1001 UINT DriveType, ResourceId;
1002 DriveType = GetDriveTypeW(wszDrive);
1003
1004 switch (DriveType)
1005 {
1006 case DRIVE_FIXED:
1007 ResourceId = IDS_DRIVE_FIXED;
1008 break;
1009 case DRIVE_REMOTE:
1010 ResourceId = IDS_DRIVE_NETWORK;
1011 break;
1012 case DRIVE_CDROM:
1013 ResourceId = IDS_DRIVE_CDROM;
1014 break;
1015 default:
1016 ResourceId = 0;
1017 }
1018
1019 if (ResourceId)
1020 {
1021 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
1022 if (dwFileSystemFlags > MAX_PATH - 7)
1023 pszPath[MAX_PATH-7] = L'\0';
1024 }
1025 }
1026 }
1027 wcscat(pszPath, L" (");
1028 wszDrive[2] = L'\0';
1029 wcscat(pszPath, wszDrive);
1030 wcscat(pszPath, L")");
1031 }
1032
1033 if (SUCCEEDED(hr))
1034 {
1035 strRet->uType = STRRET_WSTR;
1036 strRet->pOleStr = pszPath;
1037 }
1038 else
1039 CoTaskMemFree(pszPath);
1040
1041 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
1042 return hr;
1043 }
1044
1045 /**************************************************************************
1046 * CDrivesFolder::SetNameOf
1047 * Changes the name of a file object or subfolder, possibly changing its item
1048 * identifier in the process.
1049 *
1050 * PARAMETERS
1051 * hwndOwner [in] Owner window for output
1052 * pidl [in] simple pidl of item to change
1053 * lpszName [in] the items new display name
1054 * dwFlags [in] SHGNO formatting flags
1055 * ppidlOut [out] simple pidl returned
1056 */
SetNameOf(HWND hwndOwner,PCUITEMID_CHILD pidl,LPCOLESTR lpName,DWORD dwFlags,PITEMID_CHILD * pPidlOut)1057 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
1058 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
1059 {
1060 WCHAR szName[30];
1061
1062 if (_ILIsDrive(pidl))
1063 {
1064 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
1065 SetVolumeLabelW(szName, lpName);
1066 if (pPidlOut)
1067 *pPidlOut = _ILCreateDrive(szName);
1068 return S_OK;
1069 }
1070
1071 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
1072 }
1073
GetDefaultSearchGUID(GUID * pguid)1074 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
1075 {
1076 FIXME("(%p)\n", this);
1077 return E_NOTIMPL;
1078 }
1079
EnumSearches(IEnumExtraSearch ** ppenum)1080 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
1081 {
1082 FIXME("(%p)\n", this);
1083 return E_NOTIMPL;
1084 }
1085
GetDefaultColumn(DWORD dwRes,ULONG * pSort,ULONG * pDisplay)1086 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
1087 {
1088 TRACE("(%p)\n", this);
1089
1090 if (pSort)
1091 *pSort = 0;
1092 if (pDisplay)
1093 *pDisplay = 0;
1094 return S_OK;
1095 }
1096
GetDefaultColumnState(UINT iColumn,SHCOLSTATEF * pcsFlags)1097 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF * pcsFlags)
1098 {
1099 TRACE("(%p)\n", this);
1100
1101 if (!pcsFlags || iColumn >= _countof(MyComputerSFHeader))
1102 return E_INVALIDARG;
1103 *pcsFlags = MyComputerSFHeader[iColumn].colstate;
1104 return S_OK;
1105 }
1106
GetDetailsEx(PCUITEMID_CHILD pidl,const SHCOLUMNID * pscid,VARIANT * pv)1107 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
1108 {
1109 FIXME("(%p)\n", this);
1110 return E_NOTIMPL;
1111 }
1112
GetDetailsOf(PCUITEMID_CHILD pidl,UINT iColumn,SHELLDETAILS * psd)1113 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
1114 {
1115 HRESULT hr;
1116
1117 TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
1118
1119 if (!psd || iColumn >= _countof(MyComputerSFHeader))
1120 return E_INVALIDARG;
1121
1122 if (!pidl)
1123 {
1124 psd->fmt = MyComputerSFHeader[iColumn].fmt;
1125 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
1126 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
1127 }
1128 else if (!_ILIsDrive(pidl))
1129 {
1130 switch (MyComputerSFHeader[iColumn].colnameid)
1131 {
1132 case IDS_SHV_COLUMN_NAME:
1133 case IDS_SHV_COLUMN_TYPE:
1134 return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
1135 case IDS_SHV_COLUMN_DISK_CAPACITY:
1136 case IDS_SHV_COLUMN_DISK_AVAILABLE:
1137 return SHSetStrRet(&psd->str, ""); /* blank col */
1138 case IDS_SHV_COLUMN_COMMENTS:
1139 return m_regFolder->GetDetailsOf(pidl, 2, psd); /* 2 = comments */
1140 DEFAULT_UNREACHABLE;
1141 }
1142 }
1143 else
1144 {
1145 ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
1146 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
1147 UINT DriveType = GetDriveTypeA(pszDrive);
1148 if (DriveType > DRIVE_RAMDISK)
1149 DriveType = DRIVE_FIXED;
1150
1151 switch (MyComputerSFHeader[iColumn].colnameid)
1152 {
1153 case IDS_SHV_COLUMN_NAME:
1154 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
1155 break;
1156 case IDS_SHV_COLUMN_TYPE:
1157 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive))
1158 hr = SHSetStrRet(&psd->str, IDS_DRIVE_REMOVABLE);
1159 else
1160 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
1161 break;
1162 case IDS_SHV_COLUMN_DISK_CAPACITY:
1163 case IDS_SHV_COLUMN_DISK_AVAILABLE:
1164 psd->str.cStr[0] = 0x00;
1165 psd->str.uType = STRRET_CSTR;
1166 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0))
1167 {
1168 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
1169 if (iColumn == 2)
1170 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
1171 else
1172 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
1173 }
1174 hr = S_OK;
1175 break;
1176 case IDS_SHV_COLUMN_COMMENTS:
1177 hr = SHSetStrRet(&psd->str, ""); /* FIXME: comments */
1178 break;
1179 DEFAULT_UNREACHABLE;
1180 }
1181 }
1182
1183 return hr;
1184 }
1185
MapColumnToSCID(UINT column,SHCOLUMNID * pscid)1186 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
1187 {
1188 FIXME("(%p)\n", this);
1189 return E_NOTIMPL;
1190 }
1191
1192 /************************************************************************
1193 * CDrivesFolder::GetClassID
1194 */
GetClassID(CLSID * lpClassId)1195 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
1196 {
1197 TRACE("(%p)\n", this);
1198
1199 if (!lpClassId)
1200 return E_POINTER;
1201
1202 *lpClassId = CLSID_MyComputer;
1203 return S_OK;
1204 }
1205
1206 /************************************************************************
1207 * CDrivesFolder::Initialize
1208 *
1209 * NOTES: it makes no sense to change the pidl
1210 */
Initialize(PCIDLIST_ABSOLUTE pidl)1211 HRESULT WINAPI CDrivesFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
1212 {
1213 return S_OK;
1214 }
1215
1216 /**************************************************************************
1217 * CDrivesFolder::GetCurFolder
1218 */
GetCurFolder(PIDLIST_ABSOLUTE * pidl)1219 HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl)
1220 {
1221 TRACE("(%p)->(%p)\n", this, pidl);
1222
1223 if (!pidl)
1224 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
1225
1226 *pidl = ILClone(pidlRoot);
1227 return S_OK;
1228 }
1229
1230 /**************************************************************************
1231 * CDrivesFolder::ShouldShow
1232 */
ShouldShow(IShellFolder * psf,PCIDLIST_ABSOLUTE pidlFolder,PCUITEMID_CHILD pidlItem)1233 HRESULT WINAPI CDrivesFolder::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem)
1234 {
1235 if (const CLSID* pClsid = IsRegItem(pidlItem))
1236 return SHELL32_IsShellFolderNamespaceItemHidden(L"HideMyComputerIcons", *pClsid) ? S_FALSE : S_OK;
1237 return S_OK;
1238 }
1239
1240 /************************************************************************/
1241 /* IContextMenuCB interface */
1242
CallBack(IShellFolder * psf,HWND hwndOwner,IDataObject * pdtobj,UINT uMsg,WPARAM wParam,LPARAM lParam)1243 HRESULT WINAPI CDrivesFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
1244 {
1245 enum { IDC_PROPERTIES };
1246 /* no data object means no selection */
1247 if (!pdtobj)
1248 {
1249 if (uMsg == DFM_INVOKECOMMAND && wParam == IDC_PROPERTIES)
1250 {
1251 // "System" properties
1252 return SHELL_ExecuteControlPanelCPL(hwndOwner, L"sysdm.cpl") ? S_OK : E_FAIL;
1253 }
1254 else if (uMsg == DFM_MERGECONTEXTMENU) // TODO: DFM_MERGECONTEXTMENU_BOTTOM
1255 {
1256 QCMINFO *pqcminfo = (QCMINFO *)lParam;
1257 HMENU hpopup = CreatePopupMenu();
1258 _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
1259 pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
1260 DestroyMenu(hpopup);
1261 return S_OK;
1262 }
1263 }
1264 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg);
1265 }
1266