Skip to content

Commit d128939

Browse files
chrdavisChris Davis (EDGE)
and
Chris Davis (EDGE)
authored
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>
1 parent 6613522 commit d128939

12 files changed

+463
-106
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,5 @@ src/common/Telemetry/*.etl
342342
!**/MergeModules/Release/
343343
!**/MergeModules/Debug/
344344
/src/modules/previewpane/SvgThumbnailProvider/$(SolutionDir)$(Platform)/$(Configuration)/modules/FileExplorerPreview/SvgThumbnailProvider.xml
345+
/src/modules/powerrename/ui/RCa24464
346+
/src/modules/powerrename/ui/RCb24464

src/modules/powerrename/lib/Helpers.cpp

+29-69
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
275275
return hr;
276276
}
277277

278-
HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
278+
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
279279
{
280280
*items = nullptr;
281281
CComPtr<IDataObject> dataObj;
@@ -292,73 +292,6 @@ HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_
292292
return hr;
293293
}
294294

295-
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* psrm, _In_ int depth = 0)
296-
{
297-
HRESULT hr = E_INVALIDARG;
298-
299-
// We shouldn't get this deep since we only enum the contents of
300-
// regular folders but adding just in case
301-
if ((pesi) && (depth < (MAX_PATH / 2)))
302-
{
303-
hr = S_OK;
304-
305-
ULONG celtFetched;
306-
CComPtr<IShellItem> spsi;
307-
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)) && (SUCCEEDED(hr)))
308-
{
309-
CComPtr<IPowerRenameItemFactory> spsrif;
310-
hr = psrm->GetRenameItemFactory(&spsrif);
311-
if (SUCCEEDED(hr))
312-
{
313-
CComPtr<IPowerRenameItem> spNewItem;
314-
hr = spsrif->Create(spsi, &spNewItem);
315-
if (SUCCEEDED(hr))
316-
{
317-
spNewItem->PutDepth(depth);
318-
hr = psrm->AddItem(spNewItem);
319-
}
320-
321-
if (SUCCEEDED(hr))
322-
{
323-
bool isFolder = false;
324-
if (SUCCEEDED(spNewItem->GetIsFolder(&isFolder)) && isFolder)
325-
{
326-
// Bind to the IShellItem for the IEnumShellItems interface
327-
CComPtr<IEnumShellItems> spesiNext;
328-
hr = spsi->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spesiNext));
329-
if (SUCCEEDED(hr))
330-
{
331-
// Parse the folder contents recursively
332-
hr = _ParseEnumItems(spesiNext, psrm, depth + 1);
333-
}
334-
}
335-
}
336-
}
337-
338-
spsi = nullptr;
339-
}
340-
}
341-
342-
return hr;
343-
}
344-
345-
// Iterate through the data source and add paths to the rotation manager
346-
HRESULT EnumerateDataObject(_In_ IUnknown* dataSource, _In_ IPowerRenameManager* psrm)
347-
{
348-
CComPtr<IShellItemArray> spsia;
349-
HRESULT hr = E_FAIL;
350-
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
351-
{
352-
CComPtr<IEnumShellItems> spesi;
353-
if (SUCCEEDED(spsia->EnumItems(&spesi)))
354-
{
355-
hr = _ParseEnumItems(spesi, psrm);
356-
}
357-
}
358-
359-
return hr;
360-
}
361-
362295
BOOL GetEnumeratedFileName(__out_ecount(cchMax) PWSTR pszUniqueName, UINT cchMax, __in PCWSTR pszTemplate, __in_opt PCWSTR pszDir, unsigned long ulMinLong, __inout unsigned long* pulNumUsed)
363296
{
364297
PWSTR pszName = nullptr;
@@ -528,7 +461,7 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
528461
{
529462
bool hasRenamable = false;
530463
CComPtr<IShellItemArray> spsia;
531-
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
464+
if (SUCCEEDED(GetShellItemArrayFromDataObject(dataSource, &spsia)))
532465
{
533466
CComPtr<IEnumShellItems> spesi;
534467
if (SUCCEEDED(spsia->EnumItems(&spesi)))
@@ -549,3 +482,30 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
549482
}
550483
return hasRenamable;
551484
}
485+
486+
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
487+
{
488+
WNDCLASS wc = { 0 };
489+
PCWSTR wndClassName = L"MsgWindow";
490+
491+
wc.lpfnWndProc = DefWindowProc;
492+
wc.cbWndExtra = sizeof(void*);
493+
wc.hInstance = hInst;
494+
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
495+
wc.lpszClassName = wndClassName;
496+
497+
RegisterClass(&wc);
498+
499+
HWND hwnd = CreateWindowEx(
500+
0, wndClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInst, nullptr);
501+
if (hwnd)
502+
{
503+
SetWindowLongPtr(hwnd, 0, (LONG_PTR)p);
504+
if (pfnWndProc)
505+
{
506+
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pfnWndProc);
507+
}
508+
}
509+
510+
return hwnd;
511+
}

src/modules/powerrename/lib/Helpers.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
77
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime);
88
bool isFileTimeUsed(_In_ PCWSTR source);
99
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
10-
HRESULT EnumerateDataObject(_In_ IUnknown* pdo, _In_ IPowerRenameManager* psrm);
10+
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items);
1111
BOOL GetEnumeratedFileName(
1212
__out_ecount(cchMax) PWSTR pszUniqueName,
1313
UINT cchMax,
1414
__in PCWSTR pszTemplate,
1515
__in_opt PCWSTR pszDir,
1616
unsigned long ulMinLong,
1717
__inout unsigned long* pulNumUsed);
18+
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include "pch.h"
2+
#include "PowerRenameEnum.h"
3+
#include <ShlGuid.h>
4+
#include <helpers.h>
5+
6+
IFACEMETHODIMP_(ULONG) CPowerRenameEnum::AddRef()
7+
{
8+
return InterlockedIncrement(&m_refCount);
9+
}
10+
11+
IFACEMETHODIMP_(ULONG) CPowerRenameEnum::Release()
12+
{
13+
long refCount = InterlockedDecrement(&m_refCount);
14+
15+
if (refCount == 0)
16+
{
17+
delete this;
18+
}
19+
return refCount;
20+
}
21+
22+
IFACEMETHODIMP CPowerRenameEnum::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
23+
{
24+
static const QITAB qit[] = {
25+
QITABENT(CPowerRenameEnum, IPowerRenameEnum),
26+
{ 0 }
27+
};
28+
return QISearch(this, qit, riid, ppv);
29+
}
30+
31+
IFACEMETHODIMP CPowerRenameEnum::Start()
32+
{
33+
m_canceled = false;
34+
CComPtr<IShellItemArray> spsia;
35+
HRESULT hr = GetShellItemArrayFromDataObject(m_spdo, &spsia);
36+
if (SUCCEEDED(hr))
37+
{
38+
CComPtr<IEnumShellItems> spesi;
39+
hr = spsia->EnumItems(&spesi);
40+
if (SUCCEEDED(hr))
41+
{
42+
hr = _ParseEnumItems(spesi);
43+
}
44+
}
45+
46+
return hr;
47+
}
48+
49+
IFACEMETHODIMP CPowerRenameEnum::Cancel()
50+
{
51+
m_canceled = true;
52+
return S_OK;
53+
}
54+
55+
HRESULT CPowerRenameEnum::s_CreateInstance(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager, _In_ REFIID iid, _Outptr_ void** resultInterface)
56+
{
57+
*resultInterface = nullptr;
58+
59+
CPowerRenameEnum* newRenameEnum = new CPowerRenameEnum();
60+
HRESULT hr = newRenameEnum ? S_OK : E_OUTOFMEMORY;
61+
if (SUCCEEDED(hr))
62+
{
63+
hr = newRenameEnum->_Init(pdo, pManager);
64+
if (SUCCEEDED(hr))
65+
{
66+
hr = newRenameEnum->QueryInterface(iid, resultInterface);
67+
}
68+
69+
newRenameEnum->Release();
70+
}
71+
return hr;
72+
}
73+
74+
CPowerRenameEnum::CPowerRenameEnum() :
75+
m_refCount(1)
76+
{
77+
}
78+
79+
CPowerRenameEnum::~CPowerRenameEnum()
80+
{
81+
}
82+
83+
HRESULT CPowerRenameEnum::_Init(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager)
84+
{
85+
m_spdo = pdo;
86+
m_spsrm = pManager;
87+
return S_OK;
88+
}
89+
90+
HRESULT CPowerRenameEnum::_ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int depth)
91+
{
92+
HRESULT hr = E_INVALIDARG;
93+
94+
// We shouldn't get this deep since we only enum the contents of
95+
// regular folders but adding just in case
96+
if ((pesi) && (depth < (MAX_PATH / 2)))
97+
{
98+
hr = S_OK;
99+
100+
ULONG celtFetched;
101+
CComPtr<IShellItem> spsi;
102+
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)) && (SUCCEEDED(hr)))
103+
{
104+
if (m_canceled)
105+
{
106+
return E_ABORT;
107+
}
108+
109+
CComPtr<IPowerRenameItemFactory> spFactory;
110+
hr = m_spsrm->GetRenameItemFactory(&spFactory);
111+
if (SUCCEEDED(hr))
112+
{
113+
CComPtr<IPowerRenameItem> spNewItem;
114+
// Failure may be valid if we come across a shell item that does
115+
// not support a file system path. In that case we simply ignore
116+
// the item.
117+
if (SUCCEEDED(spFactory->Create(spsi, &spNewItem)))
118+
{
119+
spNewItem->PutDepth(depth);
120+
hr = m_spsrm->AddItem(spNewItem);
121+
if (SUCCEEDED(hr))
122+
{
123+
bool isFolder = false;
124+
if (SUCCEEDED(spNewItem->GetIsFolder(&isFolder)) && isFolder)
125+
{
126+
// Bind to the IShellItem for the IEnumShellItems interface
127+
CComPtr<IEnumShellItems> spesiNext;
128+
hr = spsi->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spesiNext));
129+
if (SUCCEEDED(hr))
130+
{
131+
// Parse the folder contents recursively
132+
hr = _ParseEnumItems(spesiNext, depth + 1);
133+
}
134+
}
135+
}
136+
}
137+
}
138+
139+
spsi = nullptr;
140+
}
141+
}
142+
143+
return hr;
144+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
#include "pch.h"
3+
#include "PowerRenameInterfaces.h"
4+
#include <vector>
5+
#include "srwlock.h"
6+
7+
class CPowerRenameEnum :
8+
public IPowerRenameEnum
9+
{
10+
public:
11+
// IUnknown
12+
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
13+
IFACEMETHODIMP_(ULONG) AddRef();
14+
IFACEMETHODIMP_(ULONG) Release();
15+
16+
// ISmartRenameEnum
17+
IFACEMETHODIMP Start();
18+
IFACEMETHODIMP Cancel();
19+
20+
public:
21+
static HRESULT s_CreateInstance(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager, _In_ REFIID iid, _Outptr_ void** resultInterface);
22+
23+
protected:
24+
CPowerRenameEnum();
25+
virtual ~CPowerRenameEnum();
26+
27+
HRESULT _Init(_In_ IUnknown* pdo, _In_ IPowerRenameManager* pManager);
28+
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int depth = 0);
29+
30+
CComPtr<IPowerRenameManager> m_spsrm;
31+
CComPtr<IUnknown> m_spdo;
32+
bool m_canceled = false;
33+
long m_refCount = 0;
34+
};

src/modules/powerrename/lib/PowerRenameInterfaces.h

+6
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,9 @@ interface __declspec(uuid("04AAFABE-B76E-4E13-993A-B5941F52B139")) IPowerRenameM
134134
IFACEMETHOD(AddMRUString)(_In_ PCWSTR entry) = 0;
135135
};
136136

137+
interface __declspec(uuid("CE8C8616-C1A8-457A-9601-10570F5B9F1F")) IPowerRenameEnum : public IUnknown
138+
{
139+
public:
140+
IFACEMETHOD(Start)() = 0;
141+
IFACEMETHOD(Cancel)() = 0;
142+
};

src/modules/powerrename/lib/PowerRenameLib.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
</ItemDefinitionGroup>
4141
<ItemGroup>
4242
<ClInclude Include="Helpers.h" />
43+
<ClInclude Include="PowerRenameEnum.h" />
4344
<ClInclude Include="PowerRenameItem.h" />
4445
<ClInclude Include="PowerRenameInterfaces.h" />
4546
<ClInclude Include="PowerRenameManager.h" />
@@ -52,6 +53,7 @@
5253
</ItemGroup>
5354
<ItemGroup>
5455
<ClCompile Include="Helpers.cpp" />
56+
<ClCompile Include="PowerRenameEnum.cpp" />
5557
<ClCompile Include="PowerRenameItem.cpp" />
5658
<ClCompile Include="PowerRenameManager.cpp" />
5759
<ClCompile Include="PowerRenameRegEx.cpp" />

src/modules/powerrename/lib/PowerRenameManager.cpp

-28
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,6 @@ namespace fs = std::filesystem;
1313

1414
extern HINSTANCE g_hInst;
1515

16-
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
17-
{
18-
WNDCLASS wc = { 0 };
19-
20-
PCWSTR wndClassName = L"MsgWindow";
21-
22-
wc.lpfnWndProc = DefWindowProc;
23-
wc.cbWndExtra = sizeof(void*);
24-
wc.hInstance = hInst;
25-
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
26-
wc.lpszClassName = wndClassName;
27-
28-
RegisterClass(&wc);
29-
30-
HWND hwnd = CreateWindowEx(
31-
0, wndClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInst, nullptr);
32-
if (hwnd)
33-
{
34-
SetWindowLongPtr(hwnd, 0, (LONG_PTR)p);
35-
if (pfnWndProc)
36-
{
37-
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pfnWndProc);
38-
}
39-
}
40-
41-
return hwnd;
42-
}
43-
4416
// The default FOF flags to use in the rename operations
4517
#define FOF_DEFAULTFLAGS (FOF_ALLOWUNDO | FOFX_ADDUNDORECORD | FOFX_SHOWELEVATIONPROMPT | FOF_RENAMEONCOLLISION)
4618

src/modules/powerrename/lib/pch.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <shobjidl.h>
1818
#include <shellapi.h>
1919
#include <shlwapi.h>
20+
#include <ShlObj_core.h>
2021

2122
#include <ProjectTelemetry.h>
2223

0 commit comments

Comments
 (0)