mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
[PowerRename] Fluent UX (#13678)
* PowerRename new UI * Add scrollviewer * Don't deploy PowerRenameUI_new * Visual updates * Visual updates * Updates * Update Resources.resw * Added docs button * Update MainWindow.xaml * Wire Docs button * RegEx -> regular expressions * Update Show only renamed list on search/replace text changed * Update Show only renamed list on search/replace text changed - proper fix Set searchTerm to NULL when cleared - fix Show only renamed files on clear searchTerm * Files/folders input error handling * Fix renaming with keeping UI window opened After renaming folder, all of it's children need path update. Without path update, further renaming of children items would fail. * Update only children, not all items with greater depth * Fix dictionary false positives * Remove .NET dep * Rename PowerRenameUI_new to PowerRenameUILib Rename executable PowerRenameUIHost to PowerRename Co-authored-by: Laute <Niels.Laute@philips.com>
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "PowerRenameExt.h"
|
||||
#include <PowerRenameUI.h>
|
||||
#include <PowerRenameItem.h>
|
||||
#include <PowerRenameManager.h>
|
||||
#include <trace.h>
|
||||
#include <Helpers.h>
|
||||
#include <common/themes/icon_helpers.h>
|
||||
@@ -11,6 +8,7 @@
|
||||
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/HDropIterator.h>
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
@@ -116,6 +114,11 @@ HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirs
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameMenu::InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
return RunPowerRename(pici, nullptr);
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameMenu::RunPowerRename(CMINVOKECOMMANDINFO* pici, IShellItemArray* psiItemArray)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
@@ -124,84 +127,119 @@ HRESULT CPowerRenameMenu::InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pici)
|
||||
(LOWORD(pici->lpVerb) == 0))
|
||||
{
|
||||
Trace::Invoked();
|
||||
InvokeStruct* pInvokeData = new (std::nothrow) InvokeStruct;
|
||||
hr = E_OUTOFMEMORY;
|
||||
if (pInvokeData)
|
||||
// Set the application path based on the location of the dll
|
||||
std::wstring path = get_module_folderpath(g_hInst);
|
||||
path = path + L"\\PowerRename.exe";
|
||||
LPTSTR lpApplicationName = (LPTSTR)path.c_str();
|
||||
// Create an anonymous pipe to stream filenames
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
HANDLE hReadPipe;
|
||||
HANDLE hWritePipe;
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0))
|
||||
{
|
||||
pInvokeData->hwndParent = pici->hwnd;
|
||||
hr = CoMarshalInterThreadInterfaceInStream(__uuidof(m_spdo), m_spdo, &(pInvokeData->pstrm));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SHCreateThread(s_PowerRenameUIThreadProc, pInvokeData, CTF_COINIT | CTF_PROCESS_REF, nullptr) ? S_OK : E_FAIL;
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pInvokeData->pstrm->Release(); // if we failed to create the thread, then we must release the stream
|
||||
}
|
||||
}
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
if (!SetHandleInformation(hWritePipe, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
CAtlFile writePipe(hWritePipe);
|
||||
|
||||
if (FAILED(hr))
|
||||
CString commandLine;
|
||||
commandLine.Format(_T("\"%s\""), lpApplicationName);
|
||||
|
||||
int nSize = commandLine.GetLength() + 1;
|
||||
LPTSTR lpszCommandLine = new TCHAR[nSize];
|
||||
_tcscpy_s(lpszCommandLine, nSize, commandLine);
|
||||
|
||||
STARTUPINFO startupInfo;
|
||||
ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
|
||||
startupInfo.cb = sizeof(STARTUPINFO);
|
||||
startupInfo.hStdInput = hReadPipe;
|
||||
startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
||||
if (pici)
|
||||
{
|
||||
startupInfo.wShowWindow = pici->nShow;
|
||||
}
|
||||
else
|
||||
{
|
||||
startupInfo.wShowWindow = SW_SHOWNORMAL;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
// Start the resizer
|
||||
CreateProcess(
|
||||
NULL,
|
||||
lpszCommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&startupInfo,
|
||||
&processInformation);
|
||||
delete[] lpszCommandLine;
|
||||
if (!CloseHandle(processInformation.hProcess))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
if (!CloseHandle(processInformation.hThread))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Stream the input files
|
||||
HDropIterator i(m_spdo);
|
||||
for (i.First(); !i.IsDone(); i.Next())
|
||||
{
|
||||
delete pInvokeData;
|
||||
CString fileName(i.CurrentItem());
|
||||
// File name can't contain '?'
|
||||
fileName.Append(_T("?"));
|
||||
|
||||
writePipe.Write(fileName, fileName.GetLength() * sizeof(TCHAR));
|
||||
}
|
||||
}
|
||||
Trace::InvokedRet(hr);
|
||||
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).
|
||||
DWORD fileCount = 0;
|
||||
// Gets the list of files currently selected using the IShellItemArray
|
||||
psiItemArray->GetCount(&fileCount);
|
||||
// Iterate over the list of files
|
||||
for (DWORD i = 0; i < fileCount; i++)
|
||||
{
|
||||
IShellItem* shellItem;
|
||||
psiItemArray->GetItemAt(i, &shellItem);
|
||||
LPWSTR itemName;
|
||||
// Retrieves the entire file system path of the file from its shell item
|
||||
shellItem->GetDisplayName(SIGDN_FILESYSPATH, &itemName);
|
||||
CString fileName(itemName);
|
||||
// File name can't contain '?'
|
||||
fileName.Append(_T("?"));
|
||||
// Write the file path into the input stream for image resizer
|
||||
writePipe.Write(fileName, fileName.GetLength() * sizeof(TCHAR));
|
||||
}
|
||||
}
|
||||
|
||||
writePipe.Close();
|
||||
}
|
||||
Trace::InvokedRet(hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
DWORD WINAPI CPowerRenameMenu::s_PowerRenameUIThreadProc(_In_ void* pData)
|
||||
{
|
||||
InvokeStruct* pInvokeData = static_cast<InvokeStruct*>(pData);
|
||||
CComPtr<IUnknown> dataSource;
|
||||
HRESULT hr = CoGetInterfaceAndReleaseStream(pInvokeData->pstrm, IID_PPV_ARGS(&dataSource));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Create the rename manager
|
||||
CComPtr<IPowerRenameManager> spsrm;
|
||||
hr = CPowerRenameManager::s_CreateInstance(&spsrm);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Create the factory for our items
|
||||
CComPtr<IPowerRenameItemFactory> spsrif;
|
||||
hr = CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&spsrif));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Pass the factory to the manager
|
||||
hr = spsrm->PutRenameItemFactory(spsrif);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Create the rename UI instance and pass the rename manager
|
||||
CComPtr<IPowerRenameUI> spsrui;
|
||||
hr = CPowerRenameUI::s_CreateInstance(spsrm, dataSource, false, &spsrui);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IDataObject* dummy;
|
||||
// If we're running on a local COM server, we need to decrement module refcount, which was previously incremented in CPowerRenameMenu::Invoke.
|
||||
if (SUCCEEDED(dataSource->QueryInterface(IID_IShellItemArray, reinterpret_cast<void**>(&dummy))))
|
||||
{
|
||||
ModuleRelease();
|
||||
}
|
||||
// Call blocks until we are done
|
||||
spsrui->Show(pInvokeData->hwndParent);
|
||||
spsrui->Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to call shutdown to break circular dependencies
|
||||
spsrm->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
delete pInvokeData;
|
||||
|
||||
Trace::UIShownRet(hr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT __stdcall CPowerRenameMenu::GetTitle(IShellItemArray* /*psiItemArray*/, LPWSTR* ppszName)
|
||||
{
|
||||
return SHStrDup(app_name.c_str(), ppszName);
|
||||
@@ -261,7 +299,7 @@ HRESULT __stdcall CPowerRenameMenu::Invoke(IShellItemArray* psiItemArray, IBindC
|
||||
}
|
||||
// Prevent Shutting down before PowerRenameUI is created
|
||||
ModuleAddRef();
|
||||
hr = SHCreateThread(s_PowerRenameUIThreadProc, pInvokeData, CTF_COINIT | CTF_PROCESS_REF, nullptr) ? S_OK : E_FAIL;
|
||||
hr = RunPowerRename(nullptr, psiItemArray);
|
||||
}
|
||||
Trace::InvokedRet(hr);
|
||||
return S_OK;
|
||||
|
||||
Reference in New Issue
Block a user