in src/modules/powerrename/lib/PowerRenameManager.cpp [912:1149]
DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
{
try
{
winrt::check_hresult(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
WorkerThreadData* pwtd = reinterpret_cast<WorkerThreadData*>(pv);
if (pwtd)
{
PostMessage(pwtd->hwndManager, SRM_REGEX_STARTED, GetCurrentThreadId(), 0);
// Wait to be told we can begin
if (WaitForSingleObject(pwtd->startEvent, INFINITE) == WAIT_OBJECT_0)
{
CComPtr<IPowerRenameRegEx> spRenameRegEx;
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
if (WaitForSingleObject(pwtd->cancelEvent, 0) == WAIT_OBJECT_0)
{
// Canceled from manager
// Send the manager thread the canceled message
PostMessage(pwtd->hwndManager, SRM_REGEX_CANCELED, GetCurrentThreadId(), 0);
break;
}
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(¤tNewName));
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++;
}
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);
}
CoTaskMemFree(replaceTerm);
}
// Send the manager thread the completion message
PostMessage(pwtd->hwndManager, SRM_REGEX_COMPLETE, GetCurrentThreadId(), 0);
delete pwtd;
}
CoUninitialize();
}
catch (...)
{
// TODO: an exception can happen while typing the expression and the syntax is not correct yet,
// we need to be more granular and raise an exception only when a real problem happened.
// MessageBox(NULL, L"RegexWorkerThread failed to execute.\nPlease report the bug to https://aka.ms/powerToysReportBug", L"PowerRename Error", MB_OK);
}
return 0;
}