mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 04:07:40 +02:00
Show progress dialog during startup (#9255)
* Show progress dialog during startup for selection enumeration that can take a long time. * Updated with better code organization and a timer to ensure the progress dialog does not appear in most cases. * Update based on PR feedback * Change progress dialog delay from 1500ms to 2500ms * Move progress dialog invocation off the main UI thread Co-authored-by: Chris Davis (EDGE) <chrdavis@microsoft.com>
This commit is contained in:
@@ -275,7 +275,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
|
||||
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
|
||||
{
|
||||
*items = nullptr;
|
||||
CComPtr<IDataObject> dataObj;
|
||||
@@ -292,73 +292,6 @@ HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* psrm, _In_ int depth = 0)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
// We shouldn't get this deep since we only enum the contents of
|
||||
// regular folders but adding just in case
|
||||
if ((pesi) && (depth < (MAX_PATH / 2)))
|
||||
{
|
||||
hr = S_OK;
|
||||
|
||||
ULONG celtFetched;
|
||||
CComPtr<IShellItem> spsi;
|
||||
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)) && (SUCCEEDED(hr)))
|
||||
{
|
||||
CComPtr<IPowerRenameItemFactory> spsrif;
|
||||
hr = psrm->GetRenameItemFactory(&spsrif);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CComPtr<IPowerRenameItem> spNewItem;
|
||||
hr = spsrif->Create(spsi, &spNewItem);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
spNewItem->PutDepth(depth);
|
||||
hr = psrm->AddItem(spNewItem);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
bool isFolder = false;
|
||||
if (SUCCEEDED(spNewItem->GetIsFolder(&isFolder)) && isFolder)
|
||||
{
|
||||
// Bind to the IShellItem for the IEnumShellItems interface
|
||||
CComPtr<IEnumShellItems> spesiNext;
|
||||
hr = spsi->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spesiNext));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Parse the folder contents recursively
|
||||
hr = _ParseEnumItems(spesiNext, psrm, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spsi = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Iterate through the data source and add paths to the rotation manager
|
||||
HRESULT EnumerateDataObject(_In_ IUnknown* dataSource, _In_ IPowerRenameManager* psrm)
|
||||
{
|
||||
CComPtr<IShellItemArray> spsia;
|
||||
HRESULT hr = E_FAIL;
|
||||
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
|
||||
{
|
||||
CComPtr<IEnumShellItems> spesi;
|
||||
if (SUCCEEDED(spsia->EnumItems(&spesi)))
|
||||
{
|
||||
hr = _ParseEnumItems(spesi, psrm);
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
BOOL GetEnumeratedFileName(__out_ecount(cchMax) PWSTR pszUniqueName, UINT cchMax, __in PCWSTR pszTemplate, __in_opt PCWSTR pszDir, unsigned long ulMinLong, __inout unsigned long* pulNumUsed)
|
||||
{
|
||||
PWSTR pszName = nullptr;
|
||||
@@ -528,7 +461,7 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
|
||||
{
|
||||
bool hasRenamable = false;
|
||||
CComPtr<IShellItemArray> spsia;
|
||||
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
|
||||
if (SUCCEEDED(GetShellItemArrayFromDataObject(dataSource, &spsia)))
|
||||
{
|
||||
CComPtr<IEnumShellItems> spesi;
|
||||
if (SUCCEEDED(spsia->EnumItems(&spesi)))
|
||||
@@ -549,3 +482,30 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
|
||||
}
|
||||
return hasRenamable;
|
||||
}
|
||||
|
||||
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
|
||||
{
|
||||
WNDCLASS wc = { 0 };
|
||||
PCWSTR wndClassName = L"MsgWindow";
|
||||
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.cbWndExtra = sizeof(void*);
|
||||
wc.hInstance = hInst;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||||
wc.lpszClassName = wndClassName;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
0, wndClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInst, nullptr);
|
||||
if (hwnd)
|
||||
{
|
||||
SetWindowLongPtr(hwnd, 0, (LONG_PTR)p);
|
||||
if (pfnWndProc)
|
||||
{
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pfnWndProc);
|
||||
}
|
||||
}
|
||||
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime);
|
||||
bool isFileTimeUsed(_In_ PCWSTR source);
|
||||
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
|
||||
HRESULT EnumerateDataObject(_In_ IUnknown* pdo, _In_ IPowerRenameManager* psrm);
|
||||
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items);
|
||||
BOOL GetEnumeratedFileName(
|
||||
__out_ecount(cchMax) PWSTR pszUniqueName,
|
||||
UINT cchMax,
|
||||
@@ -15,3 +15,4 @@ BOOL GetEnumeratedFileName(
|
||||
__in_opt PCWSTR pszDir,
|
||||
unsigned long ulMinLong,
|
||||
__inout unsigned long* pulNumUsed);
|
||||
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
|
||||
|
||||
144
src/modules/powerrename/lib/PowerRenameEnum.cpp
Normal file
144
src/modules/powerrename/lib/PowerRenameEnum.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "pch.h"
|
||||
#include "PowerRenameEnum.h"
|
||||
#include <ShlGuid.h>
|
||||
#include <helpers.h>
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameEnum::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) CPowerRenameEnum::Release()
|
||||
{
|
||||
long refCount = InterlockedDecrement(&m_refCount);
|
||||
|
||||
if (refCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CPowerRenameEnum::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(CPowerRenameEnum, IPowerRenameEnum),
|
||||
{ 0 }
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CPowerRenameEnum::Start()
|
||||
{
|
||||
m_canceled = false;
|
||||
CComPtr<IShellItemArray> spsia;
|
||||
HRESULT hr = GetShellItemArrayFromDataObject(m_spdo, &spsia);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CComPtr<IEnumShellItems> spesi;
|
||||
hr = spsia->EnumItems(&spesi);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _ParseEnumItems(spesi);
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CPowerRenameEnum::Cancel()
|
||||
{
|
||||
m_canceled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameEnum::s_CreateInstance(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager, _In_ REFIID iid, _Outptr_ void** resultInterface)
|
||||
{
|
||||
*resultInterface = nullptr;
|
||||
|
||||
CPowerRenameEnum* newRenameEnum = new CPowerRenameEnum();
|
||||
HRESULT hr = newRenameEnum ? S_OK : E_OUTOFMEMORY;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = newRenameEnum->_Init(pdo, pManager);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = newRenameEnum->QueryInterface(iid, resultInterface);
|
||||
}
|
||||
|
||||
newRenameEnum->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CPowerRenameEnum::CPowerRenameEnum() :
|
||||
m_refCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
CPowerRenameEnum::~CPowerRenameEnum()
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameEnum::_Init(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager)
|
||||
{
|
||||
m_spdo = pdo;
|
||||
m_spsrm = pManager;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CPowerRenameEnum::_ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int depth)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
// We shouldn't get this deep since we only enum the contents of
|
||||
// regular folders but adding just in case
|
||||
if ((pesi) && (depth < (MAX_PATH / 2)))
|
||||
{
|
||||
hr = S_OK;
|
||||
|
||||
ULONG celtFetched;
|
||||
CComPtr<IShellItem> spsi;
|
||||
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)) && (SUCCEEDED(hr)))
|
||||
{
|
||||
if (m_canceled)
|
||||
{
|
||||
return E_ABORT;
|
||||
}
|
||||
|
||||
CComPtr<IPowerRenameItemFactory> spFactory;
|
||||
hr = m_spsrm->GetRenameItemFactory(&spFactory);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CComPtr<IPowerRenameItem> spNewItem;
|
||||
// Failure may be valid if we come across a shell item that does
|
||||
// not support a file system path. In that case we simply ignore
|
||||
// the item.
|
||||
if (SUCCEEDED(spFactory->Create(spsi, &spNewItem)))
|
||||
{
|
||||
spNewItem->PutDepth(depth);
|
||||
hr = m_spsrm->AddItem(spNewItem);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
bool isFolder = false;
|
||||
if (SUCCEEDED(spNewItem->GetIsFolder(&isFolder)) && isFolder)
|
||||
{
|
||||
// Bind to the IShellItem for the IEnumShellItems interface
|
||||
CComPtr<IEnumShellItems> spesiNext;
|
||||
hr = spsi->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spesiNext));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Parse the folder contents recursively
|
||||
hr = _ParseEnumItems(spesiNext, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spsi = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
34
src/modules/powerrename/lib/PowerRenameEnum.h
Normal file
34
src/modules/powerrename/lib/PowerRenameEnum.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "PowerRenameInterfaces.h"
|
||||
#include <vector>
|
||||
#include "srwlock.h"
|
||||
|
||||
class CPowerRenameEnum :
|
||||
public IPowerRenameEnum
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// ISmartRenameEnum
|
||||
IFACEMETHODIMP Start();
|
||||
IFACEMETHODIMP Cancel();
|
||||
|
||||
public:
|
||||
static HRESULT s_CreateInstance(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager, _In_ REFIID iid, _Outptr_ void** resultInterface);
|
||||
|
||||
protected:
|
||||
CPowerRenameEnum();
|
||||
virtual ~CPowerRenameEnum();
|
||||
|
||||
HRESULT _Init(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager);
|
||||
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int depth = 0);
|
||||
|
||||
CComPtr<IPowerRenameManager> m_spsrm;
|
||||
CComPtr<IUnknown> m_spdo;
|
||||
bool m_canceled = false;
|
||||
long m_refCount = 0;
|
||||
};
|
||||
@@ -134,3 +134,9 @@ public:
|
||||
IFACEMETHOD(AddMRUString)(_In_ PCWSTR entry) = 0;
|
||||
};
|
||||
|
||||
interface __declspec(uuid("CE8C8616-C1A8-457A-9601-10570F5B9F1F")) IPowerRenameEnum : public IUnknown
|
||||
{
|
||||
public:
|
||||
IFACEMETHOD(Start)() = 0;
|
||||
IFACEMETHOD(Cancel)() = 0;
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="PowerRenameEnum.h" />
|
||||
<ClInclude Include="PowerRenameItem.h" />
|
||||
<ClInclude Include="PowerRenameInterfaces.h" />
|
||||
<ClInclude Include="PowerRenameManager.h" />
|
||||
@@ -52,6 +53,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Helpers.cpp" />
|
||||
<ClCompile Include="PowerRenameEnum.cpp" />
|
||||
<ClCompile Include="PowerRenameItem.cpp" />
|
||||
<ClCompile Include="PowerRenameManager.cpp" />
|
||||
<ClCompile Include="PowerRenameRegEx.cpp" />
|
||||
|
||||
@@ -13,34 +13,6 @@ namespace fs = std::filesystem;
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
|
||||
{
|
||||
WNDCLASS wc = { 0 };
|
||||
|
||||
PCWSTR wndClassName = L"MsgWindow";
|
||||
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.cbWndExtra = sizeof(void*);
|
||||
wc.hInstance = hInst;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||||
wc.lpszClassName = wndClassName;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
0, wndClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInst, nullptr);
|
||||
if (hwnd)
|
||||
{
|
||||
SetWindowLongPtr(hwnd, 0, (LONG_PTR)p);
|
||||
if (pfnWndProc)
|
||||
{
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pfnWndProc);
|
||||
}
|
||||
}
|
||||
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
// The default FOF flags to use in the rename operations
|
||||
#define FOF_DEFAULTFLAGS (FOF_ALLOWUNDO | FOFX_ADDUNDORECORD | FOFX_SHOWELEVATIONPROMPT | FOF_RENAMEONCOLLISION)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <shobjidl.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <ShlObj_core.h>
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user