2 * Virtual Workplace folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 * Copyright 2017-2018 Katayama Hirofumi MZ
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.
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.
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
26 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
29 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
30 the registry. The CRegFolder is aggregated by the CDrivesFolder.
31 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
32 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
33 CDrivesFolderEnum is only responsible for returning the physical items.
35 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
36 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
39 static int iDriveIconIds
[7] = { IDI_SHELL_DRIVE
, /* DRIVE_UNKNOWN */
40 IDI_SHELL_CDROM
, /* DRIVE_NO_ROOT_DIR*/
41 IDI_SHELL_3_14_FLOPPY
, /* DRIVE_REMOVABLE*/
42 IDI_SHELL_DRIVE
, /* DRIVE_FIXED*/
43 IDI_SHELL_NETDRIVE
, /* DRIVE_REMOTE*/
44 IDI_SHELL_CDROM
, /* DRIVE_CDROM*/
45 IDI_SHELL_RAMDISK
/* DRIVE_RAMDISK*/
48 static int iDriveTypeIds
[7] = { IDS_DRIVE_FIXED
, /* DRIVE_UNKNOWN */
49 IDS_DRIVE_FIXED
, /* DRIVE_NO_ROOT_DIR*/
50 IDS_DRIVE_FLOPPY
, /* DRIVE_REMOVABLE*/
51 IDS_DRIVE_FIXED
, /* DRIVE_FIXED*/
52 IDS_DRIVE_NETWORK
, /* DRIVE_REMOTE*/
53 IDS_DRIVE_CDROM
, /* DRIVE_CDROM*/
54 IDS_DRIVE_FIXED
/* DRIVE_RAMDISK*/
57 /***********************************************************************
58 * IShellFolder implementation
62 #define RETRY_SLEEP 250
63 static BOOL
TryToLockOrUnlockDrive(HANDLE hDrive
, BOOL bLock
)
65 DWORD dwError
, dwBytesReturned
;
66 DWORD dwCode
= (bLock
? FSCTL_LOCK_VOLUME
: FSCTL_UNLOCK_VOLUME
);
67 for (DWORD i
= 0; i
< RETRY_COUNT
; ++i
)
69 if (DeviceIoControl(hDrive
, dwCode
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
))
72 dwError
= GetLastError();
73 if (dwError
== ERROR_INVALID_FUNCTION
)
74 break; /* don't sleep if function is not implemented */
78 SetLastError(dwError
);
82 // NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp
83 static BOOL
DoEjectDrive(const WCHAR
*physical
, UINT nDriveType
, INT
*pnStringID
)
85 /* GENERIC_WRITE isn't needed for umount */
86 DWORD dwAccessMode
= GENERIC_READ
;
87 DWORD dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
89 HANDLE hDrive
= CreateFile(physical
, dwAccessMode
, dwShareMode
, 0, OPEN_EXISTING
, 0, NULL
);
90 if (hDrive
== INVALID_HANDLE_VALUE
)
93 BOOL bResult
, bNeedUnlock
= FALSE
;
94 DWORD dwBytesReturned
, dwError
= NO_ERROR
;
95 PREVENT_MEDIA_REMOVAL removal
;
98 bResult
= TryToLockOrUnlockDrive(hDrive
, TRUE
);
101 dwError
= GetLastError();
102 *pnStringID
= IDS_CANTLOCKVOLUME
; /* Unable to lock volume */
105 bResult
= DeviceIoControl(hDrive
, FSCTL_DISMOUNT_VOLUME
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
);
108 dwError
= GetLastError();
109 *pnStringID
= IDS_CANTDISMOUNTVOLUME
; /* Unable to dismount volume */
113 removal
.PreventMediaRemoval
= FALSE
;
114 bResult
= DeviceIoControl(hDrive
, IOCTL_STORAGE_MEDIA_REMOVAL
, &removal
, sizeof(removal
), NULL
,
115 0, &dwBytesReturned
, NULL
);
118 *pnStringID
= IDS_CANTEJECTMEDIA
; /* Unable to eject media */
119 dwError
= GetLastError();
123 bResult
= DeviceIoControl(hDrive
, IOCTL_STORAGE_EJECT_MEDIA
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
);
126 *pnStringID
= IDS_CANTEJECTMEDIA
; /* Unable to eject media */
127 dwError
= GetLastError();
135 TryToLockOrUnlockDrive(hDrive
, FALSE
);
140 SetLastError(dwError
);
144 HRESULT CALLBACK
DrivesContextMenuCallback(IShellFolder
*psf
,
151 if (uMsg
!= DFM_MERGECONTEXTMENU
&& uMsg
!= DFM_INVOKECOMMAND
)
154 PIDLIST_ABSOLUTE pidlFolder
;
155 PUITEMID_CHILD
*apidl
;
159 HRESULT hr
= SH_GetApidlFromDataObject(pdtobj
, &pidlFolder
, &apidl
, &cidl
);
160 if (FAILED_UNEXPECTEDLY(hr
))
163 char szDrive
[8] = {0};
164 if (!_ILGetDrive(apidl
[0], szDrive
, sizeof(szDrive
)))
166 ERR("pidl is not a drive\n");
168 _ILFreeaPidl(apidl
, cidl
);
171 nDriveType
= GetDriveTypeA(szDrive
);
172 GetVolumeInformationA(szDrive
, NULL
, 0, NULL
, NULL
, &dwFlags
, NULL
, 0);
174 // custom command IDs
175 #define CMDID_FORMAT 1
176 #define CMDID_EJECT 2
177 #define CMDID_DISCONNECT 3
179 if (uMsg
== DFM_MERGECONTEXTMENU
)
181 QCMINFO
*pqcminfo
= (QCMINFO
*)lParam
;
183 UINT idCmdFirst
= pqcminfo
->idCmdFirst
;
184 if (!(dwFlags
& FILE_READ_ONLY_VOLUME
) && nDriveType
!= DRIVE_REMOTE
)
186 /* add separator and Format */
187 UINT idCmd
= idCmdFirst
+ CMDID_FORMAT
;
188 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
189 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
191 if (nDriveType
== DRIVE_REMOVABLE
|| nDriveType
== DRIVE_CDROM
)
193 /* add separator and Eject */
194 UINT idCmd
= idCmdFirst
+ CMDID_EJECT
;
195 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
196 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_EJECT
), MFS_ENABLED
);
198 if (nDriveType
== DRIVE_REMOTE
)
200 /* add separator and Disconnect */
201 UINT idCmd
= idCmdFirst
+ CMDID_DISCONNECT
;
202 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
203 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DISCONNECT
), MFS_ENABLED
);
206 pqcminfo
->idCmdFirst
+= 3;
208 else if (uMsg
== DFM_INVOKECOMMAND
)
210 WCHAR wszBuf
[4] = L
"A:\\";
211 wszBuf
[0] = (WCHAR
)szDrive
[0];
214 DWORD dwError
= NO_ERROR
;
216 if (wParam
== DFM_CMD_PROPERTIES
)
218 hr
= SH_ShowDriveProperties(wszBuf
, pidlFolder
, apidl
);
221 dwError
= ERROR_CAN_NOT_COMPLETE
;
222 nStringID
= IDS_CANTSHOWPROPERTIES
;
227 if (wParam
== CMDID_FORMAT
)
230 DWORD dwRet
= SHFormatDrive(hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
233 case SHFMT_ERROR
: case SHFMT_CANCEL
: case SHFMT_NOFORMAT
:
238 else if (wParam
== CMDID_EJECT
)
242 wsprintfW(physical
, _T("\\\\.\\%c:"), szDrive
[0]);
244 if (DoEjectDrive(physical
, nDriveType
, &nStringID
))
246 SHChangeNotify(SHCNE_MEDIAREMOVED
, SHCNF_PATHW
| SHCNF_FLUSHNOWAIT
, wszBuf
, NULL
);
250 dwError
= GetLastError();
253 else if (wParam
== CMDID_DISCONNECT
)
256 wszBuf
[2] = UNICODE_NULL
;
257 dwError
= WNetCancelConnection2W(wszBuf
, 0, FALSE
);
258 if (dwError
== NO_ERROR
)
260 SHChangeNotify(SHCNE_DRIVEREMOVED
, SHCNF_PATHW
| SHCNF_FLUSHNOWAIT
, wszBuf
, NULL
);
264 nStringID
= IDS_CANTDISCONNECT
;
271 /* show error message */
272 WCHAR szFormat
[128], szMessage
[128];
273 LoadStringW(shell32_hInstance
, nStringID
, szFormat
, _countof(szFormat
));
274 wsprintfW(szMessage
, szFormat
, dwError
);
275 MessageBoxW(hwnd
, szMessage
, NULL
, MB_ICONERROR
);
280 _ILFreeaPidl(apidl
, cidl
);
285 HRESULT
CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder
,
288 PCUITEMID_CHILD_ARRAY apidl
,
294 AddClassKeyToArray(L
"Drive", hKeys
, &cKeys
);
295 AddClassKeyToArray(L
"Folder", hKeys
, &cKeys
);
297 return CDefFolderMenu_Create2(pidlFolder
, hwnd
, cidl
, apidl
, psf
, DrivesContextMenuCallback
, cKeys
, hKeys
, ppcm
);
301 getIconLocationForDrive(IShellFolder
*psf
, PCITEMID_CHILD pidl
, UINT uFlags
,
302 LPWSTR szIconFile
, UINT cchMax
, int *piIndex
, UINT
*pwFlags
)
304 WCHAR wszPath
[MAX_PATH
];
305 WCHAR wszAutoRunInfPath
[MAX_PATH
];
306 WCHAR wszValue
[MAX_PATH
], wszTemp
[MAX_PATH
];
307 static const WCHAR wszAutoRunInf
[] = { 'a','u','t','o','r','u','n','.','i','n','f',0 };
308 static const WCHAR wszAutoRun
[] = { 'a','u','t','o','r','u','n',0 };
311 if (!ILGetDisplayNameExW(psf
, pidl
, wszPath
, 0))
313 if (!PathIsDirectoryW(wszPath
))
316 // build the full path of autorun.inf
317 StringCchCopyW(wszAutoRunInfPath
, _countof(wszAutoRunInfPath
), wszPath
);
318 PathAppendW(wszAutoRunInfPath
, wszAutoRunInf
);
320 // autorun.inf --> wszValue
321 if (GetPrivateProfileStringW(wszAutoRun
, L
"icon", NULL
, wszValue
, _countof(wszValue
),
322 wszAutoRunInfPath
) && wszValue
[0] != 0)
324 // wszValue --> wszTemp
325 ExpandEnvironmentStringsW(wszValue
, wszTemp
, _countof(wszTemp
));
327 // parse the icon location
328 *piIndex
= PathParseIconLocationW(wszTemp
);
330 // wszPath + wszTemp --> wszPath
331 if (PathIsRelativeW(wszTemp
))
332 PathAppendW(wszPath
, wszTemp
);
334 StringCchCopyW(wszPath
, _countof(wszPath
), wszTemp
);
336 // wszPath --> szIconFile
337 GetFullPathNameW(wszPath
, cchMax
, szIconFile
, NULL
);
345 HRESULT
CDrivesExtractIcon_CreateInstance(IShellFolder
* psf
, LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
* ppvOut
)
347 CComPtr
<IDefaultExtractIconInit
> initIcon
;
348 HRESULT hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
, &initIcon
));
349 if (FAILED_UNEXPECTEDLY(hr
))
352 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
353 UINT DriveType
= GetDriveTypeA(pszDrive
);
354 if (DriveType
> DRIVE_RAMDISK
)
355 DriveType
= DRIVE_FIXED
;
357 WCHAR wTemp
[MAX_PATH
];
360 if ((DriveType
== DRIVE_FIXED
|| DriveType
== DRIVE_UNKNOWN
) &&
361 (HCR_GetIconW(L
"Drive", wTemp
, NULL
, MAX_PATH
, &icon_idx
)))
363 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
365 else if (SUCCEEDED(getIconLocationForDrive(psf
, pidl
, 0, wTemp
, _countof(wTemp
),
368 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
372 icon_idx
= iDriveIconIds
[DriveType
];
373 initIcon
->SetNormalIcon(swShell32Name
, -icon_idx
);
376 return initIcon
->QueryInterface(riid
, ppvOut
);
379 class CDrivesFolderEnum
:
380 public CEnumIDListBase
383 HRESULT WINAPI
Initialize(HWND hwndOwner
, DWORD dwFlags
, IEnumIDList
* pRegEnumerator
)
385 /* enumerate the folders */
386 if (dwFlags
& SHCONTF_FOLDERS
)
388 WCHAR wszDriveName
[] = {'A', ':', '\\', '\0'};
389 DWORD dwDrivemap
= GetLogicalDrives();
391 while (wszDriveName
[0] <= 'Z')
393 if(dwDrivemap
& 0x00000001L
)
394 AddToEnumList(_ILCreateDrive(wszDriveName
));
396 dwDrivemap
= dwDrivemap
>> 1;
400 /* Enumerate the items of the reg folder */
401 AppendItemsFromEnumerator(pRegEnumerator
);
406 BEGIN_COM_MAP(CDrivesFolderEnum
)
407 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
411 /***********************************************************************
412 * IShellFolder [MyComputer] implementation
415 static const shvheader MyComputerSFHeader
[] = {
416 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
417 {IDS_SHV_COLUMN_COMMENTS
, SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 10},
418 {IDS_SHV_COLUMN_TYPE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
419 {IDS_SHV_COLUMN_DISK_CAPACITY
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
420 {IDS_SHV_COLUMN_DISK_AVAILABLE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
423 #define MYCOMPUTERSHELLVIEWCOLUMNS 5
425 static const DWORD dwComputerAttributes
=
426 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
427 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
;
428 static const DWORD dwControlPanelAttributes
=
429 SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
| SFGAO_CANLINK
;
430 static const DWORD dwDriveAttributes
=
431 SFGAO_HASSUBFOLDER
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
|
432 SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANRENAME
| SFGAO_CANLINK
;
434 CDrivesFolder::CDrivesFolder()
439 CDrivesFolder::~CDrivesFolder()
441 TRACE ("-- destroying IShellFolder(%p)\n", this);
445 HRESULT WINAPI
CDrivesFolder::FinalConstruct()
447 pidlRoot
= _ILCreateMyComputer(); /* my qualified pidl */
448 if (pidlRoot
== NULL
)
449 return E_OUTOFMEMORY
;
451 HRESULT hr
= CRegFolder_CreateInstance(&CLSID_MyComputer
,
453 L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
455 IID_PPV_ARG(IShellFolder2
, &m_regFolder
));
460 /**************************************************************************
461 * CDrivesFolder::ParseDisplayName
463 HRESULT WINAPI
CDrivesFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
,
464 DWORD
* pchEaten
, PIDLIST_RELATIVE
* ppidl
, DWORD
* pdwAttributes
)
466 HRESULT hr
= E_INVALIDARG
;
467 LPCWSTR szNext
= NULL
;
468 LPITEMIDLIST pidlTemp
= NULL
;
470 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
471 hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
472 pchEaten
, ppidl
, pdwAttributes
);
476 *pchEaten
= 0; /* strange but like the original */
478 /* handle CLSID paths */
479 if (lpszDisplayName
[0] == ':' && lpszDisplayName
[1] == ':')
480 return m_regFolder
->ParseDisplayName(hwndOwner
, pbc
, lpszDisplayName
, pchEaten
, ppidl
, pdwAttributes
);
482 if (PathGetDriveNumberW(lpszDisplayName
) < 0)
485 pidlTemp
= _ILCreateDrive(lpszDisplayName
);
487 return E_OUTOFMEMORY
;
489 if (lpszDisplayName
[2] == L
'\\')
491 szNext
= &lpszDisplayName
[3];
494 if (szNext
&& *szNext
)
496 hr
= SHELL32_ParseNextElement (this, hwndOwner
, pbc
, &pidlTemp
,
497 (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
502 if (pdwAttributes
&& *pdwAttributes
)
504 if (_ILIsDrive(pidlTemp
))
505 *pdwAttributes
&= dwDriveAttributes
;
506 else if (_ILIsSpecialFolder(pidlTemp
))
507 m_regFolder
->GetAttributesOf(1, &pidlTemp
, pdwAttributes
);
509 ERR("Got an unkown pidl here!\n");
515 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr
);
520 /**************************************************************************
521 * CDrivesFolder::EnumObjects
523 HRESULT WINAPI
CDrivesFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
525 CComPtr
<IEnumIDList
> pRegEnumerator
;
526 m_regFolder
->EnumObjects(hwndOwner
, dwFlags
, &pRegEnumerator
);
528 return ShellObjectCreatorInit
<CDrivesFolderEnum
>(hwndOwner
, dwFlags
, pRegEnumerator
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
531 /**************************************************************************
532 * CDrivesFolder::BindToObject
534 HRESULT WINAPI
CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
536 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
537 pidl
, pbcReserved
, shdebugstr_guid(&riid
), ppvOut
);
539 if (_ILIsSpecialFolder(pidl
))
540 return m_regFolder
->BindToObject(pidl
, pbcReserved
, riid
, ppvOut
);
542 CHAR
* pchDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
544 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
545 pfti
.dwAttributes
= -1;
547 pfti
.szTargetParsingName
[0] = *pchDrive
;
548 pfti
.szTargetParsingName
[1] = L
':';
549 pfti
.szTargetParsingName
[2] = L
'\\';
551 HRESULT hr
= SHELL32_BindToSF(pidlRoot
,
554 &CLSID_ShellFSFolder
,
557 if (FAILED_UNEXPECTEDLY(hr
))
563 /**************************************************************************
564 * CDrivesFolder::BindToStorage
566 HRESULT WINAPI
CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
568 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
569 pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
575 /**************************************************************************
576 * CDrivesFolder::CompareIDs
579 HRESULT WINAPI
CDrivesFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
583 if (!pidl1
|| !pidl2
)
585 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam
, pidl1
, pidl2
);
589 if (_ILIsSpecialFolder(pidl1
) || _ILIsSpecialFolder(pidl2
))
590 return m_regFolder
->CompareIDs(lParam
, pidl1
, pidl2
);
592 if (!_ILIsDrive(pidl1
) || !_ILIsDrive(pidl2
) || LOWORD(lParam
) >= MYCOMPUTERSHELLVIEWCOLUMNS
)
595 CHAR
* pszDrive1
= _ILGetDataPointer(pidl1
)->u
.drive
.szDriveName
;
596 CHAR
* pszDrive2
= _ILGetDataPointer(pidl2
)->u
.drive
.szDriveName
;
599 switch(LOWORD(lParam
))
603 result
= stricmp(pszDrive1
, pszDrive2
);
604 hres
= MAKE_COMPARE_HRESULT(result
);
607 case 1: /* comments */
608 hres
= MAKE_COMPARE_HRESULT(0);
612 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
613 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
616 case 4: /* Size Available */
618 ULARGE_INTEGER Drive1Available
, Drive1Total
, Drive2Available
, Drive2Total
;
620 if (GetVolumeInformationA(pszDrive1
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
621 GetDiskFreeSpaceExA(pszDrive1
, &Drive1Available
, &Drive1Total
, NULL
);
623 Drive1Available
.QuadPart
= Drive1Total
.QuadPart
= 0;
625 if (GetVolumeInformationA(pszDrive2
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
626 GetDiskFreeSpaceExA(pszDrive2
, &Drive2Available
, &Drive2Total
, NULL
);
628 Drive2Available
.QuadPart
= Drive2Total
.QuadPart
= 0;
631 if (lParam
== 3) /* Size */
632 Diff
.QuadPart
= Drive1Total
.QuadPart
- Drive2Total
.QuadPart
;
633 else /* Size available */
634 Diff
.QuadPart
= Drive1Available
.QuadPart
- Drive2Available
.QuadPart
;
636 hres
= MAKE_COMPARE_HRESULT(Diff
.QuadPart
);
643 if (HRESULT_CODE(hres
) == 0)
644 return SHELL32_CompareChildren(this, lParam
, pidl1
, pidl2
);
649 /**************************************************************************
650 * CDrivesFolder::CreateViewObject
652 HRESULT WINAPI
CDrivesFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
* ppvOut
)
654 CComPtr
<IShellView
> pShellView
;
655 HRESULT hr
= E_INVALIDARG
;
657 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
658 hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
665 if (IsEqualIID(riid
, IID_IDropTarget
))
667 WARN("IDropTarget not implemented\n");
670 else if (IsEqualIID(riid
, IID_IContextMenu
))
672 WARN("IContextMenu not implemented\n");
675 else if (IsEqualIID(riid
, IID_IShellView
))
677 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this};
678 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
680 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut
);
684 static BOOL
_ILIsControlPanel(LPCITEMIDLIST pidl
)
686 GUID
*guid
= _ILGetGUIDPointer(pidl
);
688 TRACE("(%p)\n", pidl
);
691 return IsEqualIID(*guid
, CLSID_ControlPanel
);
695 /**************************************************************************
696 * CDrivesFolder::GetAttributesOf
698 HRESULT WINAPI
CDrivesFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
700 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
701 this, cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
709 /* FIXME: always add SFGAO_CANLINK */
711 *rgfInOut
&= dwComputerAttributes
;
714 for (UINT i
= 0; i
< cidl
; ++i
)
716 if (_ILIsDrive(apidl
[i
]))
717 *rgfInOut
&= dwDriveAttributes
;
718 else if (_ILIsControlPanel(apidl
[i
]))
719 *rgfInOut
&= dwControlPanelAttributes
;
720 else if (_ILIsSpecialFolder(*apidl
))
721 m_regFolder
->GetAttributesOf(1, &apidl
[i
], rgfInOut
);
723 ERR("Got unknown pidl type!\n");
727 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
728 *rgfInOut
&= ~SFGAO_VALIDATE
;
730 TRACE ("-- result=0x%08x\n", *rgfInOut
);
734 /**************************************************************************
735 * CDrivesFolder::GetUIObjectOf
738 * hwndOwner [in] Parent window for any output
739 * cidl [in] array size
740 * apidl [in] simple pidl array
741 * riid [in] Requested Interface
742 * prgfInOut [ ] reserved
743 * ppvObject [out] Resulting Interface
746 HRESULT WINAPI
CDrivesFolder::GetUIObjectOf(HWND hwndOwner
,
747 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
748 REFIID riid
, UINT
*prgfInOut
, LPVOID
*ppvOut
)
751 HRESULT hr
= E_INVALIDARG
;
753 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
754 hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
761 if (IsEqualIID (riid
, IID_IContextMenu
) && (cidl
>= 1))
763 if (_ILIsDrive(apidl
[0]))
764 hr
= CDrivesContextMenu_CreateInstance(pidlRoot
, hwndOwner
, cidl
, apidl
, static_cast<IShellFolder
*>(this), (IContextMenu
**)&pObj
);
766 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
768 else if (IsEqualIID (riid
, IID_IDataObject
) && (cidl
>= 1))
770 hr
= IDataObject_Constructor (hwndOwner
,
771 pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
773 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
775 if (_ILIsDrive(apidl
[0]))
776 hr
= CDrivesExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
778 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
780 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
== 1))
782 CComPtr
<IShellFolder
> psfChild
;
783 hr
= this->BindToObject(apidl
[0], NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
784 if (FAILED_UNEXPECTEDLY(hr
))
787 return psfChild
->CreateViewObject(NULL
, riid
, ppvOut
);
792 if (SUCCEEDED(hr
) && !pObj
)
796 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
800 /**************************************************************************
801 * CDrivesFolder::GetDisplayNameOf
803 HRESULT WINAPI
CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
808 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
814 if (!_ILIsPidlSimple (pidl
))
816 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
818 else if (_ILIsSpecialFolder(pidl
))
820 return m_regFolder
->GetDisplayNameOf(pidl
, dwFlags
, strRet
);
822 else if (!_ILIsDrive(pidl
))
824 ERR("Wrong pidl type\n");
828 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
830 return E_OUTOFMEMORY
;
834 _ILSimpleGetTextW(pidl
, pszPath
, MAX_PATH
); /* append my own path */
835 /* long view "lw_name (C:)" */
836 if (!(dwFlags
& SHGDN_FORPARSING
))
838 WCHAR wszDrive
[18] = {0};
839 DWORD dwVolumeSerialNumber
, dwMaximumComponentLength
, dwFileSystemFlags
;
840 static const WCHAR wszOpenBracket
[] = {' ', '(', 0};
841 static const WCHAR wszCloseBracket
[] = {')', 0};
843 lstrcpynW(wszDrive
, pszPath
, 4);
845 GetVolumeInformationW(wszDrive
, pszPath
,
847 &dwVolumeSerialNumber
,
848 &dwMaximumComponentLength
, &dwFileSystemFlags
, NULL
, 0);
849 pszPath
[MAX_PATH
-1] = L
'\0';
850 if (!wcslen(pszPath
))
852 UINT DriveType
, ResourceId
;
853 DriveType
= GetDriveTypeW(wszDrive
);
857 ResourceId
= IDS_DRIVE_FIXED
;
860 ResourceId
= IDS_DRIVE_NETWORK
;
863 ResourceId
= IDS_DRIVE_CDROM
;
870 dwFileSystemFlags
= LoadStringW(shell32_hInstance
, ResourceId
, pszPath
, MAX_PATH
);
871 if (dwFileSystemFlags
> MAX_PATH
- 7)
872 pszPath
[MAX_PATH
-7] = L
'\0';
875 wcscat (pszPath
, wszOpenBracket
);
877 wcscat (pszPath
, wszDrive
);
878 wcscat (pszPath
, wszCloseBracket
);
883 strRet
->uType
= STRRET_WSTR
;
884 strRet
->pOleStr
= pszPath
;
887 CoTaskMemFree(pszPath
);
889 TRACE("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
893 /**************************************************************************
894 * CDrivesFolder::SetNameOf
895 * Changes the name of a file object or subfolder, possibly changing its item
896 * identifier in the process.
899 * hwndOwner [in] Owner window for output
900 * pidl [in] simple pidl of item to change
901 * lpszName [in] the items new display name
902 * dwFlags [in] SHGNO formatting flags
903 * ppidlOut [out] simple pidl returned
905 HRESULT WINAPI
CDrivesFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
,
906 LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
910 if (_ILIsDrive(pidl
))
912 if (_ILSimpleGetTextW(pidl
, szName
, _countof(szName
)))
913 SetVolumeLabelW(szName
, lpName
);
915 *pPidlOut
= _ILCreateDrive(szName
);
919 return m_regFolder
->SetNameOf(hwndOwner
, pidl
, lpName
, dwFlags
, pPidlOut
);
922 HRESULT WINAPI
CDrivesFolder::GetDefaultSearchGUID(GUID
* pguid
)
924 FIXME ("(%p)\n", this);
928 HRESULT WINAPI
CDrivesFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
930 FIXME ("(%p)\n", this);
934 HRESULT WINAPI
CDrivesFolder::GetDefaultColumn (DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
936 TRACE ("(%p)\n", this);
945 HRESULT WINAPI
CDrivesFolder::GetDefaultColumnState(UINT iColumn
, DWORD
* pcsFlags
)
947 TRACE ("(%p)\n", this);
949 if (!pcsFlags
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
951 *pcsFlags
= MyComputerSFHeader
[iColumn
].pcsFlags
;
955 HRESULT WINAPI
CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
* pscid
, VARIANT
* pv
)
957 FIXME ("(%p)\n", this);
961 HRESULT WINAPI
CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
965 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
967 if (!psd
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
972 psd
->fmt
= MyComputerSFHeader
[iColumn
].fmt
;
973 psd
->cxChar
= MyComputerSFHeader
[iColumn
].cxChar
;
974 return SHSetStrRet(&psd
->str
, MyComputerSFHeader
[iColumn
].colnameid
);
976 else if (!_ILIsDrive(pidl
))
978 return m_regFolder
->GetDetailsOf(pidl
, iColumn
, psd
);
982 ULARGE_INTEGER ulTotalBytes
, ulFreeBytes
;
983 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
984 UINT DriveType
= GetDriveTypeA(pszDrive
);
985 if (DriveType
> DRIVE_RAMDISK
)
986 DriveType
= DRIVE_FIXED
;
991 hr
= GetDisplayNameOf(pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
993 case 1: /* FIXME: comments */
994 hr
= SHSetStrRet(&psd
->str
, "");
997 hr
= SHSetStrRet(&psd
->str
, iDriveTypeIds
[DriveType
]);
999 case 3: /* total size */
1000 case 4: /* free size */
1001 psd
->str
.cStr
[0] = 0x00;
1002 psd
->str
.uType
= STRRET_CSTR
;
1003 if (GetVolumeInformationA(pszDrive
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
1005 GetDiskFreeSpaceExA(pszDrive
, &ulFreeBytes
, &ulTotalBytes
, NULL
);
1007 StrFormatByteSize64A(ulTotalBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
1009 StrFormatByteSize64A(ulFreeBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
1019 HRESULT WINAPI
CDrivesFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
* pscid
)
1021 FIXME("(%p)\n", this);
1025 /************************************************************************
1026 * CDrivesFolder::GetClassID
1028 HRESULT WINAPI
CDrivesFolder::GetClassID(CLSID
*lpClassId
)
1030 TRACE ("(%p)\n", this);
1035 *lpClassId
= CLSID_MyComputer
;
1039 /************************************************************************
1040 * CDrivesFolder::Initialize
1042 * NOTES: it makes no sense to change the pidl
1044 HRESULT WINAPI
CDrivesFolder::Initialize(LPCITEMIDLIST pidl
)
1049 /**************************************************************************
1050 * CDrivesFolder::GetCurFolder
1052 HRESULT WINAPI
CDrivesFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
1054 TRACE("(%p)->(%p)\n", this, pidl
);
1057 return E_INVALIDARG
; /* xp doesn't have this check and crashes on NULL */
1059 *pidl
= ILClone(pidlRoot
);