Check the shell attributes of the items to see if we should show the Power Rename menu item and or perform a rename. Also fix a unit test for the SVG Thumbnail Provider. (#5158)

This commit is contained in:
Chris Davis
2020-07-22 13:27:58 -07:00
committed by GitHub
parent 14247fa75a
commit 3acc96cab1
6 changed files with 61 additions and 15 deletions

View File

@@ -67,6 +67,10 @@ HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirs
if (CSettingsInstance().GetExtendedContextMenuOnly() && (!(uFlags & CMF_EXTENDEDVERBS)))
return E_FAIL;
// Check if at least one of the selected items is actually renamable.
if (!DataObjectContainsRenamableItem(m_spdo))
return E_FAIL;
HRESULT hr = E_UNEXPECTED;
if (m_spdo && !(uFlags & (CMF_DEFAULTONLY | CMF_VERBSONLY | CMF_OPTIMIZEFORINVOKE)))
{

View File

@@ -9,7 +9,7 @@ namespace fs = std::filesystem;
HRESULT GetTrimmedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source)
{
HRESULT hr = (source && wcslen(source) > 0) ? S_OK : E_INVALIDARG;
HRESULT hr = (source && wcslen(source) > 0) ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hr))
{
PWSTR newName = nullptr;
@@ -226,6 +226,23 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
return hr;
}
HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
{
*items = nullptr;
CComPtr<IDataObject> dataObj;
HRESULT hr;
if (SUCCEEDED(dataSource->QueryInterface(IID_PPV_ARGS(&dataObj))))
{
hr = SHCreateShellItemArrayFromDataObject(dataObj, IID_PPV_ARGS(items));
}
else
{
hr = dataSource->QueryInterface(IID_PPV_ARGS(items));
}
return hr;
}
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* psrm, _In_ int depth = 0)
{
HRESULT hr = E_INVALIDARG;
@@ -280,16 +297,7 @@ HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* ps
HRESULT EnumerateDataObject(_In_ IUnknown* dataSource, _In_ IPowerRenameManager* psrm)
{
CComPtr<IShellItemArray> spsia;
IDataObject* dataObj{};
HRESULT hr;
if (SUCCEEDED(dataSource->QueryInterface(IID_IDataObject, reinterpret_cast<void**>(&dataObj))))
{
hr = SHCreateShellItemArrayFromDataObject(dataObj, IID_PPV_ARGS(&spsia));
}
else
{
hr = dataSource->QueryInterface(IID_IShellItemArray, reinterpret_cast<void**>(&spsia));
}
HRESULT hr = _GetShellItemArrayFromDataOject(dataSource, &spsia);
if (SUCCEEDED(hr))
{
CComPtr<IEnumShellItems> spesi;
@@ -465,3 +473,31 @@ BOOL GetEnumeratedFileName(__out_ecount(cchMax) PWSTR pszUniqueName, UINT cchMax
return fRet;
}
// Iterate through the data source and checks if at least 1 item has SFGAO_CANRENAME.
// We do not enumerate child items - only the items the user selected.
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
{
bool hasRenamable = false;
CComPtr<IShellItemArray> spsia;
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
{
CComPtr<IEnumShellItems> spesi;
if (SUCCEEDED(spsia->EnumItems(&spesi)))
{
ULONG celtFetched;
CComPtr<IShellItem> spsi;
while ((S_OK == spesi->Next(1, &spsi, &celtFetched)))
{
SFGAOF attrs;
if (SUCCEEDED(spsi->GetAttributes(SFGAO_CANRENAME, &attrs)) &&
attrs & SFGAO_CANRENAME)
{
hasRenamable = true;
break;
}
}
}
}
return hasRenamable;
}

View File

@@ -6,6 +6,7 @@
HRESULT GetTrimmedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source);
HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, DWORD flags);
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME LocalTime);
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
HRESULT EnumerateDataObject(_In_ IUnknown* pdo, _In_ IPowerRenameManager* psrm);
BOOL GetEnumeratedFileName(
__out_ecount(cchMax) PWSTR pszUniqueName,

View File

@@ -177,7 +177,7 @@ IFACEMETHODIMP CPowerRenameItem::ShouldRenameItem(_In_ DWORD flags, _Out_ bool*
bool excludeBecauseFolder = (m_isFolder && (flags & PowerRenameFlags::ExcludeFolders));
bool excludeBecauseFile = (!m_isFolder && (flags & PowerRenameFlags::ExcludeFiles));
bool excludeBecauseSubFolderContent = (m_depth > 0 && (flags & PowerRenameFlags::ExcludeSubfolders));
*shouldRename = (m_selected && hasChanged && !excludeBecauseFile &&
*shouldRename = (m_selected && m_canRename && hasChanged && !excludeBecauseFile &&
!excludeBecauseFolder && !excludeBecauseSubFolderContent);
return S_OK;
@@ -237,12 +237,16 @@ HRESULT CPowerRenameItem::_Init(_In_ IShellItem* psi)
if (SUCCEEDED(hr))
{
// Check if we are a folder now so we can check this attribute quickly later
// Also check if the shell allows us to rename the item.
SFGAOF att = 0;
hr = psi->GetAttributes(SFGAO_STREAM | SFGAO_FOLDER, &att);
hr = psi->GetAttributes(SFGAO_STREAM | SFGAO_FOLDER | SFGAO_CANRENAME, &att);
if (SUCCEEDED(hr))
{
// Some items can be both folders and streams (ex: zip folders).
m_isFolder = (att & SFGAO_FOLDER) && !(att & SFGAO_STREAM);
// The shell lets us know if an item should not be renamed
// (ex: user profile director, windows dir, etc).
m_canRename = (att & SFGAO_CANRENAME);
}
}
}

View File

@@ -50,6 +50,7 @@ protected:
bool m_selected = true;
bool m_isFolder = false;
bool m_isDateParsed = false;
bool m_canRename = true;
int m_id = -1;
int m_iconIndex = -1;
UINT m_depth = 0;

View File

@@ -33,7 +33,7 @@ namespace SvgThumbnailProviderUnitTests
}
[TestMethod]
public void CheckBlockedElements_ShouldReturnNullBitmap_IfBlockedElementsIsPresentInNestedLevel()
public void CheckBlockedElements_ShouldReturnNonNullBitmap_IfBlockedElementsIsPresentInNestedLevel()
{
var svgBuilder = new StringBuilder();
svgBuilder.AppendLine("<svg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\">");
@@ -43,7 +43,7 @@ namespace SvgThumbnailProviderUnitTests
svgBuilder.AppendLine("</svg>");
Bitmap thumbnail = SvgThumbnailProvider.SvgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
Assert.IsTrue(thumbnail == null);
Assert.IsTrue(thumbnail != null);
}
[TestMethod]