[PowerRename] Handle many items w/o crashing and OOM (#26761)

* [PowerRename] Disable AnimatedIcon (check mark) for CheckBox to prevent crashes
* [PowerRename] Implement lightweight ExplorerItemsSource/VM
This commit is contained in:
Andrey Nekrasov
2023-07-13 18:42:08 +02:00
committed by GitHub
parent bf0d442770
commit 53e104e858
32 changed files with 1124 additions and 538 deletions

View File

@@ -148,7 +148,7 @@ void MRUListHandler::ParseJson()
else
{
std::vector<std::wstring> temp;
for (unsigned int i = 0; i < min(jsonArray.Size(), size); ++i)
for (unsigned int i = 0; i < std::min(jsonArray.Size(), size); ++i)
{
int idx = (oldPushIdx + oldSize - (i + 1)) % oldSize;
temp.push_back(std::wstring(jsonArray.GetStringAt(idx)));

View File

@@ -93,16 +93,16 @@ HRESULT CPowerRenameEnum::_ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ int d
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)))
{
items.push_back(spsi);
items.push_back(std::move(spsi));
spsi = nullptr;
}
auto cmpShellItems = [](CComPtr<IShellItem> l, CComPtr<IShellItem> r) {
auto cmpShellItems = [](const CComPtr<IShellItem>& l, const CComPtr<IShellItem>& r) {
int res = 0;
l->Compare(r, SICHINT_DISPLAY, &res);
return res < 0;
};
std::sort(items.begin(), items.end(), cmpShellItems);
std::sort(begin(items), end(items), cmpShellItems);
for (const auto& item : items)
{

View File

@@ -95,8 +95,6 @@ public:
interface __declspec(uuid("87FC43F9-7634-43D9-99A5-20876AFCE4AD")) IPowerRenameManagerEvents : public IUnknown
{
public:
IFACEMETHOD(OnItemAdded)(_In_ IPowerRenameItem* renameItem) = 0;
IFACEMETHOD(OnUpdate)(_In_ IPowerRenameItem * renameItem) = 0;
IFACEMETHOD(OnRename)(_In_ IPowerRenameItem * renameItem) = 0;
IFACEMETHOD(OnError)(_In_ IPowerRenameItem * renameItem) = 0;
IFACEMETHOD(OnRegExStarted)(_In_ DWORD threadId) = 0;
@@ -135,6 +133,7 @@ public:
IFACEMETHOD(PutRenameRegEx)(_In_ IPowerRenameRegEx* pRegEx) = 0;
IFACEMETHOD(GetRenameItemFactory)(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory) = 0;
IFACEMETHOD(PutRenameItemFactory)(_In_ IPowerRenameItemFactory* pItemFactory) = 0;
virtual uint32_t GetVisibleItemRealIndex(const uint32_t index) const = 0;
};
interface __declspec(uuid("04AAFABE-B76E-4E13-993A-B5941F52B139")) IPowerRenameMRU : public IUnknown

View File

@@ -39,6 +39,7 @@
<ClInclude Include="PowerRenameManager.h" />
<ClInclude Include="PowerRenameMRU.h" />
<ClInclude Include="PowerRenameRegEx.h" />
<ClInclude Include="Renaming.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="srwlock.h" />
<ClInclude Include="pch.h" />
@@ -53,6 +54,7 @@
<ClCompile Include="PowerRenameManager.cpp" />
<ClCompile Include="PowerRenameMRU.cpp" />
<ClCompile Include="PowerRenameRegEx.cpp" />
<ClCompile Include="Renaming.cpp" />
<ClCompile Include="Settings.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>

View File

@@ -5,9 +5,8 @@
#include <shlobj.h>
#include <cstring>
#include "helpers.h"
#include <filesystem>
#include "trace.h"
#include <winrt/base.h>
#include <Renaming.h>
namespace fs = std::filesystem;
@@ -174,11 +173,6 @@ IFACEMETHODIMP CPowerRenameManager::AddItem(_In_ IPowerRenameItem* pItem)
}
}
if (SUCCEEDED(hr))
{
_OnItemAdded(pItem);
}
return hr;
}
@@ -212,25 +206,32 @@ IFACEMETHODIMP CPowerRenameManager::GetVisibleItemByIndex(_In_ UINT index, _COM_
}
else if (SUCCEEDED(GetVisibleItemCount(&count)) && index < count)
{
UINT realIndex = 0, visibleIndex = 0;
for (size_t i = 0; i < m_isVisible.size(); i++)
{
if (m_isVisible[i] && visibleIndex == index)
{
realIndex = static_cast<UINT>(i);
break;
}
if (m_isVisible[i])
{
visibleIndex++;
}
}
const UINT realIndex = GetVisibleItemRealIndex(index);
hr = GetItemByIndex(realIndex, ppItem);
}
return hr;
}
uint32_t CPowerRenameManager::GetVisibleItemRealIndex(const uint32_t index) const
{
UINT realIndex = 0, visibleIndex = 0;
for (size_t i = 0; i < m_isVisible.size(); i++)
{
if (m_isVisible[i] && visibleIndex == index)
{
realIndex = static_cast<UINT>(i);
break;
}
if (m_isVisible[i])
{
visibleIndex++;
}
}
return realIndex;
}
IFACEMETHODIMP CPowerRenameManager::GetItemById(_In_ int id, _COM_Outptr_ IPowerRenameItem** ppItem)
{
*ppItem = nullptr;
@@ -464,7 +465,7 @@ IFACEMETHODIMP CPowerRenameManager::OnFileTimeChanged(_In_ SYSTEMTIME /*fileTime
HRESULT CPowerRenameManager::s_CreateInstance(_Outptr_ IPowerRenameManager** ppsrm)
{
*ppsrm = nullptr;
CPowerRenameManager *psrm = new CPowerRenameManager();
CPowerRenameManager* psrm = new CPowerRenameManager();
HRESULT hr = E_OUTOFMEMORY;
if (psrm)
{
@@ -554,12 +555,7 @@ LRESULT CPowerRenameManager::_WndProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM
{
case SRM_REGEX_ITEM_UPDATED:
{
int id = static_cast<int>(lParam);
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(GetItemById(id, &spItem)))
{
_OnUpdate(spItem);
}
// Do nothing.
break;
}
case SRM_REGEX_ITEM_RENAMED_KEEP_UI:
@@ -926,22 +922,10 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
winrt::check_hresult(pwtd->spsrm->GetRenameRegEx(&spRenameRegEx));
DWORD flags = 0;
winrt::check_hresult(spRenameRegEx->GetFlags(&flags));
PWSTR replaceTerm = nullptr;
bool useFileTime = false;
winrt::check_hresult(spRenameRegEx->GetReplaceTerm(&replaceTerm));
if (isFileTimeUsed(replaceTerm))
{
useFileTime = true;
}
UINT itemCount = 0;
unsigned long itemEnumIndex = 1;
winrt::check_hresult(pwtd->spsrm->GetItemCount(&itemCount));
for (UINT u = 0; u < itemCount; u++)
{
// Check if cancel event is signaled
@@ -956,215 +940,14 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
CComPtr<IPowerRenameItem> spItem;
winrt::check_hresult(pwtd->spsrm->GetItemByIndex(u, &spItem));
int id = -1;
winrt::check_hresult(spItem->GetId(&id));
bool isFolder = false;
bool isSubFolderContent = false;
winrt::check_hresult(spItem->GetIsFolder(&isFolder));
winrt::check_hresult(spItem->GetIsSubFolderContent(&isSubFolderContent));
if ((isFolder && (flags & PowerRenameFlags::ExcludeFolders)) ||
(!isFolder && (flags & PowerRenameFlags::ExcludeFiles)) ||
(isSubFolderContent && (flags & PowerRenameFlags::ExcludeSubfolders)) ||
(isFolder && (flags & PowerRenameFlags::ExtensionOnly)))
{
// Exclude this item from renaming. Ensure new name is cleared.
winrt::check_hresult(spItem->PutNewName(nullptr));
// Send the manager thread the item processed message
PostMessage(pwtd->hwndManager, SRM_REGEX_ITEM_UPDATED, GetCurrentThreadId(), id);
continue;
}
PWSTR originalName = nullptr;
winrt::check_hresult(spItem->GetOriginalName(&originalName));
PWSTR currentNewName = nullptr;
winrt::check_hresult(spItem->GetNewName(&currentNewName));
wchar_t sourceName[MAX_PATH] = { 0 };
if (isFolder)
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), originalName);
}
else
{
if (flags & NameOnly)
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), fs::path(originalName).stem().c_str());
}
else if (flags & ExtensionOnly)
{
std::wstring extension = fs::path(originalName).extension().wstring();
if (!extension.empty() && extension.front() == '.')
{
extension = extension.erase(0, 1);
}
StringCchCopy(sourceName, ARRAYSIZE(sourceName), extension.c_str());
}
else
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), originalName);
}
}
SYSTEMTIME fileTime = { 0 };
if (useFileTime)
{
winrt::check_hresult(spItem->GetTime(&fileTime));
winrt::check_hresult(spRenameRegEx->PutFileTime(fileTime));
}
PWSTR newName = nullptr;
// Failure here means we didn't match anything or had nothing to match
// Call put_newName with null in that case to reset it
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName));
if (useFileTime)
{
winrt::check_hresult(spRenameRegEx->ResetFileTime());
}
wchar_t resultName[MAX_PATH] = { 0 };
PWSTR newNameToUse = nullptr;
// newName == nullptr likely means we have an empty search string. We should leave newNameToUse
// as nullptr so we clear the renamed column
// Except string transformation is selected.
if (newName == nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized))
{
SHStrDup(sourceName, &newName);
}
if (newName != nullptr)
{
newNameToUse = resultName;
if (isFolder)
{
StringCchCopy(resultName, ARRAYSIZE(resultName), newName);
}
else
{
if (flags & NameOnly)
{
StringCchPrintf(resultName, ARRAYSIZE(resultName), L"%s%s", newName, fs::path(originalName).extension().c_str());
}
else if (flags & ExtensionOnly)
{
std::wstring extension = fs::path(originalName).extension().wstring();
if (!extension.empty())
{
StringCchPrintf(resultName, ARRAYSIZE(resultName), L"%s.%s", fs::path(originalName).stem().c_str(), newName);
}
else
{
StringCchCopy(resultName, ARRAYSIZE(resultName), originalName);
}
}
else
{
StringCchCopy(resultName, ARRAYSIZE(resultName), newName);
}
}
}
wchar_t trimmedName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr)
{
winrt::check_hresult(GetTrimmedFileName(trimmedName, ARRAYSIZE(trimmedName), newNameToUse));
newNameToUse = trimmedName;
}
wchar_t transformedName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized))
{
try
{
winrt::check_hresult(GetTransformedFileName(transformedName, ARRAYSIZE(transformedName), newNameToUse, flags, isFolder));
}
catch (...)
{
}
newNameToUse = transformedName;
}
// No change from originalName so set newName to
// null so we clear it from our UI as well.
if (lstrcmp(originalName, newNameToUse) == 0)
{
newNameToUse = nullptr;
}
wchar_t uniqueName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr && (flags & EnumerateItems))
{
unsigned long countUsed = 0;
if (GetEnumeratedFileName(uniqueName, ARRAYSIZE(uniqueName), newNameToUse, nullptr, itemEnumIndex, &countUsed))
{
newNameToUse = uniqueName;
}
itemEnumIndex++;
}
spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename);
if (newNameToUse != nullptr)
{
std::wstring newNameToUseWstr{ newNameToUse };
PWSTR path = nullptr;
spItem->GetPath(&path);
// Following characters cannot be used for file names.
// Ref https://learn.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions
if (newNameToUseWstr.contains('<') ||
newNameToUseWstr.contains('>') ||
newNameToUseWstr.contains(':') ||
newNameToUseWstr.contains('"') ||
newNameToUseWstr.contains('\\') ||
newNameToUseWstr.contains('/') ||
newNameToUseWstr.contains('|') ||
newNameToUseWstr.contains('?') ||
newNameToUseWstr.contains('*'))
{
spItem->PutStatus(PowerRenameItemRenameStatus::ItemNameInvalidChar);
}
// Max file path is 260 and max folder path is 247.
// Ref https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
else if ((isFolder && lstrlen(path) + (lstrlen(newNameToUse) - lstrlen(originalName)) > 247) ||
lstrlen(path) + (lstrlen(newNameToUse) - lstrlen(originalName)) > 260)
{
spItem->PutStatus(PowerRenameItemRenameStatus::ItemNameTooLong);
}
}
winrt::check_hresult(spItem->PutNewName(newNameToUse));
// Was there a change?
if (lstrcmp(currentNewName, newNameToUse) != 0)
{
// Send the manager thread the item processed message
PostMessage(pwtd->hwndManager, SRM_REGEX_ITEM_UPDATED, GetCurrentThreadId(), id);
}
CoTaskMemFree(newName);
CoTaskMemFree(currentNewName);
CoTaskMemFree(originalName);
DoRename(spRenameRegEx, itemEnumIndex, spItem);
}
CoTaskMemFree(replaceTerm);
}
// Send the manager thread the completion message
PostMessage(pwtd->hwndManager, SRM_REGEX_COMPLETE, GetCurrentThreadId(), 0);
delete pwtd;
}
CoUninitialize();
}
@@ -1249,32 +1032,6 @@ void CPowerRenameManager::_ClearRegEx()
}
}
void CPowerRenameManager::_OnItemAdded(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
it.pEvents->OnItemAdded(renameItem);
}
}
}
void CPowerRenameManager::_OnUpdate(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
it.pEvents->OnUpdate(renameItem);
}
}
}
void CPowerRenameManager::_OnRename(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);

View File

@@ -11,12 +11,12 @@ class CPowerRenameManager :
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameManager
IFACEMETHODIMP Advise(_In_ IPowerRenameManagerEvents* renameOpEvent, _Out_ DWORD *cookie);
IFACEMETHODIMP Advise(_In_ IPowerRenameManagerEvents* renameOpEvent, _Out_ DWORD* cookie);
IFACEMETHODIMP UnAdvise(_In_ DWORD cookie);
IFACEMETHODIMP Start();
IFACEMETHODIMP Stop();
@@ -42,7 +42,9 @@ public:
IFACEMETHODIMP PutRenameRegEx(_In_ IPowerRenameRegEx* pRegEx);
IFACEMETHODIMP GetRenameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory);
IFACEMETHODIMP PutRenameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory);
uint32_t GetVisibleItemRealIndex(const uint32_t index) const override;
// IPowerRenameRegExEvents
IFACEMETHODIMP OnSearchTermChanged(_In_ PCWSTR searchTerm);
IFACEMETHODIMP OnReplaceTermChanged(_In_ PCWSTR replaceTerm);
@@ -60,8 +62,6 @@ protected:
void _Cancel();
void _OnItemAdded(_In_ IPowerRenameItem* renameItem);
void _OnUpdate(_In_ IPowerRenameItem* renameItem);
void _OnRename(_In_ IPowerRenameItem* renameItem);
void _OnError(_In_ IPowerRenameItem* renameItem);
void _OnRegExStarted(_In_ DWORD threadId);

View File

@@ -0,0 +1,220 @@
#include "pch.h"
#include <winrt/base.h>
#include "Renaming.h"
#include <Helpers.h>
namespace fs = std::filesystem;
bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnumIndex, CComPtr<IPowerRenameItem>& spItem)
{
bool wouldRename = false;
DWORD flags = 0;
winrt::check_hresult(spRenameRegEx->GetFlags(&flags));
PWSTR replaceTerm = nullptr;
bool useFileTime = false;
winrt::check_hresult(spRenameRegEx->GetReplaceTerm(&replaceTerm));
if (isFileTimeUsed(replaceTerm))
{
useFileTime = true;
}
CoTaskMemFree(replaceTerm);
int id = -1;
winrt::check_hresult(spItem->GetId(&id));
bool isFolder = false;
bool isSubFolderContent = false;
winrt::check_hresult(spItem->GetIsFolder(&isFolder));
winrt::check_hresult(spItem->GetIsSubFolderContent(&isSubFolderContent));
if ((isFolder && (flags & PowerRenameFlags::ExcludeFolders)) ||
(!isFolder && (flags & PowerRenameFlags::ExcludeFiles)) ||
(isSubFolderContent && (flags & PowerRenameFlags::ExcludeSubfolders)) ||
(isFolder && (flags & PowerRenameFlags::ExtensionOnly)))
{
// Exclude this item from renaming. Ensure new name is cleared.
winrt::check_hresult(spItem->PutNewName(nullptr));
return wouldRename;
}
PWSTR originalName = nullptr;
winrt::check_hresult(spItem->GetOriginalName(&originalName));
PWSTR currentNewName = nullptr;
winrt::check_hresult(spItem->GetNewName(&currentNewName));
wchar_t sourceName[MAX_PATH] = { 0 };
if (isFolder)
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), originalName);
}
else
{
if (flags & NameOnly)
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), fs::path(originalName).stem().c_str());
}
else if (flags & ExtensionOnly)
{
std::wstring extension = fs::path(originalName).extension().wstring();
if (!extension.empty() && extension.front() == '.')
{
extension = extension.erase(0, 1);
}
StringCchCopy(sourceName, ARRAYSIZE(sourceName), extension.c_str());
}
else
{
StringCchCopy(sourceName, ARRAYSIZE(sourceName), originalName);
}
}
SYSTEMTIME fileTime = { 0 };
if (useFileTime)
{
winrt::check_hresult(spItem->GetTime(&fileTime));
winrt::check_hresult(spRenameRegEx->PutFileTime(fileTime));
}
PWSTR newName = nullptr;
// Failure here means we didn't match anything or had nothing to match
// Call put_newName with null in that case to reset it
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName));
if (useFileTime)
{
winrt::check_hresult(spRenameRegEx->ResetFileTime());
}
wchar_t resultName[MAX_PATH] = { 0 };
PWSTR newNameToUse = nullptr;
// newName == nullptr likely means we have an empty search string. We should leave newNameToUse
// as nullptr so we clear the renamed column
// Except string transformation is selected.
if (newName == nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized))
{
SHStrDup(sourceName, &newName);
}
if (newName != nullptr)
{
newNameToUse = resultName;
if (isFolder)
{
StringCchCopy(resultName, ARRAYSIZE(resultName), newName);
}
else
{
if (flags & NameOnly)
{
StringCchPrintf(resultName, ARRAYSIZE(resultName), L"%s%s", newName, fs::path(originalName).extension().c_str());
}
else if (flags & ExtensionOnly)
{
std::wstring extension = fs::path(originalName).extension().wstring();
if (!extension.empty())
{
StringCchPrintf(resultName, ARRAYSIZE(resultName), L"%s.%s", fs::path(originalName).stem().c_str(), newName);
}
else
{
StringCchCopy(resultName, ARRAYSIZE(resultName), originalName);
}
}
else
{
StringCchCopy(resultName, ARRAYSIZE(resultName), newName);
}
}
}
wchar_t trimmedName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr)
{
winrt::check_hresult(GetTrimmedFileName(trimmedName, ARRAYSIZE(trimmedName), newNameToUse));
newNameToUse = trimmedName;
}
wchar_t transformedName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr && (flags & Uppercase || flags & Lowercase || flags & Titlecase || flags & Capitalized))
{
try
{
winrt::check_hresult(GetTransformedFileName(transformedName, ARRAYSIZE(transformedName), newNameToUse, flags, isFolder));
}
catch (...)
{
}
newNameToUse = transformedName;
}
// No change from originalName so set newName to
// null so we clear it from our UI as well.
if (lstrcmp(originalName, newNameToUse) == 0)
{
newNameToUse = nullptr;
}
wchar_t uniqueName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr && (flags & EnumerateItems))
{
unsigned long countUsed = 0;
if (GetEnumeratedFileName(uniqueName, ARRAYSIZE(uniqueName), newNameToUse, nullptr, itemEnumIndex, &countUsed))
{
newNameToUse = uniqueName;
}
itemEnumIndex++;
}
spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename);
if (newNameToUse != nullptr)
{
wouldRename = true;
std::wstring newNameToUseWstr{ newNameToUse };
PWSTR path = nullptr;
spItem->GetPath(&path);
// Following characters cannot be used for file names.
// Ref https://learn.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions
if (newNameToUseWstr.contains('<') ||
newNameToUseWstr.contains('>') ||
newNameToUseWstr.contains(':') ||
newNameToUseWstr.contains('"') ||
newNameToUseWstr.contains('\\') ||
newNameToUseWstr.contains('/') ||
newNameToUseWstr.contains('|') ||
newNameToUseWstr.contains('?') ||
newNameToUseWstr.contains('*'))
{
spItem->PutStatus(PowerRenameItemRenameStatus::ItemNameInvalidChar);
wouldRename = false;
}
// Max file path is 260 and max folder path is 247.
// Ref https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
else if ((isFolder && lstrlen(path) + (lstrlen(newNameToUse) - lstrlen(originalName)) > 247) ||
lstrlen(path) + (lstrlen(newNameToUse) - lstrlen(originalName)) > 260)
{
spItem->PutStatus(PowerRenameItemRenameStatus::ItemNameTooLong);
wouldRename = false;
}
}
winrt::check_hresult(spItem->PutNewName(newNameToUse));
CoTaskMemFree(newName);
CoTaskMemFree(currentNewName);
CoTaskMemFree(originalName);
return wouldRename;
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include <PowerRenameInterfaces.h>
bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnumIndex, CComPtr<IPowerRenameItem>& spItem);

View File

@@ -2,12 +2,13 @@
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX
// Windows Header Files:
#include <windows.h>
// C RunTime Header Files
#include <algorithm>
#include <execution>
#include <cstdlib>
#include <malloc.h>
#include <memory.h>
@@ -19,6 +20,8 @@
#include <shellapi.h>
#include <shlwapi.h>
#include <ShlObj_core.h>
#include <filesystem>
#include <ProjectTelemetry.h>
#include <winrt/base.h>