mirror of
https://github.com/reactos/reactos.git
synced 2025-02-28 19:32:59 +00:00
[SHELL32] Use FS compatible PIDL format for Recycle Bin items (#7532)
* [SHELL32] Use FS compatible PIDL format for Recycle Bin items This allows SHChangeNotify to handle these items and DefView will correctly update the recycle folder. CORE-18005 CORE-19239 CORE-13950 CORE-18435 CORE-18436 CORE-18437
This commit is contained in:
parent
a18424267b
commit
28399a216b
27 changed files with 1151 additions and 951 deletions
|
@ -103,6 +103,12 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto)
|
|||
return hr;
|
||||
}
|
||||
|
||||
static const CMVERBMAP g_VerbMap[] =
|
||||
{
|
||||
{ "copyaspath", IDC_COPYASPATH },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
STDMETHODIMP
|
||||
CCopyAsPathMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
|
@ -133,7 +139,8 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
|
|||
{
|
||||
TRACE("CCopyAsPathMenu::InvokeCommand(%p %p)\n", this, lpcmi);
|
||||
|
||||
if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) == IDC_COPYASPATH)
|
||||
int CmdId = SHELL_MapContextMenuVerbToCmdId(lpcmi, g_VerbMap);
|
||||
if (CmdId == IDC_COPYASPATH)
|
||||
return DoCopyAsPath(m_pDataObject);
|
||||
|
||||
return E_FAIL;
|
||||
|
@ -142,10 +149,9 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
|
|||
STDMETHODIMP
|
||||
CCopyAsPathMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
|
||||
{
|
||||
FIXME("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this,
|
||||
TRACE("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this,
|
||||
idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
|
||||
|
||||
return E_NOTIMPL;
|
||||
return SHELL_GetCommandStringImpl(idCommand, uFlags, lpszName, uMaxNameLen, g_VerbMap);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
|
|
|
@ -1318,6 +1318,7 @@ int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
|
|||
{
|
||||
for (i = 0; i < cItems; i++)
|
||||
{
|
||||
//FIXME: ILIsEqual needs absolute pidls!
|
||||
currentpidl = _PidlByItem(i);
|
||||
if (ILIsEqual(pidl, currentpidl))
|
||||
return i;
|
||||
|
@ -2848,29 +2849,35 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
|
|||
TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam);
|
||||
|
||||
if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE)
|
||||
{
|
||||
SHChangeNotification_Unlock(hLock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Translate child IDLs.
|
||||
// SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes)
|
||||
lEvent &= ~SHCNE_INTERRUPT;
|
||||
HRESULT hr;
|
||||
PITEMID_CHILD child0 = NULL, child1 = NULL;
|
||||
CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp;
|
||||
if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
|
||||
if (lEvent != SHCNE_UPDATEIMAGE && lEvent < SHCNE_EXTENDED_EVENT)
|
||||
{
|
||||
child0 = ILFindLastID(Pidls[0]);
|
||||
hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
|
||||
if (SUCCEEDED(hr))
|
||||
child0 = pidl0Temp;
|
||||
}
|
||||
if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
|
||||
{
|
||||
child1 = ILFindLastID(Pidls[1]);
|
||||
hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
|
||||
if (SUCCEEDED(hr))
|
||||
child1 = pidl1Temp;
|
||||
if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
|
||||
{
|
||||
child0 = ILFindLastID(Pidls[0]);
|
||||
hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
|
||||
if (SUCCEEDED(hr))
|
||||
child0 = pidl0Temp;
|
||||
}
|
||||
if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
|
||||
{
|
||||
child1 = ILFindLastID(Pidls[1]);
|
||||
hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
|
||||
if (SUCCEEDED(hr))
|
||||
child1 = pidl1Temp;
|
||||
}
|
||||
}
|
||||
|
||||
lEvent &= ~SHCNE_INTERRUPT;
|
||||
switch (lEvent)
|
||||
{
|
||||
case SHCNE_MKDIR:
|
||||
|
|
|
@ -84,6 +84,25 @@ UINT MapVerbToDfmCmd(_In_ LPCSTR verba)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
MapVerbToCmdId(PVOID Verb, BOOL IsUnicode, IContextMenu *pCM, UINT idFirst, UINT idLast)
|
||||
{
|
||||
const UINT gcs = IsUnicode ? GCS_VERBW : GCS_VERBA;
|
||||
for (UINT id = idFirst; id <= idLast; ++id)
|
||||
{
|
||||
WCHAR buf[MAX_PATH];
|
||||
*buf = UNICODE_NULL;
|
||||
HRESULT hr = pCM->GetCommandString(id, gcs, NULL, (LPSTR)buf, _countof(buf));
|
||||
if (FAILED(hr) || !*buf)
|
||||
continue;
|
||||
else if (IsUnicode && !_wcsicmp((LPWSTR)Verb, buf))
|
||||
return id;
|
||||
else if (!IsUnicode && !lstrcmpiA((LPSTR)Verb, (LPSTR)buf))
|
||||
return id;
|
||||
}
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
static inline bool IsVerbListSeparator(WCHAR Ch)
|
||||
{
|
||||
return Ch == L' ' || Ch == L','; // learn.microsoft.com/en-us/windows/win32/shell/context-menu-handlers
|
||||
|
@ -738,7 +757,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
|||
return cIds;
|
||||
}
|
||||
|
||||
void WINAPI _InsertMenuItemW(
|
||||
BOOL WINAPI _InsertMenuItemW(
|
||||
HMENU hMenu,
|
||||
UINT indexMenu,
|
||||
BOOL fByPosition,
|
||||
|
@ -764,7 +783,7 @@ void WINAPI _InsertMenuItemW(
|
|||
else
|
||||
{
|
||||
ERR("failed to load string %p\n", dwTypeData);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -774,7 +793,7 @@ void WINAPI _InsertMenuItemW(
|
|||
|
||||
mii.wID = wID;
|
||||
mii.fType = fType;
|
||||
InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
|
||||
return InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1212,6 +1231,18 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
|||
}
|
||||
}
|
||||
|
||||
for (POSITION it = m_DynamicEntries.GetHeadPosition(); it != NULL;)
|
||||
{
|
||||
DynamicShellEntry& entry = m_DynamicEntries.GetNext(it);
|
||||
if (!entry.NumIds)
|
||||
continue;
|
||||
HRESULT hr = ::MapVerbToCmdId(Verb, IsUnicode, entry.pCM, 0, entry.NumIds - 1);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*idCmd = m_iIdSHEFirst + entry.iIdCmdFirst + hr;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,13 +91,7 @@ CFolderItemVerbs::~CFolderItemVerbs()
|
|||
|
||||
HRESULT CFolderItemVerbs::Init(LPITEMIDLIST idlist)
|
||||
{
|
||||
CComPtr<IShellFolder> folder;
|
||||
LPCITEMIDLIST child;
|
||||
HRESULT hr = SHBindToParent(idlist, IID_PPV_ARG(IShellFolder, &folder), &child);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
hr = folder->GetUIObjectOf(NULL, 1, &child, IID_IContextMenu, NULL, (PVOID*)&m_contextmenu);
|
||||
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &m_contextmenu));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
|
|
|
@ -1250,6 +1250,11 @@ VOID COpenWithMenu::AddApp(PVOID pApp)
|
|||
m_idCmdLast++;
|
||||
}
|
||||
|
||||
static const CMVERBMAP g_VerbMap[] = {
|
||||
{ "openas", 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
HRESULT WINAPI COpenWithMenu::QueryContextMenu(
|
||||
HMENU hMenu,
|
||||
UINT indexMenu,
|
||||
|
@ -1328,14 +1333,19 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu(
|
|||
HRESULT WINAPI
|
||||
COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
|
||||
{
|
||||
const SIZE_T idChooseApp = m_idCmdLast;
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
TRACE("This %p idFirst %u idLast %u idCmd %u\n", this, m_idCmdFirst, m_idCmdLast, m_idCmdFirst + LOWORD(lpici->lpVerb));
|
||||
|
||||
if (HIWORD(lpici->lpVerb) == 0 && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast)
|
||||
if (!IS_INTRESOURCE(lpici->lpVerb) && SHELL_MapContextMenuVerbToCmdId(lpici, g_VerbMap) == 0)
|
||||
goto DoChooseApp;
|
||||
|
||||
if (IS_INTRESOURCE(lpici->lpVerb) && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast)
|
||||
{
|
||||
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdLast)
|
||||
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == idChooseApp)
|
||||
{
|
||||
DoChooseApp:
|
||||
OPENASINFO info;
|
||||
LPCWSTR pwszExt = PathFindExtensionW(m_wszPath);
|
||||
|
||||
|
@ -1371,9 +1381,13 @@ HRESULT WINAPI
|
|||
COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType,
|
||||
UINT* pwReserved, LPSTR pszName, UINT cchMax )
|
||||
{
|
||||
FIXME("%p %lu %u %p %p %u\n", this,
|
||||
TRACE("%p %lu %u %p %p %u\n", this,
|
||||
idCmd, uType, pwReserved, pszName, cchMax );
|
||||
|
||||
const SIZE_T idChooseApp = m_idCmdLast;
|
||||
if (m_idCmdFirst + idCmd == idChooseApp)
|
||||
return SHELL_GetCommandStringImpl(0, uType, pszName, cchMax, g_VerbMap);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,14 +130,7 @@ HRESULT CSendToMenu::GetUIObjectFromPidl(HWND hwnd, PIDLIST_ABSOLUTE pidl,
|
|||
REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
*ppvOut = NULL;
|
||||
|
||||
PCITEMID_CHILD pidlLast;
|
||||
CComPtr<IShellFolder> pFolder;
|
||||
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pFolder), &pidlLast);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
hr = pFolder->GetUIObjectOf(hwnd, 1, &pidlLast, riid, NULL, ppvOut);
|
||||
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(hwnd, pidl, riid, ppvOut);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
|
|
|
@ -1729,18 +1729,10 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(LPWSTR pszIconPath, INT cc
|
|||
static HRESULT SHELL_PidlGetIconLocationW(PCIDLIST_ABSOLUTE pidl,
|
||||
UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
|
||||
{
|
||||
LPCITEMIDLIST pidlLast;
|
||||
CComPtr<IShellFolder> psf;
|
||||
|
||||
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
CComPtr<IExtractIconW> pei;
|
||||
hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei));
|
||||
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IExtractIconW, &pei));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
@ -3142,20 +3134,9 @@ HRESULT STDMETHODCALLTYPE CShellLink::DragEnter(IDataObject *pDataObject,
|
|||
if (*pdwEffect == DROPEFFECT_NONE)
|
||||
return S_OK;
|
||||
|
||||
LPCITEMIDLIST pidlLast;
|
||||
CComPtr<IShellFolder> psf;
|
||||
|
||||
HRESULT hr = SHBindToParent(m_pPidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
|
||||
|
||||
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, m_pPidl, IID_PPV_ARG(IDropTarget, &m_DropTarget));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IDropTarget, &m_DropTarget));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
|
||||
else
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
|
||||
else
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ static void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable)
|
|||
EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
|
||||
SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0);
|
||||
}
|
||||
|
||||
// FIXME: Max capacity not implemented yet, disable for now (CORE-13743)
|
||||
EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
|
||||
}
|
||||
|
||||
static VOID
|
||||
|
@ -129,7 +132,8 @@ InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive)
|
|||
swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial));
|
||||
|
||||
dwSize = sizeof(DWORD);
|
||||
RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize);
|
||||
if (RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize))
|
||||
pItem->dwMaxCapacity = ~0;
|
||||
|
||||
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
|
||||
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
|
||||
|
@ -240,7 +244,7 @@ static VOID FreeDriveItemContext(HWND hwndDlg)
|
|||
}
|
||||
|
||||
static INT
|
||||
GetDefaultItem(HWND hwndDlg, LVITEMW* li)
|
||||
GetSelectedDriveItem(HWND hwndDlg, LVITEMW* li)
|
||||
{
|
||||
HWND hDlgCtrl;
|
||||
UINT iItemCount, iIndex;
|
||||
|
@ -275,6 +279,7 @@ RecycleBinDlg(
|
|||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
enum { WM_NEWDRIVESELECTED = WM_APP, WM_UPDATEDRIVESETTINGS };
|
||||
LPPSHNOTIFY lppsn;
|
||||
LPNMLISTVIEW lppl;
|
||||
LVITEMW li;
|
||||
|
@ -329,25 +334,9 @@ RecycleBinDlg(
|
|||
ss.fNoConfirmRecycle = SendDlgItemMessage(hwndDlg, 14004, BM_GETCHECK, 0, 0) == BST_UNCHECKED;
|
||||
SHGetSetSettings(&ss, SSF_NOCONFIRMRECYCLE, TRUE);
|
||||
|
||||
if (GetDefaultItem(hwndDlg, &li) > -1)
|
||||
if (GetSelectedDriveItem(hwndDlg, &li) > -1)
|
||||
{
|
||||
pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
|
||||
if (pItem)
|
||||
{
|
||||
uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
|
||||
if (bSuccess)
|
||||
{
|
||||
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
|
||||
FreeBytesAvailable = pItem->FreeBytesAvailable;
|
||||
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
|
||||
pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart);
|
||||
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
|
||||
}
|
||||
if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
pItem->dwNukeOnDelete = TRUE;
|
||||
else
|
||||
pItem->dwNukeOnDelete = FALSE;
|
||||
}
|
||||
SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, li.lParam);
|
||||
}
|
||||
if (StoreDriveSettings(hwndDlg))
|
||||
{
|
||||
|
@ -369,31 +358,45 @@ RecycleBinDlg(
|
|||
|
||||
if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
|
||||
{
|
||||
/* new focused item */
|
||||
toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete);
|
||||
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
|
||||
// New focused item, delay handling until after kill focus has been processed
|
||||
PostMessage(hwndDlg, WM_NEWDRIVESELECTED, 0, (LPARAM)pItem);
|
||||
}
|
||||
else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED))
|
||||
{
|
||||
/* kill focus */
|
||||
uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
|
||||
if (bSuccess)
|
||||
{
|
||||
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
|
||||
FreeBytesAvailable = pItem->FreeBytesAvailable;
|
||||
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
|
||||
pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart);
|
||||
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
|
||||
}
|
||||
if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
pItem->dwNukeOnDelete = TRUE;
|
||||
else
|
||||
pItem->dwNukeOnDelete = FALSE;
|
||||
// Kill focus
|
||||
SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, (LPARAM)pItem);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
break;
|
||||
case WM_NEWDRIVESELECTED:
|
||||
if (lParam)
|
||||
{
|
||||
pItem = (PDRIVE_ITEM_CONTEXT)lParam;
|
||||
toggleNukeOnDeleteOption(hwndDlg, pItem->dwNukeOnDelete);
|
||||
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
|
||||
}
|
||||
break;
|
||||
case WM_UPDATEDRIVESETTINGS:
|
||||
if (lParam)
|
||||
{
|
||||
pItem = (PDRIVE_ITEM_CONTEXT)lParam;
|
||||
uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
|
||||
if (bSuccess)
|
||||
{
|
||||
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
|
||||
FreeBytesAvailable = pItem->FreeBytesAvailable;
|
||||
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
|
||||
pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart);
|
||||
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
|
||||
}
|
||||
if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
pItem->dwNukeOnDelete = TRUE;
|
||||
else
|
||||
pItem->dwNukeOnDelete = FALSE;
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
FreeDriveItemContext(hwndDlg);
|
||||
break;
|
||||
|
|
|
@ -695,7 +695,7 @@ HRESULT WINAPI CDesktopFolder::GetAttributesOf(
|
|||
*rgfInOut &= dwMyComputerAttributes;
|
||||
else if (_ILIsNetHood(apidl[i]))
|
||||
*rgfInOut &= dwMyNetPlacesAttributes;
|
||||
else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
|
||||
else if (_ILIsFolderOrFile(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
|
||||
{
|
||||
CComPtr<IShellFolder2> psf;
|
||||
HRESULT hr = _GetSFFromPidl(apidl[i], &psf);
|
||||
|
|
|
@ -620,7 +620,7 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW
|
|||
{
|
||||
DWORD dwFileAttributes, dwShellAttributes;
|
||||
|
||||
if (!_ILIsFolder(pidl) && !_ILIsValue(pidl))
|
||||
if (!_ILIsFolderOrFile(pidl))
|
||||
{
|
||||
ERR("Got wrong type of pidl!\n");
|
||||
*pdwAttributes &= SFGAO_CANLINK;
|
||||
|
@ -1007,9 +1007,9 @@ HRESULT WINAPI CFSFolder::BindToObject(
|
|||
|
||||
/* Get the pidl data */
|
||||
FileStruct* pData = &_ILGetDataPointer(pidl)->u.file;
|
||||
FileStructW* pDataW = _ILGetFileStructW(pidl);
|
||||
|
||||
if (!pDataW)
|
||||
WCHAR szNameBuf[MAX_PATH];
|
||||
LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf));
|
||||
if (!pszName)
|
||||
{
|
||||
ERR("CFSFolder::BindToObject: Invalid pidl!\n");
|
||||
return E_INVALIDARG;
|
||||
|
@ -1021,7 +1021,7 @@ HRESULT WINAPI CFSFolder::BindToObject(
|
|||
PERSIST_FOLDER_TARGET_INFO pfti = {0};
|
||||
pfti.dwAttributes = -1;
|
||||
pfti.csidl = -1;
|
||||
PathCombineW(pfti.szTargetParsingName, m_sPathTarget, pDataW->wszName);
|
||||
PathCombineW(pfti.szTargetParsingName, m_sPathTarget, pszName);
|
||||
|
||||
/* Get the CLSID to bind to */
|
||||
CLSID clsidFolder;
|
||||
|
@ -1088,6 +1088,20 @@ HRESULT WINAPI CFSFolder::BindToStorage(
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT CFSFolder::CompareSortFoldersFirst(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||||
{
|
||||
BOOL bIsFolder1 = _ILIsFolder(pidl1), bIsFolder2 = _ILIsFolder(pidl2);
|
||||
// When sorting between a File and a Folder, the Folder gets sorted first
|
||||
if (bIsFolder1 != bIsFolder2)
|
||||
{
|
||||
// ...but only if neither of them were generated by SHSimpleIDListFromPath
|
||||
// because in that case we cannot tell if it's a file or a folder.
|
||||
if (pidl1 && IsRealItem(*pidl1) && pidl2 && IsRealItem(*pidl2))
|
||||
return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
|
||||
}
|
||||
return MAKE_SCODE(SEVERITY_ERROR, FACILITY_SHELL, S_EQUAL);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CFSFolder::CompareIDs
|
||||
*/
|
||||
|
@ -1096,31 +1110,24 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
|
|||
PCUIDLIST_RELATIVE pidl1,
|
||||
PCUIDLIST_RELATIVE pidl2)
|
||||
{
|
||||
LPPIDLDATA pData1 = _ILGetDataPointer(pidl1);
|
||||
LPPIDLDATA pData2 = _ILGetDataPointer(pidl2);
|
||||
FileStructW* pDataW1 = _ILGetFileStructW(pidl1);
|
||||
FileStructW* pDataW2 = _ILGetFileStructW(pidl2);
|
||||
BOOL bIsFolder1 = _ILIsFolder(pidl1);
|
||||
BOOL bIsFolder2 = _ILIsFolder(pidl2);
|
||||
LPWSTR pExtension1, pExtension2;
|
||||
|
||||
if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS)
|
||||
WCHAR szNameBuf1[MAX_PATH], szNameBuf2[_countof(szNameBuf1)];
|
||||
LPCWSTR pszName1 = GetItemFileName(pidl1, szNameBuf1, _countof(szNameBuf1));
|
||||
LPCWSTR pszName2 = GetItemFileName(pidl2, szNameBuf2, _countof(szNameBuf2));
|
||||
if (!pszName1 || !pszName2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS)
|
||||
return E_INVALIDARG;
|
||||
|
||||
/* When sorting between a File and a Folder, the Folder gets sorted first */
|
||||
if (bIsFolder1 != bIsFolder2)
|
||||
{
|
||||
// ...but only if neither of them were generated by SHSimpleIDListFromPath
|
||||
// because in that case we cannot tell if it's a file or a folder.
|
||||
if (IsRealItem(*pidl1) && IsRealItem(*pidl2))
|
||||
return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
|
||||
}
|
||||
LPPIDLDATA pData1 = _ILGetDataPointer(pidl1);
|
||||
LPPIDLDATA pData2 = _ILGetDataPointer(pidl2);
|
||||
LPWSTR pExtension1, pExtension2;
|
||||
|
||||
HRESULT hr = CompareSortFoldersFirst(pidl1, pidl2);
|
||||
if (SUCCEEDED(hr))
|
||||
return hr;
|
||||
int result = 0;
|
||||
switch (LOWORD(lParam))
|
||||
{
|
||||
case SHFSF_COL_NAME:
|
||||
result = _wcsicmp(pDataW1->wszName, pDataW2->wszName);
|
||||
result = _wcsicmp(pszName1, pszName2);
|
||||
break;
|
||||
case SHFSF_COL_SIZE:
|
||||
if (pData1->u.file.dwFileSize > pData2->u.file.dwFileSize)
|
||||
|
@ -1131,8 +1138,9 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
|
|||
result = 0;
|
||||
break;
|
||||
case SHFSF_COL_TYPE:
|
||||
pExtension1 = PathFindExtensionW(pDataW1->wszName);
|
||||
pExtension2 = PathFindExtensionW(pDataW2->wszName);
|
||||
// FIXME: Compare the type strings from SHGetFileInfo
|
||||
pExtension1 = PathFindExtensionW(pszName1);
|
||||
pExtension2 = PathFindExtensionW(pszName2);
|
||||
result = _wcsicmp(pExtension1, pExtension2);
|
||||
break;
|
||||
case SHFSF_COL_MDATE:
|
||||
|
@ -1273,7 +1281,7 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
|
|||
{
|
||||
LPCITEMIDLIST rpidl = ILFindLastID(m_pidlRoot);
|
||||
|
||||
if (_ILIsFolder(rpidl) || _ILIsValue(rpidl))
|
||||
if (_ILIsFolderOrFile(rpidl))
|
||||
{
|
||||
SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut);
|
||||
}
|
||||
|
@ -1297,7 +1305,7 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
|
|||
while (cidl > 0 && *apidl)
|
||||
{
|
||||
pdump(*apidl);
|
||||
if(_ILIsFolder(*apidl) || _ILIsValue(*apidl))
|
||||
if (_ILIsFolderOrFile(*apidl))
|
||||
SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut);
|
||||
else
|
||||
ERR("Got an unknown type of pidl!!!\n");
|
||||
|
@ -1549,14 +1557,14 @@ HRESULT WINAPI CFSFolder::SetNameOf(
|
|||
DWORD dwFlags,
|
||||
PITEMID_CHILD *pPidlOut)
|
||||
{
|
||||
WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
|
||||
WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1], szNameBuf[MAX_PATH];
|
||||
BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
|
||||
|
||||
TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
|
||||
debugstr_w (lpName), dwFlags, pPidlOut);
|
||||
|
||||
FileStructW* pDataW = _ILGetFileStructW(pidl);
|
||||
if (!pDataW)
|
||||
LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf));
|
||||
if (!pszName)
|
||||
{
|
||||
ERR("Got garbage pidl:\n");
|
||||
pdump_always(pidl);
|
||||
|
@ -1564,7 +1572,7 @@ HRESULT WINAPI CFSFolder::SetNameOf(
|
|||
}
|
||||
|
||||
/* build source path */
|
||||
PathCombineW(szSrc, m_sPathTarget, pDataW->wszName); // FIXME: PIDLs without wide string
|
||||
PathCombineW(szSrc, m_sPathTarget, pszName);
|
||||
|
||||
/* build destination path */
|
||||
if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER)
|
||||
|
@ -1662,6 +1670,7 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
|
|||
}
|
||||
else
|
||||
{
|
||||
FILETIME ft;
|
||||
hr = S_OK;
|
||||
psd->str.uType = STRRET_WSTR;
|
||||
if (iColumn != SHFSF_COL_NAME)
|
||||
|
@ -1683,7 +1692,11 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
|
|||
GetItemDescription(pidl, psd->str.pOleStr, MAX_PATH);
|
||||
break;
|
||||
case SHFSF_COL_MDATE:
|
||||
_ILGetFileDate(pidl, psd->str.pOleStr, MAX_PATH);
|
||||
if (!_ILGetFileDateTime(pidl, &ft) || FAILED(FormatDateTime(ft, psd->str.pOleStr, MAX_PATH)))
|
||||
{
|
||||
*psd->str.pOleStr = UNICODE_NULL;
|
||||
hr = S_FALSE;
|
||||
}
|
||||
break;
|
||||
case SHFSF_COL_FATTS:
|
||||
_ILGetFileAttributes(pidl, psd->str.pOleStr, MAX_PATH);
|
||||
|
@ -1744,17 +1757,12 @@ HRESULT WINAPI CFSFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
|
|||
m_sPathTarget = NULL;
|
||||
|
||||
/* set my path */
|
||||
HRESULT hr = E_FAIL;
|
||||
if (SHGetPathFromIDListW (pidl, wszTemp))
|
||||
{
|
||||
int len = wcslen(wszTemp);
|
||||
m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
|
||||
if (!m_sPathTarget)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
|
||||
}
|
||||
hr = SHStrDupW(wszTemp, &m_sPathTarget);
|
||||
|
||||
TRACE ("--(%p)->(%s)\n", this, debugstr_w(m_sPathTarget));
|
||||
return S_OK;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -1806,44 +1814,28 @@ HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx,
|
|||
* the target folder is spezified in csidl OR pidlTargetFolder OR
|
||||
* szTargetParsingName
|
||||
*/
|
||||
HRESULT hr = E_FAIL;
|
||||
if (ppfti)
|
||||
{
|
||||
if (ppfti->csidl != -1)
|
||||
{
|
||||
if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl,
|
||||
ppfti->csidl & CSIDL_FLAG_CREATE)) {
|
||||
int len = wcslen(wszTemp);
|
||||
m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
|
||||
if (!m_sPathTarget)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
|
||||
}
|
||||
BOOL create = ppfti->csidl & CSIDL_FLAG_CREATE;
|
||||
if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl, create))
|
||||
hr = SHStrDupW(wszTemp, &m_sPathTarget);
|
||||
}
|
||||
else if (ppfti->szTargetParsingName[0])
|
||||
{
|
||||
int len = wcslen(ppfti->szTargetParsingName);
|
||||
m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
|
||||
if (!m_sPathTarget)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(m_sPathTarget, ppfti->szTargetParsingName,
|
||||
(len + 1) * sizeof(WCHAR));
|
||||
hr = SHStrDupW(ppfti->szTargetParsingName, &m_sPathTarget);
|
||||
}
|
||||
else if (ppfti->pidlTargetFolder)
|
||||
{
|
||||
if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp))
|
||||
{
|
||||
int len = wcslen(wszTemp);
|
||||
m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
|
||||
if (!m_sPathTarget)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
|
||||
}
|
||||
hr = SHStrDupW(wszTemp, &m_sPathTarget);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("--(%p)->(target=%s)\n", this, debugstr_w(m_sPathTarget));
|
||||
pdump(m_pidlRoot);
|
||||
return (m_sPathTarget) ? S_OK : E_FAIL;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti)
|
||||
|
@ -1923,17 +1915,16 @@ HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvO
|
|||
HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
HRESULT hr;
|
||||
WCHAR wszPath[MAX_PATH];
|
||||
WCHAR wszPath[MAX_PATH], szNameBuf[MAX_PATH];
|
||||
|
||||
FileStructW* pDataW = _ILGetFileStructW(pidl);
|
||||
if (!pDataW)
|
||||
LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf));
|
||||
if (!pszName)
|
||||
{
|
||||
ERR("Got garbage pidl\n");
|
||||
pdump_always(pidl);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
PathCombineW(wszPath, m_sPathTarget, pDataW->wszName);
|
||||
PathCombineW(wszPath, m_sPathTarget, pszName);
|
||||
|
||||
CComPtr<IPersistFile> pp;
|
||||
hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp));
|
||||
|
@ -2104,3 +2095,28 @@ HRESULT WINAPI CFSFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CFSFolder::FormatDateTime(const FILETIME &ft, LPWSTR Buf, UINT cchBuf)
|
||||
{
|
||||
FILETIME lft;
|
||||
SYSTEMTIME time;
|
||||
FileTimeToLocalFileTime(&ft, &lft);
|
||||
FileTimeToSystemTime(&lft, &time);
|
||||
UINT ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, Buf, cchBuf);
|
||||
if (ret > 0 && ret < cchBuf)
|
||||
{
|
||||
/* Append space + time without seconds */
|
||||
Buf[ret-1] = ' ';
|
||||
GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &Buf[ret], cchBuf - ret);
|
||||
}
|
||||
return ret ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT CFSFolder::FormatSize(UINT64 size, LPWSTR Buf, UINT cchBuf)
|
||||
{
|
||||
if (StrFormatKBSizeW(size, Buf, cchBuf))
|
||||
return S_OK;
|
||||
if (cchBuf)
|
||||
*Buf = UNICODE_NULL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
|
|
@ -130,6 +130,13 @@ class CFSFolder :
|
|||
// Helper functions shared with CDesktopFolder
|
||||
static HRESULT GetFSColumnDetails(UINT iColumn, SHELLDETAILS &sd);
|
||||
static HRESULT GetDefaultFSColumnState(UINT iColumn, SHCOLSTATEF &csFlags);
|
||||
static HRESULT FormatDateTime(const FILETIME &ft, LPWSTR Buf, UINT cchBuf);
|
||||
static HRESULT FormatSize(UINT64 size, LPWSTR Buf, UINT cchBuf);
|
||||
static HRESULT CompareSortFoldersFirst(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
||||
static inline int CompareUiStrings(LPCWSTR a, LPCWSTR b)
|
||||
{
|
||||
return StrCmpLogicalW(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CFSFOLDER_H_ */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,12 +37,15 @@ class CRecycleBin :
|
|||
{
|
||||
private:
|
||||
LPITEMIDLIST pidl;
|
||||
INT iIdEmpty;
|
||||
BOOL RecycleBinIsEmpty();
|
||||
IShellFolder *m_pFSFolders[RECYCLEBINMAXDRIVECOUNT];
|
||||
bool m_IsBackgroundMenu;
|
||||
|
||||
IShellFolder* GetFSFolderForItem(LPCITEMIDLIST pidl);
|
||||
|
||||
public:
|
||||
CRecycleBin();
|
||||
~CRecycleBin();
|
||||
static inline REFCLSID GetClassID() { return CLSID_RecycleBin; }
|
||||
|
||||
// IPersistFolder
|
||||
STDMETHOD(GetClassID)(CLSID *pClassID) override;
|
||||
|
|
|
@ -262,6 +262,12 @@ SHBindToObjectEx(
|
|||
_In_ REFIID riid,
|
||||
_Out_ void **ppvObj);
|
||||
|
||||
EXTERN_C HRESULT
|
||||
SHELL_GetUIObjectOfAbsoluteItem(
|
||||
_In_opt_ HWND hWnd,
|
||||
_In_ PCIDLIST_ABSOLUTE pidl,
|
||||
_In_ REFIID riid, _Out_ void **ppvObj);
|
||||
|
||||
DWORD
|
||||
SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwAttributes);
|
||||
HRESULT SHELL_GetIDListTarget(_In_ LPCITEMIDLIST pidl, _Out_ PIDLIST_ABSOLUTE *ppidl);
|
||||
|
|
|
@ -12,7 +12,7 @@ BOOL WINAPI
|
|||
CloseRecycleBinHandle(
|
||||
IN HDELFILE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDeletedFile);
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hDeletedFile);
|
||||
|
@ -90,7 +90,7 @@ cleanup:
|
|||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DeleteFileHandleToRecycleBin(
|
||||
DeleteFileInRecycleBin(
|
||||
IN HDELFILE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
|
@ -231,9 +231,10 @@ EnumerateRecycleBinW(
|
|||
}
|
||||
else if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
if (!pFnCallback(Context, (HANDLE)prbf))
|
||||
if (!pFnCallback(Context, (HDELFILE)prbf))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
UINT error = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(error);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -252,132 +253,38 @@ cleanup:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileTypeNameW(
|
||||
IN HDELFILE hDeletedFile,
|
||||
OUT LPWSTR pTypeName,
|
||||
IN DWORD BufferSize,
|
||||
OUT LPDWORD RequiredSize OPTIONAL)
|
||||
typedef struct _BBENUMFILECONTEXT
|
||||
{
|
||||
IRecycleBinFile *prbf = (IRecycleBinFile *)hDeletedFile;
|
||||
SIZE_T FinalSize;
|
||||
const RECYCLEBINFILEIDENTITY *pFI;
|
||||
HDELFILE hDelFile;
|
||||
} BBENUMFILECONTEXT;
|
||||
|
||||
HRESULT hr = IRecycleBinFile_GetTypeName(prbf, BufferSize, pTypeName, &FinalSize);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
static BOOL CALLBACK
|
||||
GetRecycleBinFileHandleCallback(IN PVOID Context, IN HDELFILE hDeletedFile)
|
||||
{
|
||||
BBENUMFILECONTEXT *pCtx = (BBENUMFILECONTEXT*)Context;
|
||||
IRecycleBinFile *pRBF = IRecycleBinFileFromHDELFILE(hDeletedFile);
|
||||
if (IRecycleBinFile_IsEqualIdentity(pRBF, pCtx->pFI) == S_OK)
|
||||
{
|
||||
if (RequiredSize)
|
||||
*RequiredSize = (DWORD)FinalSize;
|
||||
|
||||
return TRUE;
|
||||
pCtx->hDelFile = hDeletedFile;
|
||||
return FALSE;
|
||||
}
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
CloseRecycleBinHandle(hDeletedFile);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EXTERN_C HDELFILE
|
||||
GetRecycleBinFileHandle(
|
||||
IN LPCWSTR pszRoot OPTIONAL,
|
||||
IN const RECYCLEBINFILEIDENTITY *pFI)
|
||||
{
|
||||
BBENUMFILECONTEXT context = { pFI, NULL };
|
||||
EnumerateRecycleBinW(pszRoot, GetRecycleBinFileHandleCallback, &context);
|
||||
return context.hDelFile;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsA(
|
||||
IN HDELFILE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL)
|
||||
{
|
||||
PDELETED_FILE_DETAILS_W FileDetailsW = NULL;
|
||||
DWORD BufferSizeW = 0;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
|
||||
|
||||
if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
|
||||
{
|
||||
BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
|
||||
+ (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
|
||||
}
|
||||
if (FileDetails && BufferSizeW)
|
||||
{
|
||||
FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
|
||||
if (!FileDetailsW)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
|
||||
if (!ret)
|
||||
goto cleanup;
|
||||
|
||||
if (FileDetails)
|
||||
{
|
||||
CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
|
||||
if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
|
||||
goto cleanup;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, FileDetailsW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsW(
|
||||
IN HDELFILE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
HRESULT hr;
|
||||
SIZE_T NameSize, Needed;
|
||||
|
||||
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
|
||||
|
||||
hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
|
||||
if (RequiredSize)
|
||||
*RequiredSize = (DWORD)Needed;
|
||||
if (Needed > BufferSize)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
goto cleanup;
|
||||
}
|
||||
hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
RestoreFile(
|
||||
RestoreFileFromRecycleBin(
|
||||
IN HDELFILE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
|
@ -395,7 +302,7 @@ RestoreFile(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
EXTERN_C HRESULT
|
||||
GetDefaultRecycleBin(
|
||||
IN LPCWSTR pszVolume OPTIONAL,
|
||||
OUT IRecycleBin **pprb)
|
||||
|
@ -425,3 +332,17 @@ GetDefaultRecycleBin(
|
|||
IUnknown_Release(pUnk);
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT
|
||||
GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path)
|
||||
{
|
||||
const WCHAR volume[] = { LOWORD('A' + Drive), ':', '\\', '\0' };
|
||||
IRecycleBin *pRB;
|
||||
HRESULT hr = GetDefaultRecycleBin(volume, &pRB);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IRecycleBin_GetDirectory(pRB, Path);
|
||||
IRecycleBin_Release(pRB);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -17,48 +17,64 @@ extern "C" {
|
|||
#include <shellapi.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#define ANY_SIZE 1
|
||||
#define RECYCLEBINMAXDRIVECOUNT 26
|
||||
|
||||
/* Structures used by the API Interface */
|
||||
|
||||
typedef struct _DELETED_FILE_DETAILS_A
|
||||
typedef UINT RECYCLEBINFILESIZETYPE;
|
||||
|
||||
typedef struct _RECYCLEBINFILEIDENTITY
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
ULARGE_INTEGER FileSize;
|
||||
ULARGE_INTEGER PhysicalFileSize;
|
||||
DWORD Attributes;
|
||||
CHAR FileName[ANY_SIZE];
|
||||
} DELETED_FILE_DETAILS_A, *PDELETED_FILE_DETAILS_A;
|
||||
typedef struct _DELETED_FILE_DETAILS_W
|
||||
FILETIME DeletionTime;
|
||||
LPCWSTR RecycledFullPath; /* "C:\Recycled\Dc1.ext" etc. */
|
||||
} RECYCLEBINFILEIDENTITY, *PRECYCLEBINFILEIDENTITY;
|
||||
|
||||
typedef struct _RECYCLEBINSTRING
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
ULARGE_INTEGER FileSize;
|
||||
ULARGE_INTEGER PhysicalFileSize;
|
||||
DWORD Attributes;
|
||||
WCHAR FileName[ANY_SIZE];
|
||||
} DELETED_FILE_DETAILS_W, *PDELETED_FILE_DETAILS_W;
|
||||
#ifdef UNICODE
|
||||
#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_W
|
||||
#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_W
|
||||
#else
|
||||
#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_A
|
||||
#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_A
|
||||
#endif
|
||||
LPCWSTR String;
|
||||
LPWSTR Alloc;
|
||||
} RECYCLEBINSTRING, *PRECYCLEBINSTRING;
|
||||
|
||||
typedef struct _DELETED_FILE_INFO
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
RECYCLEBINFILESIZETYPE FileSize;
|
||||
DWORD Attributes;
|
||||
RECYCLEBINSTRING OriginalFullPath;
|
||||
RECYCLEBINSTRING RecycledFullPath;
|
||||
} DELETED_FILE_INFO, *PDELETED_FILE_INFO;
|
||||
|
||||
/* Distinct handle type for deleted file/folder */
|
||||
DECLARE_HANDLE(HDELFILE);
|
||||
#define IRecycleBinFileFromHDELFILE(hDF) ( (IRecycleBinFile*)(hDF) )
|
||||
|
||||
/* API Interface */
|
||||
|
||||
static inline void
|
||||
FreeRecycleBinString(PRECYCLEBINSTRING pRBS)
|
||||
{
|
||||
SHFree(pRBS->Alloc);
|
||||
pRBS->String = pRBS->Alloc = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
InitializeRecycleBinStringRef(PRECYCLEBINSTRING pRBS, LPCWSTR String)
|
||||
{
|
||||
pRBS->String = String;
|
||||
pRBS->Alloc = NULL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT
|
||||
GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path);
|
||||
|
||||
/* Function called for each deleted file in the recycle bin
|
||||
* Context: value given by the caller of the EnumerateRecycleBin function
|
||||
* hDeletedFile: a handle to the deleted file
|
||||
* Returning FALSE stops the enumeration.
|
||||
* Remarks: the handle must be closed with the CloseRecycleBinHandle function
|
||||
*/
|
||||
typedef BOOL (WINAPI *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HDELFILE hDeletedFile);
|
||||
typedef BOOL (CALLBACK *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HDELFILE hDeletedFile);
|
||||
|
||||
/* Closes a file deleted handle.
|
||||
* hDeletedFile: the handle to close
|
||||
|
@ -85,13 +101,13 @@ DeleteFileToRecycleBinW(
|
|||
#define DeleteFileToRecycleBin DeleteFileToRecycleBinA
|
||||
#endif
|
||||
|
||||
/* Moves a file to the recycle bin.
|
||||
/* Deletes a file in the recycle bin.
|
||||
* hDeletedFile: handle of the deleted file to delete
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback
|
||||
*/
|
||||
BOOL WINAPI
|
||||
DeleteFileHandleToRecycleBin(
|
||||
DeleteFileInRecycleBin(
|
||||
IN HDELFILE hDeletedFile);
|
||||
|
||||
/* Removes all elements contained in a recycle bin
|
||||
|
@ -134,38 +150,10 @@ EnumerateRecycleBinW(
|
|||
#define EnumerateRecycleBin EnumerateRecycleBinA
|
||||
#endif
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileTypeNameW(
|
||||
IN HDELFILE hDeletedFile,
|
||||
OUT LPWSTR pTypeName,
|
||||
IN DWORD BufferSize,
|
||||
OUT LPDWORD RequiredSize OPTIONAL);
|
||||
|
||||
/* Gets details about a deleted file
|
||||
* hDeletedFile: handle of the deleted file to get details about
|
||||
* BufferSize: size of the 'FileDetails' buffer, in bytes
|
||||
* FileDetails: if the function succeeded, contains details about the deleted file
|
||||
* RequiredSize: contains the minimal buffer size required to get file information details
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback
|
||||
*/
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsA(
|
||||
IN HDELFILE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL);
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsW(
|
||||
IN HDELFILE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL);
|
||||
#ifdef UNICODE
|
||||
#define GetDeletedFileDetails GetDeletedFileDetailsW
|
||||
#else
|
||||
#define GetDeletedFileDetails GetDeletedFileDetailsA
|
||||
#endif
|
||||
EXTERN_C HDELFILE
|
||||
GetRecycleBinFileHandle(
|
||||
IN LPCWSTR pszRoot OPTIONAL,
|
||||
IN const RECYCLEBINFILEIDENTITY *pFI);
|
||||
|
||||
/* Restores a deleted file
|
||||
* hDeletedFile: handle of the deleted file to restore
|
||||
|
@ -173,7 +161,7 @@ GetDeletedFileDetailsW(
|
|||
* Remarks: if the function succeeds, the handle is not valid anymore.
|
||||
*/
|
||||
BOOL WINAPI
|
||||
RestoreFile(
|
||||
RestoreFileFromRecycleBin(
|
||||
IN HDELFILE hDeletedFile);
|
||||
|
||||
/* COM interface */
|
||||
|
@ -189,13 +177,14 @@ DECLARE_INTERFACE_(IRecycleBinFile, IUnknown)
|
|||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IRecycleBinFile methods */
|
||||
STDMETHOD(IsEqualIdentity)(THIS_ const RECYCLEBINFILEIDENTITY *pFI) PURE;
|
||||
STDMETHOD(GetInfo)(THIS_ PDELETED_FILE_INFO pInfo) PURE;
|
||||
STDMETHOD(GetLastModificationTime)(THIS_ FILETIME *pLastModificationTime) PURE;
|
||||
STDMETHOD(GetDeletionTime)(THIS_ FILETIME *pDeletionTime) PURE;
|
||||
STDMETHOD(GetFileSize)(THIS_ ULARGE_INTEGER *pFileSize) PURE;
|
||||
STDMETHOD(GetPhysicalFileSize)(THIS_ ULARGE_INTEGER *pPhysicalFileSize) PURE;
|
||||
STDMETHOD(GetAttributes)(THIS_ DWORD *pAttributes) PURE;
|
||||
STDMETHOD(GetFileName)(THIS_ SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) PURE;
|
||||
STDMETHOD(GetTypeName)(THIS_ SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) PURE;
|
||||
STDMETHOD(Delete)(THIS) PURE;
|
||||
STDMETHOD(Restore)(THIS) PURE;
|
||||
|
||||
|
@ -233,9 +222,10 @@ DECLARE_INTERFACE_(IRecycleBin, IUnknown)
|
|||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IRecycleBin methods */
|
||||
STDMETHOD(DeleteFile)(THIS_ LPCWSTR szFileName);
|
||||
STDMETHOD(EmptyRecycleBin)(THIS);
|
||||
STDMETHOD(EnumObjects)(THIS_ IRecycleBinEnumList **ppEnumList);
|
||||
STDMETHOD(DeleteFile)(THIS_ LPCWSTR szFileName) PURE;
|
||||
STDMETHOD(EmptyRecycleBin)(THIS) PURE;
|
||||
STDMETHOD(EnumObjects)(THIS_ IRecycleBinEnumList **ppEnumList) PURE;
|
||||
STDMETHOD(GetDirectory)(THIS_ LPWSTR szPath) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
|
@ -252,6 +242,10 @@ EXTERN_C const IID IID_IRecycleBin;
|
|||
(This)->lpVtbl->AddRef(This)
|
||||
#define IRecycleBinFile_Release(This) \
|
||||
(This)->lpVtbl->Release(This)
|
||||
#define IRecycleBinFile_IsEqualIdentity(This, pFI) \
|
||||
(This)->lpVtbl->IsEqualIdentity(This, pFI)
|
||||
#define IRecycleBinFile_GetInfo(This, pInfo) \
|
||||
(This)->lpVtbl->GetInfo(This, pInfo)
|
||||
#define IRecycleBinFile_GetLastModificationTime(This, pLastModificationTime) \
|
||||
(This)->lpVtbl->GetLastModificationTime(This, pLastModificationTime)
|
||||
#define IRecycleBinFile_GetDeletionTime(This, pDeletionTime) \
|
||||
|
@ -264,8 +258,6 @@ EXTERN_C const IID IID_IRecycleBin;
|
|||
(This)->lpVtbl->GetAttributes(This, pAttributes)
|
||||
#define IRecycleBinFile_GetFileName(This, BufferSize, Buffer, RequiredSize) \
|
||||
(This)->lpVtbl->GetFileName(This, BufferSize, Buffer, RequiredSize)
|
||||
#define IRecycleBinFile_GetTypeName(This, BufferSize, Buffer, RequiredSize) \
|
||||
(This)->lpVtbl->GetTypeName(This, BufferSize, Buffer, RequiredSize)
|
||||
#define IRecycleBinFile_Delete(This) \
|
||||
(This)->lpVtbl->Delete(This)
|
||||
#define IRecycleBinFile_Restore(This) \
|
||||
|
@ -296,13 +288,20 @@ EXTERN_C const IID IID_IRecycleBin;
|
|||
(This)->lpVtbl->EmptyRecycleBin(This)
|
||||
#define IRecycleBin_EnumObjects(This, ppEnumList) \
|
||||
(This)->lpVtbl->EnumObjects(This, ppEnumList)
|
||||
#define IRecycleBin_GetDirectory(This, szPath) \
|
||||
(This)->lpVtbl->GetDirectory(This, szPath)
|
||||
#endif
|
||||
|
||||
HRESULT WINAPI
|
||||
EXTERN_C HRESULT
|
||||
GetDefaultRecycleBin(
|
||||
IN LPCWSTR pszVolume OPTIONAL,
|
||||
OUT IRecycleBin **pprb);
|
||||
|
||||
/* Recycle Bin shell folder internal API */
|
||||
void CRecycleBin_NotifyRecycled(LPCWSTR OrigPath, const WIN32_FIND_DATAW *pFind,
|
||||
const RECYCLEBINFILEIDENTITY *pFI);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,10 @@ public:
|
|||
STDMETHODIMP DeleteFile(LPCWSTR szFileName) override;
|
||||
STDMETHODIMP EmptyRecycleBin() override;
|
||||
STDMETHODIMP EnumObjects(IRecycleBinEnumList **ppEnumList) override;
|
||||
STDMETHODIMP GetDirectory(LPWSTR szPath) override
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
protected:
|
||||
LONG m_ref;
|
||||
|
@ -183,3 +187,11 @@ HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
|
|||
*ppUnknown = static_cast<IRecycleBin *>(pThis);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
EXTERN_C
|
||||
BOOL RecycleBinGeneric_IsEqualFileIdentity(const RECYCLEBINFILEIDENTITY *p1, const RECYCLEBINFILEIDENTITY *p2)
|
||||
{
|
||||
return p1->DeletionTime.dwLowDateTime == p2->DeletionTime.dwLowDateTime &&
|
||||
p1->DeletionTime.dwHighDateTime == p2->DeletionTime.dwHighDateTime &&
|
||||
_wcsicmp(p1->RecycledFullPath, p2->RecycledFullPath) == 0;
|
||||
}
|
||||
|
|
|
@ -13,11 +13,20 @@
|
|||
#include <wine/debug.h>
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
static inline HRESULT HResultFromWin32(DWORD hr)
|
||||
{
|
||||
// HRESULT_FROM_WIN32 will evaluate its parameter twice, this function will not.
|
||||
return HRESULT_FROM_WIN32(hr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Defines */
|
||||
|
||||
#define RECYCLE_BIN_DIRECTORY_WITH_ACL L"RECYCLER"
|
||||
#define RECYCLE_BIN_DIRECTORY_WITHOUT_ACL L"RECYCLED"
|
||||
#define RECYCLE_BIN_FILE_NAME L"INFO2"
|
||||
#define RECYCLE_BIN_FILE_NAME_V1 L"INFO"
|
||||
|
||||
#define ROUND_UP(N, S) ((( (N) + (S) - 1) / (S) ) * (S) )
|
||||
|
||||
|
@ -43,6 +52,9 @@ typedef struct _INFO2_HEADER
|
|||
EXTERN_C
|
||||
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
|
||||
|
||||
EXTERN_C
|
||||
BOOL RecycleBinGeneric_IsEqualFileIdentity(const RECYCLEBINFILEIDENTITY *p1, const RECYCLEBINFILEIDENTITY *p2);
|
||||
|
||||
/* recyclebin_generic_enumerator.c */
|
||||
|
||||
EXTERN_C
|
||||
|
|
|
@ -143,6 +143,13 @@ public:
|
|||
STDMETHODIMP DeleteFile(_In_ LPCWSTR szFileName) override;
|
||||
STDMETHODIMP EmptyRecycleBin() override;
|
||||
STDMETHODIMP EnumObjects(_Out_ IRecycleBinEnumList **ppEnumList) override;
|
||||
STDMETHODIMP GetDirectory(LPWSTR szPath) override
|
||||
{
|
||||
if (!m_Folder[0])
|
||||
return E_UNEXPECTED;
|
||||
lstrcpynW(szPath, m_Folder, MAX_PATH);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* IRecycleBin5 interface */
|
||||
STDMETHODIMP Delete(
|
||||
|
@ -226,6 +233,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
SYSTEMTIME SystemTime;
|
||||
DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
|
||||
HRESULT hr;
|
||||
WIN32_FIND_DATAW wfd = {};
|
||||
|
||||
TRACE("(%p, %s)\n", this, debugstr_w(szFileName));
|
||||
|
||||
|
@ -240,7 +248,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
{
|
||||
if (szFullName)
|
||||
CoTaskMemFree(szFullName);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
}
|
||||
else if (len < dwBufferLength)
|
||||
break;
|
||||
|
@ -257,7 +265,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
CoTaskMemFree(szFullName);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
}
|
||||
|
||||
if (dwBufferLength < 2 || szFullName[1] != ':')
|
||||
|
@ -270,7 +278,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -281,7 +289,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
|
||||
if (!m_hInfoMapped)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -289,7 +297,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!pHeader)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -297,7 +305,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart < sizeof(INFO2_HEADER))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1;
|
||||
|
@ -307,14 +315,14 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
#if 0
|
||||
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&FileSize))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
#else
|
||||
FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
@ -350,7 +358,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
/* Get cluster size */
|
||||
if (!GetDiskFreeSpaceW(m_VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
ClusterSize = BytesPerSector * SectorsPerCluster;
|
||||
|
@ -359,7 +367,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
GetSystemTime(&SystemTime);
|
||||
if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize);
|
||||
|
@ -373,11 +381,21 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
wfd.dwFileAttributes = dwAttributes;
|
||||
wfd.nFileSizeLow = FileSize.u.LowPart;
|
||||
GetFileTime(hFile, &wfd.ftCreationTime, &wfd.ftLastAccessTime, &wfd.ftLastWriteTime);
|
||||
|
||||
/* Move file */
|
||||
if (MoveFileW(szFullName, DeletedFileName))
|
||||
hr = S_OK;
|
||||
else
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RECYCLEBINFILEIDENTITY ident = { pDeletedFile->DeletionTime, DeletedFileName };
|
||||
CRecycleBin_NotifyRecycled(szFullName, &wfd, &ident);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (pHeader)
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef interface IRecycleBin5 IRecycleBin5;
|
|||
EXTERN_C const IID IID_IRecycleBin5;
|
||||
|
||||
#define INTERFACE IRecycleBin5
|
||||
DECLARE_INTERFACE_(IRecycleBin5, IUnknown)
|
||||
DECLARE_INTERFACE_(IRecycleBin5, IRecycleBin)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
|
@ -41,6 +41,7 @@ DECLARE_INTERFACE_(IRecycleBin5, IUnknown)
|
|||
STDMETHOD(DeleteFile)(THIS_ IN LPCWSTR szFileName) PURE;
|
||||
STDMETHOD(EmptyRecycleBin)(THIS);
|
||||
STDMETHOD(EnumObjects)(THIS_ OUT IRecycleBinEnumList **ppEnumList) PURE;
|
||||
STDMETHOD(GetDirectory)(THIS_ LPWSTR szPath) PURE;
|
||||
|
||||
/* IRecycleBin5 interface */
|
||||
STDMETHOD(Delete)(
|
||||
|
|
|
@ -28,13 +28,18 @@ public:
|
|||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
/* IRecycleBinFile methods */
|
||||
STDMETHODIMP IsEqualIdentity(const RECYCLEBINFILEIDENTITY *pFI) override
|
||||
{
|
||||
RECYCLEBINFILEIDENTITY self = { m_deletedFile.DeletionTime, m_FullName };
|
||||
return RecycleBinGeneric_IsEqualFileIdentity(pFI, &self) ? S_OK : S_FALSE;
|
||||
}
|
||||
STDMETHODIMP GetInfo(PDELETED_FILE_INFO pInfo) override;
|
||||
STDMETHODIMP GetLastModificationTime(FILETIME *pLastModificationTime) override;
|
||||
STDMETHODIMP GetDeletionTime(FILETIME *pDeletionTime) override;
|
||||
STDMETHODIMP GetFileSize(ULARGE_INTEGER *pFileSize) override;
|
||||
STDMETHODIMP GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize) override;
|
||||
STDMETHODIMP GetAttributes(DWORD *pAttributes) override;
|
||||
STDMETHODIMP GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override;
|
||||
STDMETHODIMP GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override;
|
||||
STDMETHODIMP Delete() override;
|
||||
STDMETHODIMP Restore() override;
|
||||
|
||||
|
@ -53,14 +58,8 @@ STDMETHODIMP RecycleBin5File::QueryInterface(REFIID riid, void **ppvObject)
|
|||
return E_POINTER;
|
||||
|
||||
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinFile))
|
||||
*ppvObject = static_cast<IRecycleBinFile *>(this);
|
||||
else if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
|
||||
{
|
||||
DWORD dwAttributes;
|
||||
if (GetAttributes(&dwAttributes) == S_OK)
|
||||
return SHCreateFileExtractIconW(m_FullName, dwAttributes, riid, ppvObject);
|
||||
else
|
||||
return S_FALSE;
|
||||
*ppvObject = static_cast<IRecycleBinFile *>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -94,13 +93,29 @@ STDMETHODIMP_(ULONG) RecycleBin5File::Release()
|
|||
return refCount;
|
||||
}
|
||||
|
||||
STDMETHODIMP RecycleBin5File::GetInfo(PDELETED_FILE_INFO pInfo)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ULARGE_INTEGER uli;
|
||||
if (FAILED(GetLastModificationTime(&pInfo->LastModification)))
|
||||
ZeroMemory(&pInfo->LastModification, sizeof(pInfo->LastModification));
|
||||
pInfo->DeletionTime = m_deletedFile.DeletionTime;
|
||||
C_ASSERT(sizeof(pInfo->FileSize) <= sizeof(UINT));
|
||||
pInfo->FileSize = FAILED(GetFileSize(&uli)) ? INVALID_FILE_SIZE : uli.LowPart;
|
||||
if (FAILED(hr = GetAttributes(&pInfo->Attributes)))
|
||||
pInfo->Attributes = 0;
|
||||
InitializeRecycleBinStringRef(&pInfo->OriginalFullPath, m_deletedFile.FileNameW);
|
||||
InitializeRecycleBinStringRef(&pInfo->RecycledFullPath, m_FullName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificationTime)
|
||||
{
|
||||
TRACE("(%p, %p)\n", this, pLastModificationTime);
|
||||
|
||||
DWORD dwAttributes = ::GetFileAttributesW(m_FullName);
|
||||
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
|
||||
HANDLE hFile;
|
||||
hFile = CreateFileW(m_FullName,
|
||||
|
@ -112,13 +127,13 @@ STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificatio
|
|||
(dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
|
||||
HRESULT hr;
|
||||
if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
|
||||
hr = S_OK;
|
||||
else
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
hr = HResultFromWin32(GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return hr;
|
||||
}
|
||||
|
@ -174,7 +189,7 @@ STDMETHODIMP RecycleBin5File::GetAttributes(DWORD *pAttributes)
|
|||
|
||||
dwAttributes = GetFileAttributesW(m_FullName);
|
||||
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
|
||||
*pAttributes = dwAttributes;
|
||||
return S_OK;
|
||||
|
@ -199,36 +214,6 @@ STDMETHODIMP RecycleBin5File::GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP RecycleBin5File::GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD dwRequired;
|
||||
DWORD dwAttributes;
|
||||
SHFILEINFOW shFileInfo;
|
||||
|
||||
TRACE("(%p, %u, %p, %p)\n", this, BufferSize, Buffer, RequiredSize);
|
||||
|
||||
hr = GetAttributes(&dwAttributes);
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
|
||||
hr = SHGetFileInfoW(m_FullName, dwAttributes, &shFileInfo, sizeof(shFileInfo), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
|
||||
dwRequired = (DWORD)(wcslen(shFileInfo.szTypeName) + 1) * sizeof(WCHAR);
|
||||
if (RequiredSize)
|
||||
*RequiredSize = dwRequired;
|
||||
|
||||
if (BufferSize == 0 && !Buffer)
|
||||
return S_OK;
|
||||
|
||||
if (BufferSize < dwRequired)
|
||||
return E_OUTOFMEMORY;
|
||||
CopyMemory(Buffer, shFileInfo.szTypeName, dwRequired);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP RecycleBin5File::Delete()
|
||||
{
|
||||
TRACE("(%p)\n", this);
|
||||
|
@ -390,7 +375,7 @@ STDMETHODIMP RecycleBin5Enum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *p
|
|||
ULARGE_INTEGER FileSize;
|
||||
FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart == 0)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
|
||||
DWORD dwEntries =
|
||||
(DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
|
||||
|
@ -455,7 +440,7 @@ RecycleBin5Enum::Init(
|
|||
m_hInfo = hInfo;
|
||||
m_pInfo = (PINFO2_HEADER)MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!m_pInfo)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HResultFromWin32(GetLastError());
|
||||
|
||||
if (m_pInfo->dwVersion != 5 || m_pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
|
||||
return E_FAIL;
|
||||
|
|
|
@ -1390,14 +1390,7 @@ static HRESULT shellex_get_dataobj( LPSHELLEXECUTEINFOW sei, CComPtr<IDataObject
|
|||
pidl = ILCreateFromPathW(fullpath);
|
||||
allocatedPidl.Attach(pidl);
|
||||
}
|
||||
|
||||
CComPtr<IShellFolder> shf;
|
||||
LPCITEMIDLIST pidllast = NULL;
|
||||
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
|
||||
return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject, &dataObj));
|
||||
return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IDataObject, &dataObj));
|
||||
}
|
||||
|
||||
static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
|
||||
|
@ -1582,6 +1575,7 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
|
|||
|
||||
enum { idFirst = 1, idLast = 0x7fff };
|
||||
HMENU hMenu = CreatePopupMenu();
|
||||
// Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed
|
||||
hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0);
|
||||
if (!FAILED_UNEXPECTEDLY(hr))
|
||||
{
|
||||
|
|
|
@ -259,6 +259,32 @@ HRESULT SHBindToObject(
|
|||
return SHBindToObjectEx(psf, pidl, NULL, riid, ppvObj);
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT
|
||||
SHELL_GetUIObjectOfAbsoluteItem(
|
||||
_In_opt_ HWND hWnd,
|
||||
_In_ PCIDLIST_ABSOLUTE pidl,
|
||||
_In_ REFIID riid, _Out_ void **ppvObj)
|
||||
{
|
||||
if (!ppvObj)
|
||||
return E_INVALIDARG;
|
||||
*ppvObj = NULL;
|
||||
IShellFolder *psf;
|
||||
PCUITEMID_CHILD pidlChild;
|
||||
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psf->GetUIObjectOf(hWnd, 1, &pidlChild, riid, NULL, ppvObj);
|
||||
psf->Release();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (*ppvObj)
|
||||
return hr;
|
||||
hr = E_FAIL;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Shell_DisplayNameOf(
|
||||
_In_ IShellFolder *psf,
|
||||
|
@ -1429,3 +1455,71 @@ GetDfmCmd(_In_ IContextMenu *pCM, _In_ LPCSTR verba)
|
|||
}
|
||||
return MapVerbToDfmCmd(verba); // Returns DFM_CMD_* or 0
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap)
|
||||
{
|
||||
LPCSTR pVerbA = pICI->lpVerb;
|
||||
CHAR buf[MAX_PATH];
|
||||
LPCMINVOKECOMMANDINFOEX pICIX = (LPCMINVOKECOMMANDINFOEX)pICI;
|
||||
if (IsUnicode(*pICIX) && !IS_INTRESOURCE(pICIX->lpVerbW))
|
||||
{
|
||||
if (SHUnicodeToAnsi(pICIX->lpVerbW, buf, _countof(buf)))
|
||||
pVerbA = buf;
|
||||
}
|
||||
|
||||
if (IS_INTRESOURCE(pVerbA))
|
||||
return LOWORD(pVerbA);
|
||||
for (SIZE_T i = 0; pMap[i].Verb; ++i)
|
||||
{
|
||||
assert(SUCCEEDED((int)(pMap[i].CmdId))); // The id must be >= 0 and ideally in the 0..0x7fff range
|
||||
if (!lstrcmpiA(pMap[i].Verb, pVerbA) && pVerbA[0])
|
||||
return pMap[i].CmdId;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
static const CMVERBMAP*
|
||||
FindVerbMapEntry(UINT_PTR CmdId, const CMVERBMAP *pMap)
|
||||
{
|
||||
for (SIZE_T i = 0; pMap[i].Verb; ++i)
|
||||
{
|
||||
if (pMap[i].CmdId == CmdId)
|
||||
return &pMap[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap)
|
||||
{
|
||||
const CMVERBMAP* pEntry;
|
||||
switch (uFlags | GCS_UNICODE)
|
||||
{
|
||||
case GCS_VALIDATEW:
|
||||
case GCS_VERBW:
|
||||
pEntry = FindVerbMapEntry(CmdId, pMap);
|
||||
if ((uFlags | GCS_UNICODE) == GCS_VERBW)
|
||||
{
|
||||
if (!pEntry)
|
||||
return E_INVALIDARG;
|
||||
else if (uFlags & GCS_UNICODE)
|
||||
return SHAnsiToUnicode(pEntry->Verb, (LPWSTR)Buf, cchBuf) ? S_OK : E_FAIL;
|
||||
else
|
||||
return StringCchCopyA(Buf, cchBuf, pEntry->Verb);
|
||||
}
|
||||
return pEntry ? S_OK : S_FALSE; // GCS_VALIDATE
|
||||
}
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
CComPtr<IDefaultExtractIconInit> initIcon;
|
||||
HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
return hr;
|
||||
initIcon->SetNormalIcon(swShell32Name, IconIndex);
|
||||
return initIcon->QueryInterface(riid, ppvOut);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
inline BOOL
|
||||
#ifdef __cplusplus
|
||||
static inline LPWSTR
|
||||
SHStrDupW(LPCWSTR Src)
|
||||
{
|
||||
LPWSTR Dup;
|
||||
return SUCCEEDED(SHStrDupW(Src, &Dup)) ? Dup : NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline BOOL
|
||||
RegValueExists(HKEY hKey, LPCWSTR Name)
|
||||
{
|
||||
return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
|
||||
|
@ -31,12 +40,22 @@ RegSetOrDelete(HKEY hKey, LPCWSTR Name, DWORD Type, LPCVOID Data, DWORD Size)
|
|||
return RegDeleteValueW(hKey, Name);
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
static inline DWORD
|
||||
RegSetString(HKEY hKey, LPCWSTR Name, LPCWSTR Str, DWORD Type = REG_SZ)
|
||||
{
|
||||
return RegSetValueExW(hKey, Name, 0, Type, LPBYTE(Str), (lstrlenW(Str) + 1) * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
LPCSTR Verb;
|
||||
WORD CmdId;
|
||||
} CMVERBMAP;
|
||||
|
||||
HRESULT
|
||||
SHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap);
|
||||
HRESULT
|
||||
SHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap);
|
||||
|
||||
// SHExtractIconsW is a forward, use this function instead inside shell32
|
||||
inline HICON
|
||||
SHELL32_SHExtractIcon(LPCWSTR File, int Index, int cx, int cy)
|
||||
|
@ -45,3 +64,20 @@ SHELL32_SHExtractIcon(LPCWSTR File, int Index, int cx, int cy)
|
|||
int r = PrivateExtractIconsW(File, Index, cx, cy, &hIco, NULL, 1, 0);
|
||||
return r > 0 ? hIco : NULL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut);
|
||||
|
||||
static inline HRESULT
|
||||
SHELL_CreateFallbackExtractIconForFolder(REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
const int id = IDI_SHELL_FOLDER;
|
||||
return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut);
|
||||
}
|
||||
|
||||
static inline HRESULT
|
||||
SHELL_CreateFallbackExtractIconForNoAssocFile(REFIID riid, LPVOID *ppvOut)
|
||||
{
|
||||
const int id = IDI_SHELL_DOCUMENT;
|
||||
return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut);
|
||||
}
|
||||
|
|
|
@ -2112,32 +2112,22 @@ BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl)
|
|||
|
||||
BOOL _ILIsDrive(LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
|
||||
|
||||
TRACE("(%p)\n",pidl);
|
||||
|
||||
return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
|
||||
PT_DRIVE1 == lpPData->type ||
|
||||
PT_DRIVE2 == lpPData->type ||
|
||||
PT_DRIVE3 == lpPData->type));
|
||||
const BYTE type = _ILGetType(pidl);
|
||||
const BYTE fldrtype = (PT_DRIVE & PT_FOLDERTYPEMASK);
|
||||
return (type & PT_FOLDERTYPEMASK) == fldrtype && type != PT_COMPUTER_REGITEM;
|
||||
}
|
||||
|
||||
BOOL _ILIsFolder(LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
|
||||
|
||||
TRACE("(%p)\n",pidl);
|
||||
|
||||
return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
|
||||
/* A folder or a simple PT_FS with a child */
|
||||
const BYTE type = _ILGetFSType(pidl);
|
||||
return (type & PT_FS_FOLDER_FLAG) != 0 || (type == PT_FS && ILGetNext(pidl));
|
||||
}
|
||||
|
||||
BOOL _ILIsValue(LPCITEMIDLIST pidl)
|
||||
{
|
||||
LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
|
||||
|
||||
TRACE("(%p)\n",pidl);
|
||||
|
||||
return (pidl && lpPData && PT_VALUE == lpPData->type);
|
||||
const BYTE type = _ILGetFSType(pidl);
|
||||
return type && !(type & PT_FS_FOLDER_FLAG);
|
||||
}
|
||||
|
||||
BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl)
|
||||
|
@ -2281,6 +2271,9 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl)
|
|||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
if (_ILGetFSType(pidl) & PT_FS_UNICODE_FLAG)
|
||||
return (LPWSTR)pdata->u.file.szNames;
|
||||
|
||||
switch (pdata->type)
|
||||
{
|
||||
case PT_GUID:
|
||||
|
@ -2311,9 +2304,6 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl)
|
|||
/*return (LPSTR)&(pdata->u.network.szNames);*/
|
||||
return NULL;
|
||||
|
||||
case PT_VALUEW:
|
||||
return (LPWSTR)pdata->u.file.szNames;
|
||||
|
||||
#ifdef __REACTOS__ /* r54423 */
|
||||
case PT_CPLAPPLET:
|
||||
return pdata->u.cpanel.szName;
|
||||
|
@ -2439,7 +2429,7 @@ FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) {
|
|||
FileStructW *pFileStructW;
|
||||
WORD cbOffset;
|
||||
|
||||
if (!(_ILIsValue(pidl) || _ILIsFolder(pidl)))
|
||||
if (!_ILIsFolderOrFile(pidl))
|
||||
return NULL;
|
||||
|
||||
cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD));
|
||||
|
@ -2479,48 +2469,12 @@ FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) {
|
|||
*/
|
||||
BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt)
|
||||
{
|
||||
LPPIDLDATA pdata = _ILGetDataPointer(pidl);
|
||||
|
||||
if (!pdata)
|
||||
return FALSE;
|
||||
|
||||
switch (pdata->type)
|
||||
if (_ILGetFSType(pidl) > PT_FS) /* Only non-simple FS items have a date */
|
||||
{
|
||||
case PT_FOLDER:
|
||||
case PT_VALUE:
|
||||
DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
LPPIDLDATA pdata = _ILGetDataPointer(pidl);
|
||||
return DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL _ILGetFileDate(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
|
||||
{
|
||||
FILETIME ft,lft;
|
||||
SYSTEMTIME time;
|
||||
BOOL ret;
|
||||
|
||||
if (_ILGetFileDateTime( pidl, &ft ))
|
||||
{
|
||||
FileTimeToLocalFileTime(&ft, &lft);
|
||||
FileTimeToSystemTime (&lft, &time);
|
||||
|
||||
ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, pOut, uOutSize);
|
||||
if (ret)
|
||||
{
|
||||
/* Append space + time without seconds */
|
||||
pOut[ret - 1] = L' ';
|
||||
GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut[0] = UNICODE_NULL;
|
||||
ret = FALSE;
|
||||
}
|
||||
return ret;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -2543,15 +2497,13 @@ BOOL _ILGetFileDate(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
|
|||
DWORD _ILGetFileSize(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
|
||||
{
|
||||
LPPIDLDATA pdata = _ILGetDataPointer(pidl);
|
||||
DWORD dwSize;
|
||||
|
||||
if (!pdata)
|
||||
return 0;
|
||||
|
||||
switch (pdata->type)
|
||||
if (_ILGetFSType(pidl) & PT_FS_FILE_FLAG)
|
||||
{
|
||||
case PT_VALUE:
|
||||
dwSize = pdata->u.file.dwFileSize;
|
||||
/* FIXME: Handle INVALID_FILE_SIZE (get size from disk) */
|
||||
DWORD dwSize = pdata->u.file.dwFileSize;
|
||||
if (pOut)
|
||||
StrFormatKBSizeW(dwSize, pOut, uOutSize);
|
||||
return dwSize;
|
||||
|
|
|
@ -157,16 +157,6 @@ typedef struct tagPIDLPrinterStruct
|
|||
WCHAR szName[1];
|
||||
} PIDLPrinterStruct;
|
||||
|
||||
typedef struct tagPIDLRecycleStruct
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
ULARGE_INTEGER FileSize;
|
||||
ULARGE_INTEGER PhysicalFileSize;
|
||||
DWORD Attributes;
|
||||
WCHAR szName[1];
|
||||
} PIDLRecycleStruct;
|
||||
|
||||
#endif /* !__REACTOS__ */
|
||||
|
||||
typedef struct tagGUIDStruct
|
||||
|
@ -233,7 +223,6 @@ typedef struct tagPIDLDATA
|
|||
#ifdef __REACTOS__
|
||||
struct tagPIDLFontStruct cfont;
|
||||
struct tagPIDLPrinterStruct cprinter;
|
||||
struct tagPIDLRecycleStruct crecycle;
|
||||
#endif
|
||||
}u;
|
||||
} PIDLDATA, *LPPIDLDATA;
|
||||
|
@ -243,7 +232,6 @@ typedef struct tagPIDLDATA
|
|||
* getting special values from simple pidls
|
||||
*/
|
||||
DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN;
|
||||
BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN;
|
||||
DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN;
|
||||
BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN;
|
||||
DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN;
|
||||
|
@ -261,6 +249,7 @@ BOOL _ILIsMyDocuments (LPCITEMIDLIST pidl);
|
|||
BOOL _ILIsBitBucket (LPCITEMIDLIST pidl);
|
||||
BOOL _ILIsNetHood (LPCITEMIDLIST pidl);
|
||||
BOOL _ILIsControlPanel (LPCITEMIDLIST pidl);
|
||||
#define _ILIsFolderOrFile _ILGetFSType
|
||||
#endif
|
||||
BOOL _ILIsDrive (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN;
|
||||
BOOL _ILIsFolder (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -139,7 +139,7 @@ void FreeChangeNotifications(void) DECLSPEC_HIDDEN;
|
|||
BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pwszDir, BOOL bShowUI);
|
||||
BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir);
|
||||
|
||||
void WINAPI _InsertMenuItemW (HMENU hmenu, UINT indexMenu, BOOL fByPosition,
|
||||
BOOL WINAPI _InsertMenuItemW (HMENU hmenu, UINT indexMenu, BOOL fByPosition,
|
||||
UINT wID, UINT fType, LPCWSTR dwTypeData, UINT fState);
|
||||
|
||||
static __inline BOOL SHELL_OsIsUnicode(void)
|
||||
|
|
Loading…
Reference in a new issue