Initial add of PowerRename from SmartRename repo (#499)

* Initial add of PowerRename from SmartRename repo
This commit is contained in:
Chris Davis
2019-10-17 20:57:19 -07:00
committed by GitHub
parent 04b9422ea6
commit e1d5dd263a
63 changed files with 6055 additions and 1 deletions

View File

@@ -0,0 +1,288 @@
#include "stdafx.h"
#include "Helpers.h"
#include <ShlGuid.h>
HRESULT GetIconIndexFromPath(_In_ PCWSTR path, _Out_ int* index)
{
*index = 0;
HRESULT hr = E_FAIL;
SHFILEINFO shFileInfo = { 0 };
if (!PathIsRelative(path))
{
DWORD attrib = GetFileAttributes(path);
HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo(path, attrib, &shFileInfo, sizeof(shFileInfo), (SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES));
if (himl)
{
*index = shFileInfo.iIcon;
// We shouldn't free the HIMAGELIST.
hr = S_OK;
}
}
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->get_smartRenameItemFactory(&spsrif);
if (SUCCEEDED(hr))
{
CComPtr<IPowerRenameItem> spNewItem;
hr = spsrif->Create(spsi, &spNewItem);
if (SUCCEEDED(hr))
{
spNewItem->put_depth(depth);
hr = psrm->AddItem(spNewItem);
}
if (SUCCEEDED(hr))
{
bool isFolder = false;
if (SUCCEEDED(spNewItem->get_isFolder(&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 object and add paths to the rotation manager
HRESULT EnumerateDataObject(_In_ IDataObject* pdo, _In_ IPowerRenameManager* psrm)
{
CComPtr<IShellItemArray> spsia;
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdo, IID_PPV_ARGS(&spsia));
if (SUCCEEDED(hr))
{
CComPtr<IEnumShellItems> spesi;
hr = spsia->EnumItems(&spesi);
if (SUCCEEDED(hr))
{
hr = _ParseEnumItems(spesi, psrm);
}
}
return hr;
}
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
{
WNDCLASS wc = { 0 };
PWSTR 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;
}
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;
HRESULT hr = S_OK;
BOOL fRet = FALSE;
int cchDir = 0;
if (0 != cchMax && pszUniqueName)
{
*pszUniqueName = 0;
if (pszDir)
{
hr = StringCchCopy(pszUniqueName, cchMax, pszDir);
if (SUCCEEDED(hr))
{
hr = PathCchAddBackslashEx(pszUniqueName, cchMax, &pszName, nullptr);
if (SUCCEEDED(hr))
{
cchDir = lstrlen(pszDir);
}
}
}
else
{
cchDir = 0;
pszName = pszUniqueName;
}
}
else
{
hr = E_INVALIDARG;
}
int cchTmp = 0;
int cchStem = 0;
PCWSTR pszStem = nullptr;
PCWSTR pszRest = nullptr;
wchar_t szFormat[MAX_PATH] = { 0 };
if (SUCCEEDED(hr))
{
pszStem = pszTemplate;
pszRest = StrChr(pszTemplate, L'(');
while (pszRest)
{
PCWSTR pszEndUniq = CharNext(pszRest);
while (*pszEndUniq && *pszEndUniq >= L'0' && *pszEndUniq <= L'9')
{
pszEndUniq++;
}
if (*pszEndUniq == L')')
{
break;
}
pszRest = StrChr(CharNext(pszRest), L'(');
}
if (!pszRest)
{
pszRest = PathFindExtension(pszTemplate);
cchStem = (int)(pszRest - pszTemplate);
hr = StringCchCopy(szFormat, ARRAYSIZE(szFormat), L" (%lu)");
}
else
{
pszRest++;
cchStem = (int)(pszRest - pszTemplate);
while (*pszRest && *pszRest >= L'0' && *pszRest <= L'9')
{
pszRest++;
}
hr = StringCchCopy(szFormat, ARRAYSIZE(szFormat), L"%lu");
}
}
unsigned long ulMax = 0;
unsigned long ulMin = 0;
if (SUCCEEDED(hr))
{
int cchFormat = lstrlen(szFormat);
if (cchFormat < 3)
{
*pszUniqueName = L'\0';
return FALSE;
}
ulMin = ulMinLong;
cchTmp = cchMax - cchDir - cchStem - (cchFormat - 3);
switch (cchTmp)
{
case 1:
ulMax = 10;
break;
case 2:
ulMax = 100;
break;
case 3:
ulMax = 1000;
break;
case 4:
ulMax = 10000;
break;
case 5:
ulMax = 100000;
break;
default:
if (cchTmp <= 0)
{
ulMax = ulMin;
}
else
{
ulMax = 1000000;
}
break;
}
}
if (SUCCEEDED(hr))
{
hr = StringCchCopyN(pszName, pszUniqueName + cchMax - pszName, pszStem, cchStem);
if (SUCCEEDED(hr))
{
PWSTR pszDigit = pszName + cchStem;
for (unsigned long ul = ulMin; ((ul < ulMax) && (!fRet)); ul++)
{
wchar_t szTemp[MAX_PATH] = { 0 };
hr = StringCchPrintf(szTemp, ARRAYSIZE(szTemp), szFormat, ul);
if (SUCCEEDED(hr))
{
hr = StringCchCat(szTemp, ARRAYSIZE(szTemp), pszRest);
if (SUCCEEDED(hr))
{
hr = StringCchCopy(pszDigit, pszUniqueName + cchMax - pszDigit, szTemp);
if (SUCCEEDED(hr))
{
if (!PathFileExists(pszUniqueName))
{
(*pulNumUsed) = ul;
fRet = TRUE;
}
}
}
}
}
}
}
if (!fRet)
{
*pszUniqueName = L'\0';
}
return fRet;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "stdafx.h"
HRESULT EnumerateDataObject(_In_ IDataObject* pdo, _In_ IPowerRenameManager* psrm);
HRESULT GetIconIndexFromPath(_In_ PCWSTR path, _Out_ int* index);
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
BOOL GetEnumeratedFileName(
__out_ecount(cchMax) PWSTR pszUniqueName, UINT cchMax,
__in PCWSTR pszTemplate, __in_opt PCWSTR pszDir, unsigned long ulMinLong,
__inout unsigned long* pulNumUsed);

View File

@@ -0,0 +1,109 @@
#pragma once
#include "stdafx.h"
enum PowerRenameFlags
{
CaseSensitive = 0x1,
MatchAllOccurences = 0x2,
UseRegularExpressions = 0x4,
EnumerateItems = 0x8,
ExcludeFiles = 0x10,
ExcludeFolders = 0x20,
ExcludeSubfolders = 0x40,
NameOnly = 0x80,
ExtensionOnly = 0x100
};
interface __declspec(uuid("3ECBA62B-E0F0-4472-AA2E-DEE7A1AA46B9")) IPowerRenameRegExEvents : public IUnknown
{
public:
IFACEMETHOD(OnSearchTermChanged)(_In_ PCWSTR searchTerm) = 0;
IFACEMETHOD(OnReplaceTermChanged)(_In_ PCWSTR replaceTerm) = 0;
IFACEMETHOD(OnFlagsChanged)(_In_ DWORD flags) = 0;
};
interface __declspec(uuid("E3ED45B5-9CE0-47E2-A595-67EB950B9B72")) IPowerRenameRegEx : public IUnknown
{
public:
IFACEMETHOD(Advise)(_In_ IPowerRenameRegExEvents* regExEvents, _Out_ DWORD* cookie) = 0;
IFACEMETHOD(UnAdvise)(_In_ DWORD cookie) = 0;
IFACEMETHOD(get_searchTerm)(_Outptr_ PWSTR* searchTerm) = 0;
IFACEMETHOD(put_searchTerm)(_In_ PCWSTR searchTerm) = 0;
IFACEMETHOD(get_replaceTerm)(_Outptr_ PWSTR* replaceTerm) = 0;
IFACEMETHOD(put_replaceTerm)(_In_ PCWSTR replaceTerm) = 0;
IFACEMETHOD(get_flags)(_Out_ DWORD* flags) = 0;
IFACEMETHOD(put_flags)(_In_ DWORD flags) = 0;
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result) = 0;
};
interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameItem : public IUnknown
{
public:
IFACEMETHOD(get_path)(_Outptr_ PWSTR* path) = 0;
IFACEMETHOD(get_shellItem)(_Outptr_ IShellItem** ppsi) = 0;
IFACEMETHOD(get_originalName)(_Outptr_ PWSTR* originalName) = 0;
IFACEMETHOD(get_newName)(_Outptr_ PWSTR* newName) = 0;
IFACEMETHOD(put_newName)(_In_opt_ PCWSTR newName) = 0;
IFACEMETHOD(get_isFolder)(_Out_ bool* isFolder) = 0;
IFACEMETHOD(get_isSubFolderContent)(_Out_ bool* isSubFolderContent) = 0;
IFACEMETHOD(get_selected)(_Out_ bool* selected) = 0;
IFACEMETHOD(put_selected)(_In_ bool selected) = 0;
IFACEMETHOD(get_id)(_Out_ int *id) = 0;
IFACEMETHOD(get_iconIndex)(_Out_ int* iconIndex) = 0;
IFACEMETHOD(get_depth)(_Out_ UINT* depth) = 0;
IFACEMETHOD(put_depth)(_In_ int depth) = 0;
IFACEMETHOD(ShouldRenameItem)(_In_ DWORD flags, _Out_ bool* shouldRename) = 0;
IFACEMETHOD(Reset)() = 0;
};
interface __declspec(uuid("{26CBFFD9-13B3-424E-BAC9-D12B0539149C}")) IPowerRenameItemFactory : public IUnknown
{
public:
IFACEMETHOD(Create)(_In_ IShellItem* psi, _COM_Outptr_ IPowerRenameItem** ppItem) = 0;
};
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(OnError)(_In_ IPowerRenameItem* renameItem) = 0;
IFACEMETHOD(OnRegExStarted)(_In_ DWORD threadId) = 0;
IFACEMETHOD(OnRegExCanceled)(_In_ DWORD threadId) = 0;
IFACEMETHOD(OnRegExCompleted)(_In_ DWORD threadId) = 0;
IFACEMETHOD(OnRenameStarted)() = 0;
IFACEMETHOD(OnRenameCompleted)() = 0;
};
interface __declspec(uuid("001BBD88-53D2-4FA6-95D2-F9A9FA4F9F70")) IPowerRenameManager : public IUnknown
{
public:
IFACEMETHOD(Advise)(_In_ IPowerRenameManagerEvents* renameManagerEvent, _Out_ DWORD* cookie) = 0;
IFACEMETHOD(UnAdvise)(_In_ DWORD cookie) = 0;
IFACEMETHOD(Start)() = 0;
IFACEMETHOD(Stop)() = 0;
IFACEMETHOD(Reset)() = 0;
IFACEMETHOD(Shutdown)() = 0;
IFACEMETHOD(Rename)(_In_ HWND hwndParent) = 0;
IFACEMETHOD(AddItem)(_In_ IPowerRenameItem* pItem) = 0;
IFACEMETHOD(GetItemByIndex)(_In_ UINT index, _COM_Outptr_ IPowerRenameItem** ppItem) = 0;
IFACEMETHOD(GetItemById)(_In_ int id, _COM_Outptr_ IPowerRenameItem** ppItem) = 0;
IFACEMETHOD(GetItemCount)(_Out_ UINT* count) = 0;
IFACEMETHOD(GetSelectedItemCount)(_Out_ UINT* count) = 0;
IFACEMETHOD(GetRenameItemCount)(_Out_ UINT* count) = 0;
IFACEMETHOD(get_flags)(_Out_ DWORD* flags) = 0;
IFACEMETHOD(put_flags)(_In_ DWORD flags) = 0;
IFACEMETHOD(get_smartRenameRegEx)(_COM_Outptr_ IPowerRenameRegEx** ppRegEx) = 0;
IFACEMETHOD(put_smartRenameRegEx)(_In_ IPowerRenameRegEx* pRegEx) = 0;
IFACEMETHOD(get_smartRenameItemFactory)(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory) = 0;
IFACEMETHOD(put_smartRenameItemFactory)(_In_ IPowerRenameItemFactory* pItemFactory) = 0;
};
interface __declspec(uuid("E6679DEB-460D-42C1-A7A8-E25897061C99")) IPowerRenameUI : public IUnknown
{
public:
IFACEMETHOD(Show)() = 0;
IFACEMETHOD(Close)() = 0;
IFACEMETHOD(Update)() = 0;
};

View File

@@ -0,0 +1,221 @@
#include "stdafx.h"
#include "PowerRenameItem.h"
#include "helpers.h"
int CPowerRenameItem::s_id = 0;
IFACEMETHODIMP_(ULONG) CPowerRenameItem::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CPowerRenameItem::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
IFACEMETHODIMP CPowerRenameItem::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
{
static const QITAB qit[] = {
QITABENT(CPowerRenameItem, IPowerRenameItem),
QITABENT(CPowerRenameItem, IPowerRenameItemFactory),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP CPowerRenameItem::get_path(_Outptr_ PWSTR* path)
{
*path = nullptr;
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = m_path ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = SHStrDup(m_path, path);
}
return hr;
}
IFACEMETHODIMP CPowerRenameItem::get_shellItem(_Outptr_ IShellItem** ppsi)
{
return SHCreateItemFromParsingName(m_path, nullptr, IID_PPV_ARGS(ppsi));
}
IFACEMETHODIMP CPowerRenameItem::get_originalName(_Outptr_ PWSTR* originalName)
{
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = m_originalName ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = SHStrDup(m_originalName, originalName);
}
return hr;
}
IFACEMETHODIMP CPowerRenameItem::put_newName(_In_opt_ PCWSTR newName)
{
CSRWSharedAutoLock lock(&m_lock);
CoTaskMemFree(m_newName);
m_newName = nullptr;
HRESULT hr = S_OK;
if (newName != nullptr)
{
hr = SHStrDup(newName, &m_newName);
}
return hr;
}
IFACEMETHODIMP CPowerRenameItem::get_newName(_Outptr_ PWSTR* newName)
{
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = m_newName ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = SHStrDup(m_newName, newName);
}
return hr;
}
IFACEMETHODIMP CPowerRenameItem::get_isFolder(_Out_ bool* isFolder)
{
CSRWSharedAutoLock lock(&m_lock);
*isFolder = m_isFolder;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::get_isSubFolderContent(_Out_ bool* isSubFolderContent)
{
CSRWSharedAutoLock lock(&m_lock);
*isSubFolderContent = m_depth > 0;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::get_selected(_Out_ bool* selected)
{
CSRWSharedAutoLock lock(&m_lock);
*selected = m_selected;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::put_selected(_In_ bool selected)
{
CSRWSharedAutoLock lock(&m_lock);
m_selected = selected;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::get_id(_Out_ int* id)
{
CSRWSharedAutoLock lock(&m_lock);
*id = m_id;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::get_iconIndex(_Out_ int* iconIndex)
{
if (m_iconIndex == -1)
{
GetIconIndexFromPath((PCWSTR)m_path, &m_iconIndex);
}
*iconIndex = m_iconIndex;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::get_depth(_Out_ UINT* depth)
{
*depth = m_depth;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::put_depth(_In_ int depth)
{
m_depth = depth;
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::ShouldRenameItem(_In_ DWORD flags, _Out_ bool* shouldRename)
{
// Should we perform a rename on this item given its
// state and the options that were set?
bool hasChanged = m_newName != nullptr && (lstrcmp(m_originalName, m_newName) != 0);
bool excludeBecauseFolder = (m_isFolder && (flags & PowerRenameFlags::ExcludeFolders));
bool excludeBecauseFile = (!m_isFolder && (flags & PowerRenameFlags::ExcludeFiles));
bool excludeBecauseSubFolderContent = (m_depth > 0 && (flags & PowerRenameFlags::ExcludeSubfolders));
*shouldRename = (m_selected && hasChanged && !excludeBecauseFile &&
!excludeBecauseFolder && !excludeBecauseSubFolderContent);
return S_OK;
}
IFACEMETHODIMP CPowerRenameItem::Reset()
{
CSRWSharedAutoLock lock(&m_lock);
CoTaskMemFree(m_newName);
m_newName = nullptr;
return S_OK;
}
HRESULT CPowerRenameItem::s_CreateInstance(_In_opt_ IShellItem* psi, _In_ REFIID iid, _Outptr_ void** resultInterface)
{
*resultInterface = nullptr;
CPowerRenameItem *newRenameItem = new CPowerRenameItem();
HRESULT hr = newRenameItem ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
if (psi != nullptr)
{
hr = newRenameItem->_Init(psi);
}
if (SUCCEEDED(hr))
{
hr = newRenameItem->QueryInterface(iid, resultInterface);
}
newRenameItem->Release();
}
return hr;
}
CPowerRenameItem::CPowerRenameItem() :
m_refCount(1),
m_id(++s_id)
{
}
CPowerRenameItem::~CPowerRenameItem()
{
CoTaskMemFree(m_path);
CoTaskMemFree(m_newName);
CoTaskMemFree(m_originalName);
}
HRESULT CPowerRenameItem::_Init(_In_ IShellItem* psi)
{
// Get the full filesystem path from the shell item
HRESULT hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &m_path);
if (SUCCEEDED(hr))
{
hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &m_originalName);
if (SUCCEEDED(hr))
{
// Check if we are a folder now so we can check this attribute quickly later
SFGAOF att = 0;
hr = psi->GetAttributes(SFGAO_STREAM | SFGAO_FOLDER, &att);
if (SUCCEEDED(hr))
{
// Some items can be both folders and streams (ex: zip folders).
m_isFolder = (att & SFGAO_FOLDER) && !(att & SFGAO_STREAM);
}
}
}
return hr;
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include "stdafx.h"
#include "PowerRenameInterfaces.h"
#include "srwlock.h"
class CPowerRenameItem :
public IPowerRenameItem,
public IPowerRenameItemFactory
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameItem
IFACEMETHODIMP get_path(_Outptr_ PWSTR* path);
IFACEMETHODIMP get_shellItem(_Outptr_ IShellItem** ppsi);
IFACEMETHODIMP get_originalName(_Outptr_ PWSTR* originalName);
IFACEMETHODIMP put_newName(_In_opt_ PCWSTR newName);
IFACEMETHODIMP get_newName(_Outptr_ PWSTR* newName);
IFACEMETHODIMP get_isFolder(_Out_ bool* isFolder);
IFACEMETHODIMP get_isSubFolderContent(_Out_ bool* isSubFolderContent);
IFACEMETHODIMP get_selected(_Out_ bool* selected);
IFACEMETHODIMP put_selected(_In_ bool selected);
IFACEMETHODIMP get_id(_Out_ int* id);
IFACEMETHODIMP get_iconIndex(_Out_ int* iconIndex);
IFACEMETHODIMP get_depth(_Out_ UINT* depth);
IFACEMETHODIMP put_depth(_In_ int depth);
IFACEMETHODIMP Reset();
IFACEMETHODIMP ShouldRenameItem(_In_ DWORD flags, _Out_ bool* shouldRename);
// IPowerRenameItemFactory
IFACEMETHODIMP Create(_In_ IShellItem* psi, _Outptr_ IPowerRenameItem** ppItem)
{
return CPowerRenameItem::s_CreateInstance(psi, IID_PPV_ARGS(ppItem));
}
public:
static HRESULT s_CreateInstance(_In_opt_ IShellItem* psi, _In_ REFIID iid, _Outptr_ void** resultInterface);
protected:
static int s_id;
CPowerRenameItem();
virtual ~CPowerRenameItem();
HRESULT _Init(_In_ IShellItem* psi);
bool m_selected = true;
bool m_isFolder = false;
int m_id = -1;
int m_iconIndex = -1;
UINT m_depth = 0;
HRESULT m_error = S_OK;
PWSTR m_path = nullptr;
PWSTR m_originalName = nullptr;
PWSTR m_newName = nullptr;
CSRWLock m_lock;
long m_refCount = 0;
};

View File

@@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{51920F1F-C28C-4ADF-8660-4238766796C2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Helpers.h" />
<ClInclude Include="PowerRenameItem.h" />
<ClInclude Include="PowerRenameInterfaces.h" />
<ClInclude Include="PowerRenameManager.h" />
<ClInclude Include="PowerRenameRegEx.h" />
<ClInclude Include="srwlock.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="PowerRenameItem.cpp" />
<ClCompile Include="PowerRenameManager.cpp" />
<ClCompile Include="PowerRenameRegEx.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
#pragma once
#include <vector>
#include <map>
#include "srwlock.h"
class CPowerRenameManager :
public IPowerRenameManager,
public IPowerRenameRegExEvents
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameManager
IFACEMETHODIMP Advise(_In_ IPowerRenameManagerEvents* renameOpEvent, _Out_ DWORD *cookie);
IFACEMETHODIMP UnAdvise(_In_ DWORD cookie);
IFACEMETHODIMP Start();
IFACEMETHODIMP Stop();
IFACEMETHODIMP Reset();
IFACEMETHODIMP Shutdown();
IFACEMETHODIMP Rename(_In_ HWND hwndParent);
IFACEMETHODIMP AddItem(_In_ IPowerRenameItem* pItem);
IFACEMETHODIMP GetItemByIndex(_In_ UINT index, _COM_Outptr_ IPowerRenameItem** ppItem);
IFACEMETHODIMP GetItemById(_In_ int id, _COM_Outptr_ IPowerRenameItem** ppItem);
IFACEMETHODIMP GetItemCount(_Out_ UINT* count);
IFACEMETHODIMP GetSelectedItemCount(_Out_ UINT* count);
IFACEMETHODIMP GetRenameItemCount(_Out_ UINT* count);
IFACEMETHODIMP get_flags(_Out_ DWORD* flags);
IFACEMETHODIMP put_flags(_In_ DWORD flags);
IFACEMETHODIMP get_smartRenameRegEx(_COM_Outptr_ IPowerRenameRegEx** ppRegEx);
IFACEMETHODIMP put_smartRenameRegEx(_In_ IPowerRenameRegEx* pRegEx);
IFACEMETHODIMP get_smartRenameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory);
IFACEMETHODIMP put_smartRenameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory);
// IPowerRenameRegExEvents
IFACEMETHODIMP OnSearchTermChanged(_In_ PCWSTR searchTerm);
IFACEMETHODIMP OnReplaceTermChanged(_In_ PCWSTR replaceTerm);
IFACEMETHODIMP OnFlagsChanged(_In_ DWORD flags);
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameManager** ppsrm);
protected:
CPowerRenameManager();
virtual ~CPowerRenameManager();
HRESULT _Init();
void _Cleanup();
void _Cancel();
void _OnItemAdded(_In_ IPowerRenameItem* renameItem);
void _OnUpdate(_In_ IPowerRenameItem* renameItem);
void _OnError(_In_ IPowerRenameItem* renameItem);
void _OnRegExStarted(_In_ DWORD threadId);
void _OnRegExCanceled(_In_ DWORD threadId);
void _OnRegExCompleted(_In_ DWORD threadId);
void _OnRenameStarted();
void _OnRenameCompleted();
void _ClearEventHandlers();
void _ClearPowerRenameItems();
HRESULT _PerformRegExRename();
HRESULT _PerformFileOperation();
HRESULT _CreateRegExWorkerThread();
void _CancelRegExWorkerThread();
void _WaitForRegExWorkerThread();
HRESULT _CreateFileOpWorkerThread();
HRESULT _EnsureRegEx();
HRESULT _InitRegEx();
void _ClearRegEx();
// Thread proc for performing the regex rename of each item
static DWORD WINAPI s_regexWorkerThread(_In_ void* pv);
// Thread proc for performing the actual file operation that does the file rename
static DWORD WINAPI s_fileOpWorkerThread(_In_ void* pv);
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);
HANDLE m_regExWorkerThreadHandle = nullptr;
HANDLE m_startRegExWorkerEvent = nullptr;
HANDLE m_cancelRegExWorkerEvent = nullptr;
HANDLE m_fileOpWorkerThreadHandle = nullptr;
HANDLE m_startFileOpWorkerEvent = nullptr;
CSRWLock m_lockEvents;
CSRWLock m_lockItems;
DWORD m_flags = 0;
DWORD m_cookie = 0;
DWORD m_regExAdviseCookie = 0;
struct SMART_RENAME_MGR_EVENT
{
IPowerRenameManagerEvents* pEvents;
DWORD cookie;
};
CComPtr<IPowerRenameItemFactory> m_spItemFactory;
CComPtr<IPowerRenameRegEx> m_spRegEx;
_Guarded_by_(m_lockEvents) std::vector<SMART_RENAME_MGR_EVENT> m_PowerRenameManagerEvents;
_Guarded_by_(m_lockItems) std::map<int, IPowerRenameItem*> m_smartRenameItems;
// Parent HWND used by IFileOperation
HWND m_hwndParent = nullptr;
HWND m_hwndMessage = nullptr;
CRITICAL_SECTION m_critsecReentrancy;
long m_refCount;
};

View File

@@ -0,0 +1,301 @@
#include "stdafx.h"
#include "PowerRenameRegEx.h"
#include <regex>
#include <string>
#include <algorithm>
using namespace std;
using std::regex_error;
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
IFACEMETHODIMP CPowerRenameRegEx::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
{
static const QITAB qit[] = {
QITABENT(CPowerRenameRegEx, IPowerRenameRegEx),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP CPowerRenameRegEx::Advise(_In_ IPowerRenameRegExEvents* regExEvents, _Out_ DWORD* cookie)
{
CSRWExclusiveAutoLock lock(&m_lockEvents);
m_cookie++;
SMART_RENAME_REGEX_EVENT srre;
srre.cookie = m_cookie;
srre.pEvents = regExEvents;
regExEvents->AddRef();
m_smartRenameRegExEvents.push_back(srre);
*cookie = m_cookie;
return S_OK;
}
IFACEMETHODIMP CPowerRenameRegEx::UnAdvise(_In_ DWORD cookie)
{
HRESULT hr = E_FAIL;
CSRWExclusiveAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
{
if (it.cookie == cookie)
{
hr = S_OK;
it.cookie = 0;
if (it.pEvents)
{
it.pEvents->Release();
it.pEvents = nullptr;
}
break;
}
}
return hr;
}
IFACEMETHODIMP CPowerRenameRegEx::get_searchTerm(_Outptr_ PWSTR* searchTerm)
{
*searchTerm = nullptr;
HRESULT hr = m_searchTerm ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
CSRWSharedAutoLock lock(&m_lock);
hr = SHStrDup(m_searchTerm, searchTerm);
}
return hr;
}
IFACEMETHODIMP CPowerRenameRegEx::put_searchTerm(_In_ PCWSTR searchTerm)
{
bool changed = false;
HRESULT hr = searchTerm ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hr))
{
CSRWExclusiveAutoLock lock(&m_lock);
if (m_searchTerm == nullptr || lstrcmp(searchTerm, m_searchTerm) != 0)
{
changed = true;
CoTaskMemFree(m_searchTerm);
hr = SHStrDup(searchTerm, &m_searchTerm);
}
}
if (SUCCEEDED(hr) && changed)
{
_OnSearchTermChanged();
}
return hr;
}
IFACEMETHODIMP CPowerRenameRegEx::get_replaceTerm(_Outptr_ PWSTR* replaceTerm)
{
*replaceTerm = nullptr;
HRESULT hr = m_replaceTerm ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
CSRWSharedAutoLock lock(&m_lock);
hr = SHStrDup(m_replaceTerm, replaceTerm);
}
return hr;
}
IFACEMETHODIMP CPowerRenameRegEx::put_replaceTerm(_In_ PCWSTR replaceTerm)
{
bool changed = false;
HRESULT hr = replaceTerm ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hr))
{
CSRWExclusiveAutoLock lock(&m_lock);
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_replaceTerm) != 0)
{
changed = true;
CoTaskMemFree(m_replaceTerm);
hr = SHStrDup(replaceTerm, &m_replaceTerm);
}
}
if (SUCCEEDED(hr) && changed)
{
_OnReplaceTermChanged();
}
return hr;
}
IFACEMETHODIMP CPowerRenameRegEx::get_flags(_Out_ DWORD* flags)
{
*flags = m_flags;
return S_OK;
}
IFACEMETHODIMP CPowerRenameRegEx::put_flags(_In_ DWORD flags)
{
if (m_flags != flags)
{
m_flags = flags;
_OnFlagsChanged();
}
return S_OK;
}
HRESULT CPowerRenameRegEx::s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameRegEx)
{
*renameRegEx = nullptr;
CPowerRenameRegEx *newRenameRegEx = new CPowerRenameRegEx();
HRESULT hr = newRenameRegEx ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = newRenameRegEx->QueryInterface(IID_PPV_ARGS(renameRegEx));
newRenameRegEx->Release();
}
return hr;
}
CPowerRenameRegEx::CPowerRenameRegEx() :
m_refCount(1)
{
// Init to empty strings
SHStrDup(L"", &m_searchTerm);
SHStrDup(L"", &m_replaceTerm);
}
CPowerRenameRegEx::~CPowerRenameRegEx()
{
CoTaskMemFree(m_searchTerm);
CoTaskMemFree(m_replaceTerm);
}
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
{
*result = nullptr;
CSRWSharedAutoLock lock(&m_lock);
HRESULT hr = (source && wcslen(source) > 0 && m_searchTerm && wcslen(m_searchTerm) > 0) ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hr))
{
wstring res = source;
try
{
// TODO: creating the regex could be costly. May want to cache this.
std::wstring sourceToUse(source);
std::wstring searchTerm(m_searchTerm);
std::wstring replaceTerm(m_replaceTerm ? wstring(m_replaceTerm) : wstring(L""));
if (m_flags & UseRegularExpressions)
{
std::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? regex_constants::icase | regex_constants::ECMAScript : regex_constants::ECMAScript);
if (m_flags & MatchAllOccurences)
{
res = regex_replace(wstring(source), pattern, replaceTerm);
}
else
{
std::wsmatch m;
if (std::regex_search(sourceToUse, m, pattern))
{
res = sourceToUse.replace(m.prefix().length(), searchTerm.length(), replaceTerm);
}
}
}
else
{
// Simple search and replace
size_t pos = 0;
do
{
pos = _Find(sourceToUse, searchTerm, (!(m_flags & CaseSensitive)), pos);
if (pos != std::string::npos)
{
res = sourceToUse.replace(pos, searchTerm.length(), replaceTerm);
pos += replaceTerm.length();
}
if (!(m_flags & MatchAllOccurences))
{
break;
}
} while (pos != std::string::npos);
}
*result = StrDup(res.c_str());
hr = (*result) ? S_OK : E_OUTOFMEMORY;
}
catch (regex_error e)
{
hr = E_FAIL;
}
}
return hr;
}
size_t CPowerRenameRegEx::_Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos)
{
if (caseInsensitive)
{
// Convert to lower
std::transform(data.begin(), data.end(), data.begin(), ::towlower);
std::transform(toSearch.begin(), toSearch.end(), toSearch.begin(), ::towlower);
}
// Find sub string position in given string starting at position pos
return data.find(toSearch, pos);
}
void CPowerRenameRegEx::_OnSearchTermChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
{
if (it.pEvents)
{
it.pEvents->OnSearchTermChanged(m_searchTerm);
}
}
}
void CPowerRenameRegEx::_OnReplaceTermChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
{
if (it.pEvents)
{
it.pEvents->OnReplaceTermChanged(m_replaceTerm);
}
}
}
void CPowerRenameRegEx::_OnFlagsChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
{
if (it.pEvents)
{
it.pEvents->OnFlagsChanged(m_flags);
}
}
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include "stdafx.h"
#include <vector>
#include <string>
#include "srwlock.h"
#define DEFAULT_FLAGS MatchAllOccurences
class CPowerRenameRegEx : public IPowerRenameRegEx
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameRegEx
IFACEMETHODIMP Advise(_In_ IPowerRenameRegExEvents* regExEvents, _Out_ DWORD* cookie);
IFACEMETHODIMP UnAdvise(_In_ DWORD cookie);
IFACEMETHODIMP get_searchTerm(_Outptr_ PWSTR* searchTerm);
IFACEMETHODIMP put_searchTerm(_In_ PCWSTR searchTerm);
IFACEMETHODIMP get_replaceTerm(_Outptr_ PWSTR* replaceTerm);
IFACEMETHODIMP put_replaceTerm(_In_ PCWSTR replaceTerm);
IFACEMETHODIMP get_flags(_Out_ DWORD* flags);
IFACEMETHODIMP put_flags(_In_ DWORD flags);
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result);
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx **renameRegEx);
protected:
CPowerRenameRegEx();
virtual ~CPowerRenameRegEx();
void _OnSearchTermChanged();
void _OnReplaceTermChanged();
void _OnFlagsChanged();
size_t _Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos);
DWORD m_flags = DEFAULT_FLAGS;
PWSTR m_searchTerm = nullptr;
PWSTR m_replaceTerm = nullptr;
CSRWLock m_lock;
CSRWLock m_lockEvents;
DWORD m_cookie = 0;
struct SMART_RENAME_REGEX_EVENT
{
IPowerRenameRegExEvents* pEvents;
DWORD cookie;
};
_Guarded_by_(m_lockEvents) std::vector<SMART_RENAME_REGEX_EVENT> m_smartRenameRegExEvents;
long m_refCount = 0;
};

View File

@@ -0,0 +1,79 @@
#pragma once
#include "stdafx.h"
// Wrapper around SRWLOCK
class CSRWLock
{
public:
CSRWLock()
{
InitializeSRWLock(&m_lock);
}
_Acquires_shared_lock_(this->m_lock)
void LockShared()
{
AcquireSRWLockShared(&m_lock);
}
_Acquires_exclusive_lock_(this->m_lock)
void LockExclusive()
{
AcquireSRWLockExclusive(&m_lock);
}
_Releases_shared_lock_(this->m_lock)
void ReleaseShared()
{
ReleaseSRWLockShared(&m_lock);
}
_Releases_exclusive_lock_(this->m_lock)
void ReleaseExclusive()
{
ReleaseSRWLockExclusive(&m_lock);
}
virtual ~CSRWLock()
{
}
private:
SRWLOCK m_lock;
};
// RAII over an SRWLock (write)
class CSRWExclusiveAutoLock
{
public:
CSRWExclusiveAutoLock(CSRWLock *srwLock)
{
m_pSRWLock = srwLock;
srwLock->LockExclusive();
}
virtual ~CSRWExclusiveAutoLock()
{
m_pSRWLock->ReleaseExclusive();
}
protected:
CSRWLock *m_pSRWLock;
};
// RAII over an SRWLock (read)
class CSRWSharedAutoLock
{
public:
CSRWSharedAutoLock(CSRWLock *srwLock)
{
m_pSRWLock = srwLock;
srwLock->LockShared();
}
virtual ~CSRWSharedAutoLock()
{
m_pSRWLock->ReleaseShared();
}
protected:
CSRWLock *m_pSRWLock;
};

View File

@@ -0,0 +1,2 @@
#include "stdafx.h"

View File

@@ -0,0 +1,20 @@
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <wchar.h>
#include <atlbase.h>
#include <strsafe.h>
#include <pathcch.h>
#include <shobjidl.h>
#include <shellapi.h>
#include "PowerRenameInterfaces.h"

View File

@@ -0,0 +1,7 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>