[PowerRename] Add PowerRename to directory background context menu (#24522)

* Add PowerRename to directory background context menu

* Fix analyzer error

* Add more checks
This commit is contained in:
Stefan Markovic
2023-03-08 14:51:33 +01:00
committed by GitHub
parent 65378200c6
commit 58015feb3a
5 changed files with 37 additions and 26 deletions

View File

@@ -742,7 +742,7 @@ IDD
IDesktop IDesktop
IDirect IDirect
idl idl
IDLIST idlist
IDOn IDOn
IDR IDR
idx idx

View File

@@ -28,6 +28,9 @@
<RegistryKey Root="HKLM" Key="SOFTWARE\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\PowerRenameExt"> <RegistryKey Root="HKLM" Key="SOFTWARE\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\PowerRenameExt">
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/> <RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
</RegistryKey> </RegistryKey>
<RegistryKey Root="HKLM" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\PowerRenameExt">
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
</RegistryKey>
</Component> </Component>
</DirectoryRef> </DirectoryRef>

View File

@@ -93,12 +93,6 @@ public:
{ {
*cmdState = ECS_ENABLED; *cmdState = ECS_ENABLED;
// We've observed that it's possible that a null gets passed instead of an empty array. Just don't show the context menu in this case.
if (nullptr == selection) {
*cmdState = ECS_HIDDEN;
return S_OK;
}
if (!CSettingsInstance().GetEnabled()) if (!CSettingsInstance().GetEnabled())
{ {
*cmdState = ECS_HIDDEN; *cmdState = ECS_HIDDEN;
@@ -112,6 +106,12 @@ public:
return S_OK; return S_OK;
} }
// When right clicking directory background, selection is empty. This prevents checking if there
// are renamable items, but internal PowerRename logic will prevent renaming non-renamable items anyway.
if (nullptr == selection) {
return S_OK;
}
// Check if at least one of the selected items is actually renamable. // Check if at least one of the selected items is actually renamable.
if (!ShellItemArrayContainsRenamableItem(selection)) if (!ShellItemArrayContainsRenamableItem(selection))
{ {

View File

@@ -46,14 +46,26 @@ HRESULT CPowerRenameMenu::s_CreateInstance(_In_opt_ IUnknown*, _In_ REFIID riid,
} }
// IShellExtInit // IShellExtInit
HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject* pdtobj, HKEY) HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE idlist, _In_ IDataObject* pdtobj, HKEY)
{ {
// Check if we have disabled ourselves // Check if we have disabled ourselves
if (!CSettingsInstance().GetEnabled()) if (!CSettingsInstance().GetEnabled())
return E_FAIL; return E_FAIL;
// Cache the data object to be used later // Cache the data object to be used later
if (idlist != NULL)
{
CComPtr<IShellItemArray> spsia;
if (SUCCEEDED(SHCreateShellItemArrayFromIDLists(1, &idlist, &spsia)) && spsia != NULL)
{
spsia->BindToHandler(NULL, BHID_DataObject, IID_IDataObject, reinterpret_cast<void**>(&m_spdo));
}
}
else
{
m_spdo = pdtobj; m_spdo = pdtobj;
}
return S_OK; return S_OK;
} }
@@ -124,7 +136,7 @@ HRESULT CPowerRenameMenu::RunPowerRename(CMINVOKECOMMANDINFO* pici, IShellItemAr
HRESULT hr = E_FAIL; HRESULT hr = E_FAIL;
if (CSettingsInstance().GetEnabled() && if (CSettingsInstance().GetEnabled() &&
(IS_INTRESOURCE(pici->lpVerb)) && pici && (IS_INTRESOURCE(pici->lpVerb)) &&
(LOWORD(pici->lpVerb) == 0)) (LOWORD(pici->lpVerb) == 0))
{ {
Trace::Invoked(); Trace::Invoked();
@@ -163,14 +175,7 @@ HRESULT CPowerRenameMenu::RunPowerRename(CMINVOKECOMMANDINFO* pici, IShellItemAr
startupInfo.cb = sizeof(STARTUPINFO); startupInfo.cb = sizeof(STARTUPINFO);
startupInfo.hStdInput = hReadPipe; startupInfo.hStdInput = hReadPipe;
startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
if (pici)
{
startupInfo.wShowWindow = static_cast<WORD>(pici->nShow); startupInfo.wShowWindow = static_cast<WORD>(pici->nShow);
}
else
{
startupInfo.wShowWindow = SW_SHOWNORMAL;
}
PROCESS_INFORMATION processInformation; PROCESS_INFORMATION processInformation;
@@ -200,6 +205,8 @@ HRESULT CPowerRenameMenu::RunPowerRename(CMINVOKECOMMANDINFO* pici, IShellItemAr
// psiItemArray is NULL if called from InvokeCommand. This part is used for the MSI installer. It is not NULL if it is called from Invoke (MSIX). // psiItemArray is NULL if called from InvokeCommand. This part is used for the MSI installer. It is not NULL if it is called from Invoke (MSIX).
if (!psiItemArray) if (!psiItemArray)
{
if (m_spdo)
{ {
// Stream the input files // Stream the input files
HDropIterator i(m_spdo); HDropIterator i(m_spdo);
@@ -212,6 +219,7 @@ HRESULT CPowerRenameMenu::RunPowerRename(CMINVOKECOMMANDINFO* pici, IShellItemAr
writePipe.Write(fileName, fileName.GetLength() * sizeof(TCHAR)); writePipe.Write(fileName, fileName.GetLength() * sizeof(TCHAR));
} }
} }
}
else else
{ {
//m_pdtobj will be NULL when invoked from the MSIX build as Initialize is never called (IShellExtInit functions aren't called in case of MSIX). //m_pdtobj will be NULL when invoked from the MSIX build as Initialize is never called (IShellExtInit functions aren't called in case of MSIX).

View File

@@ -551,7 +551,7 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
{ {
bool hasRenamable = false; bool hasRenamable = false;
CComPtr<IShellItemArray> spsia; CComPtr<IShellItemArray> spsia;
if (SUCCEEDED(GetShellItemArrayFromDataObject(dataSource, &spsia))) if (dataSource && SUCCEEDED(GetShellItemArrayFromDataObject(dataSource, &spsia)))
{ {
CComPtr<IEnumShellItems> spesi; CComPtr<IEnumShellItems> spesi;
if (SUCCEEDED(spsia->EnumItems(&spesi))) if (SUCCEEDED(spsia->EnumItems(&spesi)))