2 * Virtual Workplace folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 * Copyright 2017 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 if (!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 dwError
= WNetCancelConnection2W(wszBuf
, 0, FALSE
);
257 if (dwError
== NO_ERROR
)
259 SHChangeNotify(SHCNE_DRIVEREMOVED
, SHCNF_PATHW
| SHCNF_FLUSHNOWAIT
, wszBuf
, NULL
);
263 nStringID
= IDS_CANTDISCONNECT
;
270 /* show error message */
271 WCHAR szFormat
[128], szMessage
[128];
272 LoadStringW(shell32_hInstance
, nStringID
, szFormat
, _countof(szFormat
));
273 wsprintfW(szMessage
, szFormat
, dwError
);
274 MessageBoxW(hwnd
, szMessage
, NULL
, MB_ICONERROR
);
279 _ILFreeaPidl(apidl
, cidl
);
284 HRESULT
CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder
,
287 PCUITEMID_CHILD_ARRAY apidl
,
293 AddClassKeyToArray(L
"Drive", hKeys
, &cKeys
);
294 AddClassKeyToArray(L
"Folder", hKeys
, &cKeys
);
296 return CDefFolderMenu_Create2(pidlFolder
, hwnd
, cidl
, apidl
, psf
, DrivesContextMenuCallback
, cKeys
, hKeys
, ppcm
);
299 HRESULT
CDrivesExtractIcon_CreateInstance(IShellFolder
* psf
, LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
* ppvOut
)
301 CComPtr
<IDefaultExtractIconInit
> initIcon
;
302 HRESULT hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
, &initIcon
));
303 if (FAILED_UNEXPECTEDLY(hr
))
306 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
307 UINT DriveType
= GetDriveTypeA(pszDrive
);
308 if (DriveType
> DRIVE_RAMDISK
)
309 DriveType
= DRIVE_FIXED
;
311 WCHAR wTemp
[MAX_PATH
];
313 if ((DriveType
== DRIVE_FIXED
|| DriveType
== DRIVE_UNKNOWN
) &&
314 (HCR_GetIconW(L
"Drive", wTemp
, NULL
, MAX_PATH
, &icon_idx
)))
316 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
320 icon_idx
= iDriveIconIds
[DriveType
];
321 initIcon
->SetNormalIcon(swShell32Name
, -icon_idx
);
324 return initIcon
->QueryInterface(riid
, ppvOut
);
327 class CDrivesFolderEnum
:
328 public CEnumIDListBase
331 HRESULT WINAPI
Initialize(HWND hwndOwner
, DWORD dwFlags
, IEnumIDList
* pRegEnumerator
)
333 /* enumerate the folders */
334 if (dwFlags
& SHCONTF_FOLDERS
)
336 WCHAR wszDriveName
[] = {'A', ':', '\\', '\0'};
337 DWORD dwDrivemap
= GetLogicalDrives();
339 while (wszDriveName
[0] <= 'Z')
341 if(dwDrivemap
& 0x00000001L
)
342 AddToEnumList(_ILCreateDrive(wszDriveName
));
344 dwDrivemap
= dwDrivemap
>> 1;
348 /* Enumerate the items of the reg folder */
349 AppendItemsFromEnumerator(pRegEnumerator
);
354 BEGIN_COM_MAP(CDrivesFolderEnum
)
355 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
359 /***********************************************************************
360 * IShellFolder [MyComputer] implementation
363 static const shvheader MyComputerSFHeader
[] = {
364 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
365 {IDS_SHV_COLUMN_COMMENTS
, SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 10},
366 {IDS_SHV_COLUMN_TYPE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
367 {IDS_SHV_COLUMN_DISK_CAPACITY
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
368 {IDS_SHV_COLUMN_DISK_AVAILABLE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
371 #define MYCOMPUTERSHELLVIEWCOLUMNS 5
373 static const DWORD dwComputerAttributes
=
374 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
375 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_CANLINK
;
376 static const DWORD dwControlPanelAttributes
=
377 SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
| SFGAO_CANLINK
;
378 static const DWORD dwDriveAttributes
=
379 SFGAO_HASSUBFOLDER
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
|
380 SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANRENAME
| SFGAO_CANLINK
;
382 CDrivesFolder::CDrivesFolder()
387 CDrivesFolder::~CDrivesFolder()
389 TRACE ("-- destroying IShellFolder(%p)\n", this);
393 HRESULT WINAPI
CDrivesFolder::FinalConstruct()
395 pidlRoot
= _ILCreateMyComputer(); /* my qualified pidl */
396 if (pidlRoot
== NULL
)
397 return E_OUTOFMEMORY
;
399 HRESULT hr
= CRegFolder_CreateInstance(&CLSID_MyComputer
,
401 L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
403 IID_PPV_ARG(IShellFolder2
, &m_regFolder
));
408 /**************************************************************************
409 * CDrivesFolder::ParseDisplayName
411 HRESULT WINAPI
CDrivesFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
,
412 DWORD
* pchEaten
, PIDLIST_RELATIVE
* ppidl
, DWORD
* pdwAttributes
)
414 HRESULT hr
= E_INVALIDARG
;
415 LPCWSTR szNext
= NULL
;
416 LPITEMIDLIST pidlTemp
= NULL
;
418 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
419 hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
420 pchEaten
, ppidl
, pdwAttributes
);
424 *pchEaten
= 0; /* strange but like the original */
426 /* handle CLSID paths */
427 if (lpszDisplayName
[0] == ':' && lpszDisplayName
[1] == ':')
428 return m_regFolder
->ParseDisplayName(hwndOwner
, pbc
, lpszDisplayName
, pchEaten
, ppidl
, pdwAttributes
);
430 if (PathGetDriveNumberW(lpszDisplayName
) < 0)
433 pidlTemp
= _ILCreateDrive(lpszDisplayName
);
435 return E_OUTOFMEMORY
;
437 if (lpszDisplayName
[2] == L
'\\')
439 szNext
= &lpszDisplayName
[3];
442 if (szNext
&& *szNext
)
444 hr
= SHELL32_ParseNextElement (this, hwndOwner
, pbc
, &pidlTemp
,
445 (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
450 if (pdwAttributes
&& *pdwAttributes
)
452 if (_ILIsDrive(pidlTemp
))
453 *pdwAttributes
&= dwDriveAttributes
;
454 else if (_ILIsSpecialFolder(pidlTemp
))
455 m_regFolder
->GetAttributesOf(1, &pidlTemp
, pdwAttributes
);
457 ERR("Got an unkown pidl here!\n");
463 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr
);
468 /**************************************************************************
469 * CDrivesFolder::EnumObjects
471 HRESULT WINAPI
CDrivesFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
473 CComPtr
<IEnumIDList
> pRegEnumerator
;
474 m_regFolder
->EnumObjects(hwndOwner
, dwFlags
, &pRegEnumerator
);
476 return ShellObjectCreatorInit
<CDrivesFolderEnum
>(hwndOwner
, dwFlags
, pRegEnumerator
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
479 /**************************************************************************
480 * CDrivesFolder::BindToObject
482 HRESULT WINAPI
CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
484 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
485 pidl
, pbcReserved
, shdebugstr_guid(&riid
), ppvOut
);
487 if (_ILIsSpecialFolder(pidl
))
488 return m_regFolder
->BindToObject(pidl
, pbcReserved
, riid
, ppvOut
);
490 CHAR
* pchDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
492 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
493 pfti
.dwAttributes
= -1;
495 pfti
.szTargetParsingName
[0] = *pchDrive
;
496 pfti
.szTargetParsingName
[1] = L
':';
497 pfti
.szTargetParsingName
[2] = L
'\\';
499 HRESULT hr
= SHELL32_BindToSF(pidlRoot
,
502 &CLSID_ShellFSFolder
,
505 if (FAILED_UNEXPECTEDLY(hr
))
511 /**************************************************************************
512 * CDrivesFolder::BindToStorage
514 HRESULT WINAPI
CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
516 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
517 pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
523 /**************************************************************************
524 * CDrivesFolder::CompareIDs
527 HRESULT WINAPI
CDrivesFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
531 if (!pidl1
|| !pidl2
)
533 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam
, pidl1
, pidl2
);
537 if (_ILIsSpecialFolder(pidl1
) || _ILIsSpecialFolder(pidl2
))
538 return m_regFolder
->CompareIDs(lParam
, pidl1
, pidl2
);
540 if (!_ILIsDrive(pidl1
) || !_ILIsDrive(pidl2
) || LOWORD(lParam
) >= MYCOMPUTERSHELLVIEWCOLUMNS
)
543 CHAR
* pszDrive1
= _ILGetDataPointer(pidl1
)->u
.drive
.szDriveName
;
544 CHAR
* pszDrive2
= _ILGetDataPointer(pidl2
)->u
.drive
.szDriveName
;
547 switch(LOWORD(lParam
))
551 result
= stricmp(pszDrive1
, pszDrive2
);
552 hres
= MAKE_COMPARE_HRESULT(result
);
555 case 1: /* comments */
556 hres
= MAKE_COMPARE_HRESULT(0);
560 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
561 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
564 case 4: /* Size Available */
566 ULARGE_INTEGER Drive1Available
, Drive1Total
, Drive2Available
, Drive2Total
;
568 if (GetVolumeInformationA(pszDrive1
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
569 GetDiskFreeSpaceExA(pszDrive1
, &Drive1Available
, &Drive1Total
, NULL
);
571 Drive1Available
.QuadPart
= Drive1Total
.QuadPart
= 0;
573 if (GetVolumeInformationA(pszDrive2
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
574 GetDiskFreeSpaceExA(pszDrive2
, &Drive2Available
, &Drive2Total
, NULL
);
576 Drive2Available
.QuadPart
= Drive2Total
.QuadPart
= 0;
579 if (lParam
== 3) /* Size */
580 Diff
.QuadPart
= Drive1Total
.QuadPart
- Drive2Total
.QuadPart
;
581 else /* Size available */
582 Diff
.QuadPart
= Drive1Available
.QuadPart
- Drive2Available
.QuadPart
;
584 hres
= MAKE_COMPARE_HRESULT(Diff
.QuadPart
);
591 if (HRESULT_CODE(hres
) == 0)
592 return SHELL32_CompareChildren(this, lParam
, pidl1
, pidl2
);
597 /**************************************************************************
598 * CDrivesFolder::CreateViewObject
600 HRESULT WINAPI
CDrivesFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
* ppvOut
)
602 CComPtr
<IShellView
> pShellView
;
603 HRESULT hr
= E_INVALIDARG
;
605 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
606 hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
613 if (IsEqualIID(riid
, IID_IDropTarget
))
615 WARN("IDropTarget not implemented\n");
618 else if (IsEqualIID(riid
, IID_IContextMenu
))
620 WARN("IContextMenu not implemented\n");
623 else if (IsEqualIID(riid
, IID_IShellView
))
625 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this};
626 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
628 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut
);
632 static BOOL
_ILIsControlPanel(LPCITEMIDLIST pidl
)
634 GUID
*guid
= _ILGetGUIDPointer(pidl
);
636 TRACE("(%p)\n", pidl
);
639 return IsEqualIID(*guid
, CLSID_ControlPanel
);
643 /**************************************************************************
644 * CDrivesFolder::GetAttributesOf
646 HRESULT WINAPI
CDrivesFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
648 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
649 this, cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
657 /* FIXME: always add SFGAO_CANLINK */
659 *rgfInOut
&= dwComputerAttributes
;
662 for (UINT i
= 0; i
< cidl
; ++i
)
664 if (_ILIsDrive(apidl
[i
]))
665 *rgfInOut
&= dwDriveAttributes
;
666 else if (_ILIsControlPanel(apidl
[i
]))
667 *rgfInOut
&= dwControlPanelAttributes
;
668 else if (_ILIsSpecialFolder(*apidl
))
669 m_regFolder
->GetAttributesOf(1, &apidl
[i
], rgfInOut
);
671 ERR("Got unknown pidl type!\n");
675 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
676 *rgfInOut
&= ~SFGAO_VALIDATE
;
678 TRACE ("-- result=0x%08x\n", *rgfInOut
);
682 /**************************************************************************
683 * CDrivesFolder::GetUIObjectOf
686 * hwndOwner [in] Parent window for any output
687 * cidl [in] array size
688 * apidl [in] simple pidl array
689 * riid [in] Requested Interface
690 * prgfInOut [ ] reserved
691 * ppvObject [out] Resulting Interface
694 HRESULT WINAPI
CDrivesFolder::GetUIObjectOf(HWND hwndOwner
,
695 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
696 REFIID riid
, UINT
*prgfInOut
, LPVOID
*ppvOut
)
699 HRESULT hr
= E_INVALIDARG
;
701 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
702 hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
709 if (IsEqualIID (riid
, IID_IContextMenu
) && (cidl
>= 1))
711 if (_ILIsDrive(apidl
[0]))
712 hr
= CDrivesContextMenu_CreateInstance(pidlRoot
, hwndOwner
, cidl
, apidl
, static_cast<IShellFolder
*>(this), (IContextMenu
**)&pObj
);
714 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
716 else if (IsEqualIID (riid
, IID_IDataObject
) && (cidl
>= 1))
718 hr
= IDataObject_Constructor (hwndOwner
,
719 pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
721 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
723 if (_ILIsDrive(apidl
[0]))
724 hr
= CDrivesExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
726 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
728 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
== 1))
730 CComPtr
<IShellFolder
> psfChild
;
731 hr
= this->BindToObject(apidl
[0], NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
732 if (FAILED_UNEXPECTEDLY(hr
))
735 return psfChild
->CreateViewObject(NULL
, riid
, ppvOut
);
740 if (SUCCEEDED(hr
) && !pObj
)
744 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
748 /**************************************************************************
749 * CDrivesFolder::GetDisplayNameOf
751 HRESULT WINAPI
CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
756 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
762 if (!_ILIsPidlSimple (pidl
))
764 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
766 else if (_ILIsSpecialFolder(pidl
))
768 return m_regFolder
->GetDisplayNameOf(pidl
, dwFlags
, strRet
);
770 else if (!_ILIsDrive(pidl
))
772 ERR("Wrong pidl type\n");
776 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
778 return E_OUTOFMEMORY
;
782 _ILSimpleGetTextW(pidl
, pszPath
, MAX_PATH
); /* append my own path */
783 /* long view "lw_name (C:)" */
784 if (!(dwFlags
& SHGDN_FORPARSING
))
786 WCHAR wszDrive
[18] = {0};
787 DWORD dwVolumeSerialNumber
, dwMaximumComponentLength
, dwFileSystemFlags
;
788 static const WCHAR wszOpenBracket
[] = {' ', '(', 0};
789 static const WCHAR wszCloseBracket
[] = {')', 0};
791 lstrcpynW(wszDrive
, pszPath
, 4);
793 GetVolumeInformationW(wszDrive
, pszPath
,
795 &dwVolumeSerialNumber
,
796 &dwMaximumComponentLength
, &dwFileSystemFlags
, NULL
, 0);
797 pszPath
[MAX_PATH
-1] = L
'\0';
798 if (!wcslen(pszPath
))
800 UINT DriveType
, ResourceId
;
801 DriveType
= GetDriveTypeW(wszDrive
);
805 ResourceId
= IDS_DRIVE_FIXED
;
808 ResourceId
= IDS_DRIVE_NETWORK
;
811 ResourceId
= IDS_DRIVE_CDROM
;
818 dwFileSystemFlags
= LoadStringW(shell32_hInstance
, ResourceId
, pszPath
, MAX_PATH
);
819 if (dwFileSystemFlags
> MAX_PATH
- 7)
820 pszPath
[MAX_PATH
-7] = L
'\0';
823 wcscat (pszPath
, wszOpenBracket
);
825 wcscat (pszPath
, wszDrive
);
826 wcscat (pszPath
, wszCloseBracket
);
831 strRet
->uType
= STRRET_WSTR
;
832 strRet
->pOleStr
= pszPath
;
835 CoTaskMemFree(pszPath
);
837 TRACE("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
841 /**************************************************************************
842 * CDrivesFolder::SetNameOf
843 * Changes the name of a file object or subfolder, possibly changing its item
844 * identifier in the process.
847 * hwndOwner [in] Owner window for output
848 * pidl [in] simple pidl of item to change
849 * lpszName [in] the items new display name
850 * dwFlags [in] SHGNO formatting flags
851 * ppidlOut [out] simple pidl returned
853 HRESULT WINAPI
CDrivesFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
,
854 LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
858 if (_ILIsDrive(pidl
))
860 if (_ILSimpleGetTextW(pidl
, szName
, _countof(szName
)))
861 SetVolumeLabelW(szName
, lpName
);
863 *pPidlOut
= _ILCreateDrive(szName
);
867 return m_regFolder
->SetNameOf(hwndOwner
, pidl
, lpName
, dwFlags
, pPidlOut
);
870 HRESULT WINAPI
CDrivesFolder::GetDefaultSearchGUID(GUID
* pguid
)
872 FIXME ("(%p)\n", this);
876 HRESULT WINAPI
CDrivesFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
878 FIXME ("(%p)\n", this);
882 HRESULT WINAPI
CDrivesFolder::GetDefaultColumn (DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
884 TRACE ("(%p)\n", this);
893 HRESULT WINAPI
CDrivesFolder::GetDefaultColumnState(UINT iColumn
, DWORD
* pcsFlags
)
895 TRACE ("(%p)\n", this);
897 if (!pcsFlags
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
899 *pcsFlags
= MyComputerSFHeader
[iColumn
].pcsFlags
;
903 HRESULT WINAPI
CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
* pscid
, VARIANT
* pv
)
905 FIXME ("(%p)\n", this);
909 HRESULT WINAPI
CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
913 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
915 if (!psd
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
920 psd
->fmt
= MyComputerSFHeader
[iColumn
].fmt
;
921 psd
->cxChar
= MyComputerSFHeader
[iColumn
].cxChar
;
922 return SHSetStrRet(&psd
->str
, MyComputerSFHeader
[iColumn
].colnameid
);
924 else if (!_ILIsDrive(pidl
))
926 return m_regFolder
->GetDetailsOf(pidl
, iColumn
, psd
);
930 ULARGE_INTEGER ulTotalBytes
, ulFreeBytes
;
931 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
932 UINT DriveType
= GetDriveTypeA(pszDrive
);
933 if (DriveType
> DRIVE_RAMDISK
)
934 DriveType
= DRIVE_FIXED
;
939 hr
= GetDisplayNameOf(pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
941 case 1: /* FIXME: comments */
942 hr
= SHSetStrRet(&psd
->str
, "");
945 hr
= SHSetStrRet(&psd
->str
, iDriveTypeIds
[DriveType
]);
947 case 3: /* total size */
948 case 4: /* free size */
949 psd
->str
.cStr
[0] = 0x00;
950 psd
->str
.uType
= STRRET_CSTR
;
951 if (GetVolumeInformationA(pszDrive
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
953 GetDiskFreeSpaceExA(pszDrive
, &ulFreeBytes
, &ulTotalBytes
, NULL
);
955 StrFormatByteSize64A(ulTotalBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
957 StrFormatByteSize64A(ulFreeBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
967 HRESULT WINAPI
CDrivesFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
* pscid
)
969 FIXME("(%p)\n", this);
973 /************************************************************************
974 * CDrivesFolder::GetClassID
976 HRESULT WINAPI
CDrivesFolder::GetClassID(CLSID
*lpClassId
)
978 TRACE ("(%p)\n", this);
983 *lpClassId
= CLSID_MyComputer
;
987 /************************************************************************
988 * CDrivesFolder::Initialize
990 * NOTES: it makes no sense to change the pidl
992 HRESULT WINAPI
CDrivesFolder::Initialize(LPCITEMIDLIST pidl
)
997 /**************************************************************************
998 * CDrivesFolder::GetCurFolder
1000 HRESULT WINAPI
CDrivesFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
1002 TRACE("(%p)->(%p)\n", this, pidl
);
1005 return E_INVALIDARG
; /* xp doesn't have this check and crashes on NULL */
1007 *pidl
= ILClone(pidlRoot
);