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:
parent
6613522e53
commit
d128939227
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -342,3 +342,5 @@ src/common/Telemetry/*.etl
|
||||||
!**/MergeModules/Release/
|
!**/MergeModules/Release/
|
||||||
!**/MergeModules/Debug/
|
!**/MergeModules/Debug/
|
||||||
/src/modules/previewpane/SvgThumbnailProvider/$(SolutionDir)$(Platform)/$(Configuration)/modules/FileExplorerPreview/SvgThumbnailProvider.xml
|
/src/modules/previewpane/SvgThumbnailProvider/$(SolutionDir)$(Platform)/$(Configuration)/modules/FileExplorerPreview/SvgThumbnailProvider.xml
|
||||||
|
/src/modules/powerrename/ui/RCa24464
|
||||||
|
/src/modules/powerrename/ui/RCb24464
|
||||||
|
|
|
@ -275,7 +275,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
|
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items)
|
||||||
{
|
{
|
||||||
*items = nullptr;
|
*items = nullptr;
|
||||||
CComPtr<IDataObject> dataObj;
|
CComPtr<IDataObject> dataObj;
|
||||||
|
@ -292,73 +292,6 @@ HRESULT _GetShellItemArrayFromDataOject(_In_ IUnknown* dataSource, _COM_Outptr_
|
||||||
return hr;
|
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)
|
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;
|
PWSTR pszName = nullptr;
|
||||||
|
@ -528,7 +461,7 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
|
||||||
{
|
{
|
||||||
bool hasRenamable = false;
|
bool hasRenamable = false;
|
||||||
CComPtr<IShellItemArray> spsia;
|
CComPtr<IShellItemArray> spsia;
|
||||||
if (SUCCEEDED(_GetShellItemArrayFromDataOject(dataSource, &spsia)))
|
if (SUCCEEDED(GetShellItemArrayFromDataObject(dataSource, &spsia)))
|
||||||
{
|
{
|
||||||
CComPtr<IEnumShellItems> spesi;
|
CComPtr<IEnumShellItems> spesi;
|
||||||
if (SUCCEEDED(spsia->EnumItems(&spesi)))
|
if (SUCCEEDED(spsia->EnumItems(&spesi)))
|
||||||
|
@ -549,3 +482,30 @@ bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource)
|
||||||
}
|
}
|
||||||
return hasRenamable;
|
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);
|
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime);
|
||||||
bool isFileTimeUsed(_In_ PCWSTR source);
|
bool isFileTimeUsed(_In_ PCWSTR source);
|
||||||
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
|
bool DataObjectContainsRenamableItem(_In_ IUnknown* dataSource);
|
||||||
HRESULT EnumerateDataObject(_In_ IUnknown* pdo, _In_ IPowerRenameManager* psrm);
|
HRESULT GetShellItemArrayFromDataObject(_In_ IUnknown* dataSource, _COM_Outptr_ IShellItemArray** items);
|
||||||
BOOL GetEnumeratedFileName(
|
BOOL GetEnumeratedFileName(
|
||||||
__out_ecount(cchMax) PWSTR pszUniqueName,
|
__out_ecount(cchMax) PWSTR pszUniqueName,
|
||||||
UINT cchMax,
|
UINT cchMax,
|
||||||
|
@ -15,3 +15,4 @@ BOOL GetEnumeratedFileName(
|
||||||
__in_opt PCWSTR pszDir,
|
__in_opt PCWSTR pszDir,
|
||||||
unsigned long ulMinLong,
|
unsigned long ulMinLong,
|
||||||
__inout unsigned long* pulNumUsed);
|
__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;
|
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>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Helpers.h" />
|
<ClInclude Include="Helpers.h" />
|
||||||
|
<ClInclude Include="PowerRenameEnum.h" />
|
||||||
<ClInclude Include="PowerRenameItem.h" />
|
<ClInclude Include="PowerRenameItem.h" />
|
||||||
<ClInclude Include="PowerRenameInterfaces.h" />
|
<ClInclude Include="PowerRenameInterfaces.h" />
|
||||||
<ClInclude Include="PowerRenameManager.h" />
|
<ClInclude Include="PowerRenameManager.h" />
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Helpers.cpp" />
|
<ClCompile Include="Helpers.cpp" />
|
||||||
|
<ClCompile Include="PowerRenameEnum.cpp" />
|
||||||
<ClCompile Include="PowerRenameItem.cpp" />
|
<ClCompile Include="PowerRenameItem.cpp" />
|
||||||
<ClCompile Include="PowerRenameManager.cpp" />
|
<ClCompile Include="PowerRenameManager.cpp" />
|
||||||
<ClCompile Include="PowerRenameRegEx.cpp" />
|
<ClCompile Include="PowerRenameRegEx.cpp" />
|
||||||
|
|
|
@ -13,34 +13,6 @@ namespace fs = std::filesystem;
|
||||||
|
|
||||||
extern HINSTANCE g_hInst;
|
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
|
// The default FOF flags to use in the rename operations
|
||||||
#define FOF_DEFAULTFLAGS (FOF_ALLOWUNDO | FOFX_ADDUNDORECORD | FOFX_SHOWELEVATIONPROMPT | FOF_RENAMEONCOLLISION)
|
#define FOF_DEFAULTFLAGS (FOF_ALLOWUNDO | FOFX_ADDUNDORECORD | FOFX_SHOWELEVATIONPROMPT | FOF_RENAMEONCOLLISION)
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
#include <ShlObj_core.h>
|
||||||
|
|
||||||
#include <ProjectTelemetry.h>
|
#include <ProjectTelemetry.h>
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
#include <Shlobj.h>
|
#include <Shlobj.h>
|
||||||
#include <helpers.h>
|
#include <helpers.h>
|
||||||
|
#include <PowerRenameEnum.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <trace.h>
|
#include <trace.h>
|
||||||
|
@ -167,6 +168,17 @@ IFACEMETHODIMP CPowerRenameUI::GetShowUI(_Out_ bool* showUI)
|
||||||
// IPowerRenameManagerEvents
|
// IPowerRenameManagerEvents
|
||||||
IFACEMETHODIMP CPowerRenameUI::OnItemAdded(_In_ IPowerRenameItem*)
|
IFACEMETHODIMP CPowerRenameUI::OnItemAdded(_In_ IPowerRenameItem*)
|
||||||
{
|
{
|
||||||
|
// Check if the user canceled the enumeration from the progress dialog UI
|
||||||
|
if (m_prpui.IsCanceled())
|
||||||
|
{
|
||||||
|
m_prpui.Stop();
|
||||||
|
if (m_sppre)
|
||||||
|
{
|
||||||
|
// Cancel the enumeration
|
||||||
|
m_sppre->Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,21 +385,37 @@ void CPowerRenameUI::_Cleanup()
|
||||||
m_hwnd = NULL;
|
m_hwnd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPowerRenameUI::_EnumerateItems(_In_ IUnknown* pdtobj)
|
HRESULT CPowerRenameUI::_EnumerateItems(_In_ IUnknown* pdtobj)
|
||||||
{
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
// Enumerate the data object and populate the manager
|
// Enumerate the data object and populate the manager
|
||||||
if (m_spsrm)
|
if (m_spsrm)
|
||||||
{
|
{
|
||||||
m_disableCountUpdate = true;
|
m_disableCountUpdate = true;
|
||||||
EnumerateDataObject(pdtobj, m_spsrm);
|
|
||||||
|
// Ensure we re-create the enumerator
|
||||||
|
m_sppre = nullptr;
|
||||||
|
hr = CPowerRenameEnum::s_CreateInstance(pdtobj, m_spsrm, IID_PPV_ARGS(&m_sppre));
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
m_prpui.Start();
|
||||||
|
hr = m_sppre->Start();
|
||||||
|
m_prpui.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
m_disableCountUpdate = false;
|
m_disableCountUpdate = false;
|
||||||
|
|
||||||
UINT itemCount = 0;
|
if (SUCCEEDED(hr))
|
||||||
m_spsrm->GetVisibleItemCount(&itemCount);
|
{
|
||||||
m_listview.SetItemCount(itemCount);
|
UINT itemCount = 0;
|
||||||
|
m_spsrm->GetItemCount(&itemCount);
|
||||||
|
m_listview.SetItemCount(itemCount);
|
||||||
|
|
||||||
_UpdateCounts();
|
_UpdateCounts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT CPowerRenameUI::_ReadSettings()
|
HRESULT CPowerRenameUI::_ReadSettings()
|
||||||
|
@ -607,7 +635,12 @@ void CPowerRenameUI::_OnInitDlg()
|
||||||
if (m_dataSource)
|
if (m_dataSource)
|
||||||
{
|
{
|
||||||
// Populate the manager from the data object
|
// Populate the manager from the data object
|
||||||
_EnumerateItems(m_dataSource);
|
if (FAILED(_EnumerateItems(m_dataSource)))
|
||||||
|
{
|
||||||
|
// Failed during enumeration. Close the dialog.
|
||||||
|
_OnCloseDlg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize from stored settings. Do this now in case we have
|
// Initialize from stored settings. Do this now in case we have
|
||||||
|
@ -1442,3 +1475,160 @@ void CPowerRenameListView::OnColumnClick(_In_ IPowerRenameManager* psrm, _In_ in
|
||||||
psrm->GetFilter(&filter);
|
psrm->GetFilter(&filter);
|
||||||
_UpdateHeaderFilterState(filter);
|
_UpdateHeaderFilterState(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP CPowerRenameProgressUI::QueryInterface(__in REFIID riid, __deref_out void** ppv)
|
||||||
|
{
|
||||||
|
static const QITAB qit[] = {
|
||||||
|
QITABENT(CPowerRenameProgressUI, IUnknown),
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG)
|
||||||
|
CPowerRenameProgressUI::AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&m_refCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG)
|
||||||
|
CPowerRenameProgressUI::Release()
|
||||||
|
{
|
||||||
|
long refCount = InterlockedDecrement(&m_refCount);
|
||||||
|
if (refCount == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TIMERID_CHECKCANCELED 101
|
||||||
|
#define CANCEL_CHECK_INTERVAL 500
|
||||||
|
|
||||||
|
HRESULT CPowerRenameProgressUI::Start()
|
||||||
|
{
|
||||||
|
_Cleanup();
|
||||||
|
m_canceled = false;
|
||||||
|
m_workerThreadHandle = CreateThread(nullptr, 0, s_workerThread, this, 0, nullptr);
|
||||||
|
return (m_workerThreadHandle) ? S_OK : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI CPowerRenameProgressUI::s_workerThread(_In_ void* pv)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)))
|
||||||
|
{
|
||||||
|
CPowerRenameProgressUI* pThis = reinterpret_cast<CPowerRenameProgressUI*>(pv);
|
||||||
|
if (pThis)
|
||||||
|
{
|
||||||
|
HWND hwndMessage = CreateMsgWindow(g_hInst, s_msgWndProc, pThis);
|
||||||
|
|
||||||
|
SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr);
|
||||||
|
|
||||||
|
if (SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&pThis->m_sppd))))
|
||||||
|
{
|
||||||
|
wchar_t buff[100] = { 0 };
|
||||||
|
LoadString(g_hInst, IDS_LOADING, buff, ARRAYSIZE(buff));
|
||||||
|
pThis->m_sppd->SetLine(1, buff, FALSE, NULL);
|
||||||
|
LoadString(g_hInst, IDS_LOADING_MSG, buff, ARRAYSIZE(buff));
|
||||||
|
pThis->m_sppd->SetLine(2, buff, FALSE, NULL);
|
||||||
|
LoadString(g_hInst, IDS_APP_TITLE, buff, ARRAYSIZE(buff));
|
||||||
|
pThis->m_sppd->SetTitle(buff);
|
||||||
|
SetTimer(hwndMessage, TIMERID_CHECKCANCELED, CANCEL_CHECK_INTERVAL, nullptr);
|
||||||
|
pThis->m_sppd->StartProgressDialog(NULL, NULL, PROGDLG_MARQUEEPROGRESS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pThis->m_sppd && !pThis->m_canceled)
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KillTimer(hwndMessage, TIMERID_CHECKCANCELED);
|
||||||
|
DestroyWindow(hwndMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CPowerRenameProgressUI::Stop()
|
||||||
|
{
|
||||||
|
_Cleanup();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPowerRenameProgressUI::_Cleanup()
|
||||||
|
{
|
||||||
|
if (m_sppd)
|
||||||
|
{
|
||||||
|
m_sppd->StopProgressDialog();
|
||||||
|
m_sppd = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_workerThreadHandle)
|
||||||
|
{
|
||||||
|
CloseHandle(m_workerThreadHandle);
|
||||||
|
m_workerThreadHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPowerRenameProgressUI::_UpdateCancelState()
|
||||||
|
{
|
||||||
|
m_canceled = (m_sppd && m_sppd->HasUserCancelled());
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK CPowerRenameProgressUI::s_msgWndProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
|
||||||
|
{
|
||||||
|
LRESULT lRes = 0;
|
||||||
|
|
||||||
|
CPowerRenameProgressUI* pThis = (CPowerRenameProgressUI*)GetWindowLongPtr(hwnd, 0);
|
||||||
|
if (pThis != nullptr)
|
||||||
|
{
|
||||||
|
lRes = pThis->_WndProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
if (uMsg == WM_NCDESTROY)
|
||||||
|
{
|
||||||
|
SetWindowLongPtr(hwnd, 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lRes = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CPowerRenameProgressUI::_WndProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wParam, _In_ LPARAM lParam)
|
||||||
|
{
|
||||||
|
LRESULT lRes = 0;
|
||||||
|
|
||||||
|
AddRef();
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_TIMER:
|
||||||
|
if (wParam == TIMERID_CHECKCANCELED)
|
||||||
|
{
|
||||||
|
_UpdateCancelState();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
KillTimer(hwnd, TIMERID_CHECKCANCELED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
lRes = DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release();
|
||||||
|
|
||||||
|
return lRes;
|
||||||
|
}
|
|
@ -35,6 +35,43 @@ private:
|
||||||
HWND m_hwndLV = nullptr;
|
HWND m_hwndLV = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CPowerRenameProgressUI :
|
||||||
|
public IUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CPowerRenameProgressUI() :
|
||||||
|
m_refCount(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~CPowerRenameProgressUI() = default;
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
IFACEMETHODIMP QueryInterface(__in REFIID riid, __deref_out void** ppv);
|
||||||
|
IFACEMETHODIMP_(ULONG)
|
||||||
|
AddRef();
|
||||||
|
IFACEMETHODIMP_(ULONG)
|
||||||
|
Release();
|
||||||
|
|
||||||
|
HRESULT Start();
|
||||||
|
HRESULT Stop();
|
||||||
|
bool IsCanceled() { return m_canceled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static LRESULT CALLBACK s_msgWndProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
|
||||||
|
LRESULT _WndProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wParam, _In_ LPARAM lParam);
|
||||||
|
|
||||||
|
static DWORD WINAPI s_workerThread(_In_ void* pv);
|
||||||
|
|
||||||
|
void _UpdateCancelState();
|
||||||
|
void _Cleanup();
|
||||||
|
|
||||||
|
long m_refCount = 0;
|
||||||
|
bool m_canceled = false;
|
||||||
|
HANDLE m_workerThreadHandle = nullptr;
|
||||||
|
CComPtr<IProgressDialog> m_sppd;
|
||||||
|
};
|
||||||
|
|
||||||
class CPowerRenameUI :
|
class CPowerRenameUI :
|
||||||
public IDropTarget,
|
public IDropTarget,
|
||||||
public IPowerRenameUI,
|
public IPowerRenameUI,
|
||||||
|
@ -141,7 +178,7 @@ private:
|
||||||
void _SetCheckboxesFromFlags(_In_ DWORD flags);
|
void _SetCheckboxesFromFlags(_In_ DWORD flags);
|
||||||
void _ValidateFlagCheckbox(_In_ DWORD checkBoxId);
|
void _ValidateFlagCheckbox(_In_ DWORD checkBoxId);
|
||||||
|
|
||||||
void _EnumerateItems(_In_ IUnknown* pdtobj);
|
HRESULT _EnumerateItems(_In_ IUnknown* pdtobj);
|
||||||
void _UpdateCounts();
|
void _UpdateCounts();
|
||||||
|
|
||||||
void _CollectItemPosition(_In_ DWORD id);
|
void _CollectItemPosition(_In_ DWORD id);
|
||||||
|
@ -164,8 +201,10 @@ private:
|
||||||
int m_initialHeight = 0;
|
int m_initialHeight = 0;
|
||||||
int m_lastWidth = 0;
|
int m_lastWidth = 0;
|
||||||
int m_lastHeight = 0;
|
int m_lastHeight = 0;
|
||||||
|
CPowerRenameProgressUI m_prpui;
|
||||||
CComPtr<IPowerRenameManager> m_spsrm;
|
CComPtr<IPowerRenameManager> m_spsrm;
|
||||||
CComPtr<IUnknown> m_dataSource;
|
CComPtr<IUnknown> m_dataSource;
|
||||||
|
CComPtr<IPowerRenameEnum> m_sppre;
|
||||||
CComPtr<IDropTargetHelper> m_spdth;
|
CComPtr<IDropTargetHelper> m_spdth;
|
||||||
CComPtr<IAutoComplete2> m_spSearchAC;
|
CComPtr<IAutoComplete2> m_spSearchAC;
|
||||||
CComPtr<IUnknown> m_spSearchACL;
|
CComPtr<IUnknown> m_spSearchACL;
|
||||||
|
|
|
@ -205,4 +205,10 @@ Please select from the options above to show items.</value>
|
||||||
<data name="Rename_Criteria" xml:space="preserve">
|
<data name="Rename_Criteria" xml:space="preserve">
|
||||||
<value>Enter the criteria below to rename the items</value>
|
<value>Enter the criteria below to rename the items</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Loading" xml:space="preserve">
|
||||||
|
<value>Loading...</value>
|
||||||
|
</data>
|
||||||
|
<data name="Loading_Msg" xml:space="preserve">
|
||||||
|
<value>Please wait while the selected items are enumerated.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Loading…
Reference in a new issue