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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 6402 additions and 1 deletions

View file

@ -49,6 +49,34 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-CommonLib", "src\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZonesEditor", "src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "powerrename", "powerrename", "{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameExt", "src\modules\powerrename\dll\PowerRenameExt.vcxproj", "{B25AC7A5-FB9F-4789-B392-D5C85E948670}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modules\powerrename\lib\PowerRenameLib.vcxproj", "{51920F1F-C28C-4ADF-8660-4238766796C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUI", "src\modules\powerrename\ui\PowerRenameUI.vcxproj", "{0E072714-D127-460B-AFAD-B4C40B412798}"
ProjectSection(ProjectDependencies) = postProject
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modules\powerrename\testapp\PowerRenameTest.vcxproj", "{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
ProjectSection(ProjectDependencies) = postProject
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -97,6 +125,26 @@ Global
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.ActiveCfg = Debug|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.Build.0 = Debug|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.ActiveCfg = Release|x64
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.Build.0 = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.ActiveCfg = Debug|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.Build.0 = Debug|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.ActiveCfg = Release|x64
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.Build.0 = Release|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.ActiveCfg = Debug|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -113,6 +161,12 @@ Global
{4E577735-DFAB-41AF-8A6E-B6E8872A2928} = {1FAF749F-0D6F-4BF5-A563-31A4B5279D27}
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{0E072714-D127-460B-AFAD-B4C40B412798} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View file

@ -232,6 +232,17 @@
<File Source="$(var.BinX64Dir)\modules\MahApps.Metro.dll" />
<File Source="$(var.BinX64Dir)\modules\Microsoft.Xaml.Behaviors.dll" />
</Component>
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
<File Source="$(var.BinX64Dir)\modules\PowerRenameExt.dll" KeyPath="yes" />
<RegistryKey Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
<RegistryValue Type="string" Key="InprocServer32" Value="[ModulesInstallFolder]PowerRenameExt.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
</RegistryKey>
<RegistryKey Root="HKCR" Key="AllFileSystemObjects\ShellEx\ContextMenuHandlers\PowerRenameExt">
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
</RegistryKey>
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsHtmlInstallFolder" FileSource="$(var.RepoDir)\settings\settings-html\">
<Component Id="settings_html" Guid="87881A99-E917-4B0D-B1D8-5C6EB9709F96" Win64="yes">
@ -272,6 +283,7 @@
<ComponentRef Id="Module_ShortcutGuide" />
<ComponentRef Id="Module_FancyZones" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="Module_PowerRename" />
<ComponentRef Id="settings_exe" />
<ComponentRef Id="settings_html" />
<ComponentRef Id="settings_js_bundle" />

View file

@ -0,0 +1,2 @@
# PowerRename
A Windows Shell Extension for more advanced renaming using search and replace or regular expressions

View file

@ -0,0 +1,147 @@
#include "stdafx.h"
#include "PowerRenameExt.h"
#include <PowerRenameUI.h>
#include <PowerRenameItem.h>
#include <PowerRenameManager.h>
#include "resource.h"
extern HINSTANCE g_hInst;
HWND g_hwndParent = 0;
const wchar_t powerRenameRegPath[] = L"Software\\Microsoft\\PowerRename";
const wchar_t powerRenameRegEnabledName[] = L"Enabled";
bool CPowerRenameMenu::IsEnabled()
{
DWORD type = REG_DWORD;
DWORD dwEnabled = 0;
DWORD cb = sizeof(dwEnabled);
SHGetValue(HKEY_CURRENT_USER, powerRenameRegPath, powerRenameRegEnabledName, &type, &dwEnabled, &cb);
return (dwEnabled == 0) ? false : true;
}
bool CPowerRenameMenu::SetEnabled(_In_ bool enabled)
{
DWORD dwEnabled = enabled ? 1 : 0;
return SUCCEEDED(HRESULT_FROM_WIN32(SHSetValueW(HKEY_CURRENT_USER, powerRenameRegPath, powerRenameRegEnabledName, REG_DWORD, &dwEnabled, sizeof(dwEnabled))));
}
CPowerRenameMenu::CPowerRenameMenu()
{
DllAddRef();
}
CPowerRenameMenu::~CPowerRenameMenu()
{
m_spdo = nullptr;
DllRelease();
}
HRESULT CPowerRenameMenu::s_CreateInstance(_In_opt_ IUnknown*, _In_ REFIID riid, _Outptr_ void **ppv)
{
*ppv = nullptr;
HRESULT hr = E_OUTOFMEMORY;
CPowerRenameMenu *pprm = new CPowerRenameMenu();
if (pprm)
{
hr = pprm->QueryInterface(riid, ppv);
pprm->Release();
}
return hr;
}
// IShellExtInit
HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject *pdtobj, HKEY)
{
// Check if we have disabled ourselves
if (!IsEnabled())
return E_FAIL;
// Cache the data object to be used later
m_spdo = pdtobj;
return S_OK;
}
// IContextMenu
HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirst, UINT, UINT uFlags)
{
// Check if we have disabled ourselves
if (!IsEnabled())
return E_FAIL;
HRESULT hr = E_UNEXPECTED;
if (m_spdo)
{
if ((uFlags & ~CMF_OPTIMIZEFORINVOKE) && (uFlags & ~(CMF_DEFAULTONLY | CMF_VERBSONLY)))
{
wchar_t menuName[64] = { 0 };
LoadString(g_hInst, IDS_POWERRENAME, menuName, ARRAYSIZE(menuName));
InsertMenu(hMenu, index, MF_STRING | MF_BYPOSITION, uIDFirst++, menuName);
hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}
}
return hr;
}
HRESULT CPowerRenameMenu::InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pici)
{
// Check if we have disabled ourselves
if (!IsEnabled())
return E_FAIL;
HRESULT hr = E_FAIL;
if ((IS_INTRESOURCE(pici->lpVerb)) &&
(LOWORD(pici->lpVerb) == 0))
{
IStream* pstrm = nullptr;
if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(__uuidof(m_spdo), m_spdo, &pstrm)))
{
if (!SHCreateThread(s_PowerRenameUIThreadProc, pstrm, CTF_COINIT | CTF_PROCESS_REF, nullptr))
{
pstrm->Release(); // if we failed to create the thread, then we must release the stream
}
}
}
return hr;
}
DWORD WINAPI CPowerRenameMenu::s_PowerRenameUIThreadProc(_In_ void* pData)
{
IStream* pstrm = static_cast<IStream*>(pData);
CComPtr<IDataObject> spdo;
if (SUCCEEDED(CoGetInterfaceAndReleaseStream(pstrm, IID_PPV_ARGS(&spdo))))
{
// Create the smart rename manager
CComPtr<IPowerRenameManager> spsrm;
if (SUCCEEDED(CPowerRenameManager::s_CreateInstance(&spsrm)))
{
// Create the factory for our items
CComPtr<IPowerRenameItemFactory> spsrif;
if (SUCCEEDED(CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&spsrif))))
{
// Pass the factory to the manager
if (SUCCEEDED(spsrm->put_smartRenameItemFactory(spsrif)))
{
// Create the smart rename UI instance and pass the smart rename manager
CComPtr<IPowerRenameUI> spsrui;
if (SUCCEEDED(CPowerRenameUI::s_CreateInstance(spsrm, spdo, false, &spsrui)))
{
// Call blocks until we are done
spsrui->Show();
spsrui->Close();
}
}
}
// Need to call shutdown to break circular dependencies
spsrm->Shutdown();
}
}
return 0;
}

View file

@ -0,0 +1,5 @@
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

View file

@ -0,0 +1,61 @@
#pragma once
#include "stdafx.h"
class CPowerRenameMenu :
public IShellExtInit,
public IContextMenu
{
public:
CPowerRenameMenu();
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CPowerRenameMenu, IShellExtInit),
QITABENT(CPowerRenameMenu, IContextMenu),
{ 0, 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) Release()
{
LONG refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
// IShellExtInit
STDMETHODIMP Initialize(_In_opt_ PCIDLIST_ABSOLUTE pidlFolder, _In_ IDataObject* pdto, HKEY hkProgID);
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirst, UINT uIDLast, UINT uFlags);
STDMETHODIMP InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pCMI);
STDMETHODIMP GetCommandString(UINT_PTR, UINT, _In_opt_ UINT*, _In_ LPSTR, UINT)
{
return E_NOTIMPL;
}
static HRESULT s_CreateInstance(_In_opt_ IUnknown* punkOuter, _In_ REFIID riid, _Outptr_ void** ppv);
static DWORD WINAPI s_PowerRenameUIThreadProc(_In_ void* pData);
static bool SetEnabled(_In_ bool enabled);
static bool IsEnabled();
private:
~CPowerRenameMenu();
long m_refCount = 1;
CComPtr<IDataObject> m_spdo;
};

View file

@ -0,0 +1,111 @@
// Microsoft Visual C++ generated resource script.
⼀⼀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀眀椀渀爀攀猀⸀栀∀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀 ℀搀攀昀椀渀攀搀䄀䘀堀开刀䔀匀伀唀刀䌀䔀开䐀䰀䰀⤀ 簀簀 搀攀昀椀渀攀搀䄀䘀堀开吀䄀刀䜀开䔀一唀⤀ഀ<EFBFBD>
䰀䄀一䜀唀䄀䜀䔀 䰀䄀一䜀开䔀一䜀䰀䤀匀䠀Ⰰ 匀唀䈀䰀䄀一䜀开䔀一䜀䰀䤀匀䠀开唀匀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀爀攀猀漀甀爀挀攀⸀栀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀眀椀渀爀攀猀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 嘀攀爀猀椀漀渀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
嘀匀开嘀䔀刀匀䤀伀一开䤀一䘀伀 嘀䔀刀匀䤀伀一䤀一䘀伀ഀ<EFBFBD>
 䘀䤀䰀䔀嘀䔀刀匀䤀伀一 ㄀Ⰰ  Ⰰ㄀ഀ<EFBFBD>
 倀刀伀䐀唀䌀吀嘀䔀刀匀䤀伀一 ㄀Ⰰ  Ⰰ㄀ഀ<EFBFBD>
 䘀䤀䰀䔀䘀䰀䄀䜀匀䴀䄀匀䬀  砀㌀昀䰀ഀ<EFBFBD>
⌀椀昀搀攀昀 开䐀䔀䈀唀䜀ഀ<EFBFBD>
 䘀䤀䰀䔀䘀䰀䄀䜀匀  砀㄀䰀ഀ<EFBFBD>
⌀攀氀猀攀ഀ<EFBFBD>
 䘀䤀䰀䔀䘀䰀䄀䜀匀   䰀ഀ<EFBFBD>
⌀攀渀搀椀昀ഀ<EFBFBD>
 䘀䤀䰀䔀伀匀  砀㐀   㐀䰀ഀ<EFBFBD>
 䘀䤀䰀䔀吀夀倀䔀  砀㈀䰀ഀ<EFBFBD>
 䘀䤀䰀䔀匀唀䈀吀夀倀䔀   䰀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䈀䰀伀䌀䬀 ∀匀琀爀椀渀最䘀椀氀攀䤀渀昀漀∀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        䈀䰀伀䌀䬀    㐀戀 ∀ഀ<EFBFBD>
        䈀䔀䜀䤀一ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀䌀漀洀瀀愀渀礀一愀洀攀∀Ⰰ ∀䴀椀挀爀漀猀漀昀琀 䌀漀爀瀀⸀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀䘀椀氀攀䐀攀猀挀爀椀瀀琀椀漀渀∀Ⰰ ∀倀漀眀攀爀刀攀渀愀洀攀 倀漀眀攀爀吀漀礀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀䘀椀氀攀嘀攀爀猀椀漀渀∀Ⰰ ∀㄀⸀  ⸀㄀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀䤀渀琀攀爀渀愀氀一愀洀攀∀Ⰰ ∀倀漀眀攀爀刀攀渀愀洀攀䔀砀琀⸀搀氀氀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀䰀攀最愀氀䌀漀瀀礀爀椀最栀琀∀Ⰰ ∀䌀漀瀀礀爀椀最栀琀 䌀⤀  ㄀㤀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀伀爀椀最椀渀愀氀䘀椀氀攀渀愀洀攀∀Ⰰ ∀倀漀眀攀爀刀攀渀愀洀攀䔀砀琀⸀搀氀氀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀倀爀漀搀甀挀琀一愀洀攀∀Ⰰ ∀倀漀眀攀爀刀攀渀愀洀攀 倀漀眀攀爀吀漀礀∀ഀ<EFBFBD>
            嘀䄀䰀唀䔀 ∀倀爀漀搀甀挀琀嘀攀爀猀椀漀渀∀Ⰰ ∀㄀⸀  ⸀㄀∀ഀ<EFBFBD>
        䔀一䐀ഀ<EFBFBD>
    䔀一䐀ഀ<EFBFBD>
    䈀䰀伀䌀䬀 ∀嘀愀爀䘀椀氀攀䤀渀昀漀∀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        嘀䄀䰀唀䔀 ∀吀爀愀渀猀氀愀琀椀漀渀∀Ⰰ  砀㐀 㤀Ⰰ ㄀㈀  <EFBFBD>
    䔀一䐀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 匀琀爀椀渀最 吀愀戀氀攀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
匀吀刀䤀一䜀吀䄀䈀䰀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䤀䐀匀开倀伀圀䔀刀刀䔀一䄀䴀䔀         ∀倀漀眀攀爀 刀攀渀愀洀攀∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 渀漀琀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>

View file

@ -0,0 +1,190 @@
<?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">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{B25AC7A5-FB9F-4789-B392-D5C85E948670}</ProjectGuid>
<RootNamespace>PowerRenameExt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</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'">
<TargetExt>.dll</TargetExt>
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="PowerRenameExt.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameExt.rc" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="PowerRenameExt.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="PowerRenameExt.def" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PowerRenameExt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameExt.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameExt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PowerRenameExt.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,252 @@
#include "stdafx.h"
#include "PowerRenameExt.h"
#include <interface/powertoy_module_interface.h>
#include <common/settings_objects.h>
DWORD g_dwModuleRefCount = 0;
HINSTANCE g_hInst = 0;
extern "C" IMAGE_DOS_HEADER __ImageBase;
class CSmartRenameClassFactory : public IClassFactory
{
public:
CSmartRenameClassFactory(_In_ REFCLSID clsid) :
m_refCount(1),
m_clsid(clsid)
{
DllAddRef();
}
// IUnknown methods
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CSmartRenameClassFactory, IClassFactory),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) Release()
{
LONG refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
// IClassFactory methods
IFACEMETHODIMP CreateInstance(_In_opt_ IUnknown* punkOuter, _In_ REFIID riid, _Outptr_ void** ppv)
{
*ppv = NULL;
HRESULT hr;
if (punkOuter)
{
hr = CLASS_E_NOAGGREGATION;
}
else
{
if (m_clsid == CLSID_PowerRenameMenu)
{
hr = CPowerRenameMenu::s_CreateInstance(punkOuter, riid, ppv);
}
else
{
hr = CLASS_E_CLASSNOTAVAILABLE;
}
}
return hr;
}
IFACEMETHODIMP LockServer(BOOL bLock)
{
if (bLock)
{
DllAddRef();
}
else
{
DllRelease();
}
return S_OK;
}
private:
~CSmartRenameClassFactory()
{
DllRelease();
}
long m_refCount;
CLSID m_clsid;
};
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void*)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_hInst = hInstance;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//
// Checks if there are any external references to this module
//
STDAPI DllCanUnloadNow(void)
{
return (g_dwModuleRefCount == 0) ? S_OK : S_FALSE;
}
//
// DLL export for creating COM objects
//
STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID riid, _Outptr_ void **ppv)
{
*ppv = NULL;
HRESULT hr = E_OUTOFMEMORY;
CSmartRenameClassFactory *pClassFactory = new CSmartRenameClassFactory(clsid);
if (pClassFactory)
{
hr = pClassFactory->QueryInterface(riid, ppv);
pClassFactory->Release();
}
return hr;
}
STDAPI DllRegisterServer()
{
return S_OK;
}
STDAPI DllUnregisterServer()
{
return S_OK;
}
void DllAddRef()
{
g_dwModuleRefCount++;
}
void DllRelease()
{
g_dwModuleRefCount--;
}
class PowerRenameModule : public PowertoyModuleIface
{
private:
// Enabled by default
bool m_enabled = true;
public:
// Return the display name of the powertoy, this will be cached
virtual PCWSTR get_name() override
{
return L"PowerRename";
}
// Enable the powertoy
virtual void enable()
{
m_enabled = true;
save_settings();
}
// Disable the powertoy
virtual void disable()
{
m_enabled = false;
save_settings();
}
// Returns if the powertoy is enabled
virtual bool is_enabled() override
{
return m_enabled;
}
// Return array of the names of all events that this powertoy listens for, with
// nullptr as the last element of the array. Nullptr can also be retured for empty list.
virtual PCWSTR* get_events() override
{
return nullptr;
}
// Return JSON with the configuration options.
// These are the settings shown on the settings page along with their current values.
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
// Create a Settings object.
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(L"A Windows Shell Extension for more advanced bulk renaming using search and replace or regular expressions.");
// Link to the GitHub PowerRename sub-page
settings.set_overview_link(L"https://github.com/microsoft/PowerToys/tree/master/src/modules/powerrename");
return settings.serialize_to_buffer(buffer, buffer_size);
}
// Passes JSON with the configuration settings for the powertoy.
// This is called when the user hits Save on the settings page.
virtual void set_config(PCWSTR config) override
{
}
// Signal from the Settings editor to call a custom action.
// This can be used to spawn more complex editors.
virtual void call_custom_action(const wchar_t* action) override
{
}
// Handle incoming event, data is event-specific
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
{
return 0;
}
// Destroy the powertoy and free memory
virtual void destroy() override
{
delete this;
}
void init_settings()
{
m_enabled = CPowerRenameMenu::IsEnabled();
}
void save_settings()
{
CPowerRenameMenu::SetEnabled(m_enabled);
}
PowerRenameModule()
{
init_settings();
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new PowerRenameModule();
}

View file

@ -0,0 +1,12 @@
#define IDS_POWERRENAME 801
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,2 @@
#include "stdafx.h"
#pragma comment(lib, "windowsapp")

View file

@ -0,0 +1,26 @@
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <winrt/base.h>
#include <windows.h>
#include <unknwn.h>
#include <shlwapi.h>
#include <atlbase.h>
#include <Shobjidl.h>
#include <Shlobj.h>
#include "common/common.h"
void DllAddRef();
void DllRelease();
#define INITGUID
#include <guiddef.h>
// {0440049F-D1DC-4E46-B27B-98393D79486B}
DEFINE_GUID(CLSID_PowerRenameMenu, 0x0440049F, 0xD1DC, 0x4E46, 0xB2, 0x7B, 0x98, 0x39, 0x3D, 0x79, 0x48, 0x6B);
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

View file

@ -0,0 +1,8 @@
#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>

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>

View file

@ -0,0 +1,62 @@
// PowerRenameTest.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "PowerRenameTest.h"
#include <PowerRenameInterfaces.h>
#include <PowerRenameItem.h>
#include <PowerRenameUI.h>
#include <PowerRenameManager.h>
#include <Shobjidl.h>
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
HINSTANCE g_hInst;
// {0440049F-D1DC-4E46-B27B-98393D79486B}
//DEFINE_GUID(CLSID_PowerRenameMenu, 0x0440049F, 0xD1DC, 0x4E46, 0xB2, 0x7B, 0x98, 0x39, 0x3D, 0x79, 0x48, 0x6B);
class __declspec(uuid("{0440049F-D1DC-4E46-B27B-98393D79486B}")) Foo;
static const CLSID CLSID_PowerRenameMenu = __uuidof(Foo);
DEFINE_GUID(BHID_DataObject, 0xb8c0bd9f, 0xed24, 0x455c, 0x83, 0xe6, 0xd5, 0x39, 0xc, 0x4f, 0xe8, 0xc4);
int APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ PWSTR lpCmdLine,
_In_ int nCmdShow)
{
g_hInst = hInstance;
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
// Create the smart rename manager
CComPtr<IPowerRenameManager> spsrm;
if (SUCCEEDED(CPowerRenameManager::s_CreateInstance(&spsrm)))
{
// Create the factory for our items
CComPtr<IPowerRenameItemFactory> spsrif;
if (SUCCEEDED(CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&spsrif))))
{
// Pass the factory to the manager
if (SUCCEEDED(spsrm->put_smartRenameItemFactory(spsrif)))
{
// Create the smart rename UI instance and pass the manager
CComPtr<IPowerRenameUI> spsrui;
if (SUCCEEDED(CPowerRenameUI::s_CreateInstance(spsrm, nullptr, true, &spsrui)))
{
// Call blocks until we are done
spsrui->Show();
spsrui->Close();
// Need to call shutdown to break circular dependencies
spsrm->Shutdown();
}
}
}
}
CoUninitialize();
}
return 0;
}

View file

@ -0,0 +1,3 @@
#pragma once
#include "resource.h"

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -0,0 +1,71 @@
// Microsoft Visual C++ generated resource script.
⼀⼀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀琀愀爀最攀琀瘀攀爀⸀栀∀ഀ<EFBFBD>
⌀攀渀搀椀昀ഀ<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀眀椀渀搀漀眀猀⸀栀∀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀 ℀搀攀昀椀渀攀搀䄀䘀堀开刀䔀匀伀唀刀䌀䔀开䐀䰀䰀⤀ 簀簀 搀攀昀椀渀攀搀䄀䘀堀开吀䄀刀䜀开䔀一唀⤀ഀ<EFBFBD>
䰀䄀一䜀唀䄀䜀䔀 䰀䄀一䜀开䔀一䜀䰀䤀匀䠀Ⰰ 匀唀䈀䰀䄀一䜀开䔀一䜀䰀䤀匀䠀开唀匀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀爀攀猀漀甀爀挀攀⸀栀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀琀愀爀最攀琀瘀攀爀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀攀渀搀椀昀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀眀椀渀搀漀眀猀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 渀漀琀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>

View file

@ -0,0 +1,188 @@
<?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">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameTest</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</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'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Resource.h" />
<ClInclude Include="PowerRenameTest.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameTest.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>
<ItemGroup>
<ResourceCompile Include="PowerRenameTest.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PowerRenameTest.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PowerRenameTest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameTest.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,19 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by SmartRenameTest.rc
//
#define IDD_POWERRENAMETEST_DIALOG 402
#define IDR_MAINFRAME 428
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 429
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 410
#endif
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View file

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

View file

@ -0,0 +1,16 @@
#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 <tchar.h>
#include <atlbase.h>
#include <strsafe.h>
#include <pathcch.h>

View file

@ -0,0 +1,8 @@
#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>

View file

@ -0,0 +1,930 @@
#include "stdafx.h"
#include "resource.h"
#include "PowerRenameUI.h"
#include <commctrl.h>
#include <Shlobj.h>
#include <helpers.h>
#include <windowsx.h>
extern HINSTANCE g_hInst;
int g_rgnMatchModeResIDs[] =
{
IDS_ENTIREITEMNAME,
IDS_NAMEONLY,
IDS_EXTENSIONONLY
};
enum
{
MATCHMODE_FULLNAME = 0,
MATCHMODE_NAMEONLY,
MATCHMODE_EXTENIONONLY
};
struct FlagCheckboxMap
{
DWORD flag;
DWORD id;
};
FlagCheckboxMap g_flagCheckboxMap[] =
{
{ UseRegularExpressions, IDC_CHECK_USEREGEX },
{ ExcludeSubfolders, IDC_CHECK_EXCLUDESUBFOLDERS },
{ EnumerateItems, IDC_CHECK_ENUMITEMS },
{ ExcludeFiles, IDC_CHECK_EXCLUDEFILES },
{ CaseSensitive, IDC_CHECK_CASESENSITIVE },
{ MatchAllOccurences, IDC_CHECK_MATCHALLOCCRENCES },
{ ExcludeFolders, IDC_CHECK_EXCLUDEFOLDERS },
{ NameOnly, IDC_CHECK_NAMEONLY },
{ ExtensionOnly, IDC_CHECK_EXTENSIONONLY }
};
// IUnknown
IFACEMETHODIMP CPowerRenameUI::QueryInterface(__in REFIID riid, __deref_out void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CPowerRenameUI, IPowerRenameUI),
QITABENT(CPowerRenameUI, IPowerRenameManagerEvents),
QITABENT(CPowerRenameUI, IDropTarget),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) CPowerRenameUI::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CPowerRenameUI::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
HRESULT CPowerRenameUI::s_CreateInstance(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop, _Outptr_ IPowerRenameUI** ppsrui)
{
*ppsrui = nullptr;
CPowerRenameUI *prui = new CPowerRenameUI();
HRESULT hr = prui ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
// Pass the IPowerRenameManager to the IPowerRenameUI so it can subscribe to events
hr = prui->_Initialize(psrm, pdo, enableDragDrop);
if (SUCCEEDED(hr))
{
hr = prui->QueryInterface(IID_PPV_ARGS(ppsrui));
}
prui->Release();
}
return hr;
}
// IPowerRenameUI
IFACEMETHODIMP CPowerRenameUI::Show()
{
return _DoModal(NULL);
}
IFACEMETHODIMP CPowerRenameUI::Close()
{
_OnCloseDlg();
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::Update()
{
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::get_hwnd(_Out_ HWND* hwnd)
{
*hwnd = m_hwnd;
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::get_showUI(_Out_ bool* showUI)
{
// Let callers know that it is OK to show UI (ex: progress dialog, error dialog and conflict dialog UI)
*showUI = true;
return S_OK;
}
// IPowerRenameManagerEvents
IFACEMETHODIMP CPowerRenameUI::OnItemAdded(_In_ IPowerRenameItem*)
{
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnUpdate(_In_ IPowerRenameItem*)
{
UINT itemCount = 0;
if (m_spsrm)
{
m_spsrm->GetItemCount(&itemCount);
}
m_listview.RedrawItems(0, itemCount);
_UpdateCounts();
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnError(_In_ IPowerRenameItem*)
{
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnRegExStarted(_In_ DWORD threadId)
{
m_disableCountUpdate = true;
m_currentRegExId = threadId;
_UpdateCounts();
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnRegExCanceled(_In_ DWORD threadId)
{
if (m_currentRegExId == threadId)
{
m_disableCountUpdate = false;
_UpdateCounts();
}
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnRegExCompleted(_In_ DWORD threadId)
{
// Enable list view
if (m_currentRegExId == threadId)
{
m_disableCountUpdate = false;
_UpdateCounts();
}
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnRenameStarted()
{
// Disable controls
EnableWindow(m_hwnd, FALSE);
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::OnRenameCompleted()
{
// Enable controls
EnableWindow(m_hwnd, TRUE);
// Close the window
_OnCloseDlg();
return S_OK;
}
// IDropTarget
IFACEMETHODIMP CPowerRenameUI::DragEnter(_In_ IDataObject* pdtobj, DWORD /* grfKeyState */, POINTL pt, _Inout_ DWORD* pdwEffect)
{
if (m_spdth)
{
POINT ptT = { pt.x, pt.y };
m_spdth->DragEnter(m_hwnd, pdtobj, &ptT, *pdwEffect);
}
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::DragOver(DWORD /* grfKeyState */, POINTL pt, _Inout_ DWORD* pdwEffect)
{
if (m_spdth)
{
POINT ptT = { pt.x, pt.y };
m_spdth->DragOver(&ptT, *pdwEffect);
}
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::DragLeave()
{
if (m_spdth)
{
m_spdth->DragLeave();
}
return S_OK;
}
IFACEMETHODIMP CPowerRenameUI::Drop(_In_ IDataObject* pdtobj, DWORD, POINTL pt, _Inout_ DWORD* pdwEffect)
{
if (m_spdth)
{
POINT ptT = { pt.x, pt.y };
m_spdth->Drop(pdtobj, &ptT, *pdwEffect);
}
_OnClear();
EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), TRUE);
EnableWindow(m_hwndLV, TRUE);
// Populate the manager from the data object
if (m_spsrm)
{
_EnumerateItems(pdtobj);
}
return S_OK;
}
HRESULT CPowerRenameUI::_Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop)
{
// Cache the smart rename manager
m_spsrm = psrm;
// Cache the data object for enumeration later
m_spdo = pdo;
m_enableDragDrop = enableDragDrop;
HRESULT hr = CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spdth));
if (SUCCEEDED(hr))
{
// Subscribe to smart rename manager events
hr = m_spsrm->Advise(this, &m_cookie);
}
if (FAILED(hr))
{
_Cleanup();
}
return hr;
}
void CPowerRenameUI::_Cleanup()
{
if (m_spsrm && m_cookie != 0)
{
m_spsrm->UnAdvise(m_cookie);
m_cookie = 0;
m_spsrm = nullptr;
}
m_spdo = nullptr;
m_spdth = nullptr;
if (m_enableDragDrop)
{
RevokeDragDrop(m_hwnd);
}
}
void CPowerRenameUI::_EnumerateItems(_In_ IDataObject* pdtobj)
{
// Enumerate the data object and popuplate the manager
if (m_spsrm)
{
m_disableCountUpdate = true;
EnumerateDataObject(pdtobj, m_spsrm);
m_disableCountUpdate = false;
UINT itemCount = 0;
m_spsrm->GetItemCount(&itemCount);
m_listview.SetItemCount(itemCount);
_UpdateCounts();
}
}
// TODO: persist settings made in the UI
HRESULT CPowerRenameUI::_ReadSettings()
{
return S_OK;
}
HRESULT CPowerRenameUI::_WriteSettings()
{
return S_OK;
}
void CPowerRenameUI::_OnClear()
{
}
void CPowerRenameUI::_OnCloseDlg()
{
// Persist the current settings
_WriteSettings();
EndDialog(m_hwnd, 1);
}
void CPowerRenameUI::_OnDestroyDlg()
{
_Cleanup();
}
void CPowerRenameUI::_OnRename()
{
if (m_spsrm)
{
m_spsrm->Rename(m_hwnd);
}
}
void CPowerRenameUI::_OnAbout()
{
// Launch github page
SHELLEXECUTEINFO info = {0};
info.cbSize = sizeof(SHELLEXECUTEINFO);
info.lpVerb = L"open";
info.lpFile = L"https://github.com/microsoft/PowerToys/tree/master/src/modules/powerrename";
info.nShow = SW_SHOWDEFAULT;
ShellExecuteEx(&info);
}
HRESULT CPowerRenameUI::_DoModal(__in_opt HWND hwnd)
{
HRESULT hr = S_OK;
INT_PTR ret = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_MAIN), hwnd, s_DlgProc, (LPARAM)this);
if (ret < 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
INT_PTR CPowerRenameUI::_DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR bRet = TRUE; // default for all handled cases in switch below
switch (uMsg)
{
case WM_INITDIALOG:
_OnInitDlg();
break;
case WM_COMMAND:
_OnCommand(wParam, lParam);
break;
case WM_NOTIFY:
bRet = _OnNotify(wParam, lParam);
break;
case WM_CLOSE:
_OnCloseDlg();
break;
case WM_DESTROY:
_OnDestroyDlg();
break;
default:
bRet = FALSE;
}
return bRet;
}
void CPowerRenameUI::_OnInitDlg()
{
// Initialize from stored settings
_ReadSettings();
m_hwndLV = GetDlgItem(m_hwnd, IDC_LIST_PREVIEW);
m_listview.Init(m_hwndLV);
// Initialize checkboxes from flags
if (m_spsrm)
{
DWORD flags = 0;
m_spsrm->get_flags(&flags);
_SetCheckboxesFromFlags(flags);
}
if (m_spdo)
{
// Populate the manager from the data object
_EnumerateItems(m_spdo);
}
// Load the main icon
LoadIconWithScaleDown(g_hInst, MAKEINTRESOURCE(IDI_RENAME), 32, 32, &m_iconMain);
// Update the icon associated with our main app window
SendMessage(m_hwnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)m_iconMain);
SendMessage(m_hwnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)m_iconMain);
// TODO: put this behind a setting?
if (m_enableDragDrop)
{
RegisterDragDrop(m_hwnd, this);
}
// Disable rename button by default. It will be enabled in _UpdateCounts if
// there are tiems to be renamed
EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), FALSE);
// Update UI elements that depend on number of items selected or to be renamed
_UpdateCounts();
m_initialized = true;
}
void CPowerRenameUI::_OnCommand(_In_ WPARAM wParam, _In_ LPARAM lParam)
{
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
_OnCloseDlg();
break;
case ID_RENAME:
_OnRename();
break;
case ID_ABOUT:
_OnAbout();
break;
case IDC_EDIT_REPLACEWITH:
case IDC_EDIT_SEARCHFOR:
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
{
_OnSearchReplaceChanged();
}
break;
case IDC_CHECK_CASESENSITIVE:
case IDC_CHECK_ENUMITEMS:
case IDC_CHECK_EXCLUDEFILES:
case IDC_CHECK_EXCLUDEFOLDERS:
case IDC_CHECK_EXCLUDESUBFOLDERS:
case IDC_CHECK_MATCHALLOCCRENCES:
case IDC_CHECK_USEREGEX:
case IDC_CHECK_EXTENSIONONLY:
case IDC_CHECK_NAMEONLY:
if (BN_CLICKED == HIWORD(wParam))
{
_ValidateFlagCheckbox(LOWORD(wParam));
_GetFlagsFromCheckboxes();
}
break;
}
}
BOOL CPowerRenameUI::_OnNotify(_In_ WPARAM wParam, _In_ LPARAM lParam)
{
bool ret = FALSE;
LPNMHDR pnmdr = (LPNMHDR)lParam;
LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)pnmdr;
NMLVEMPTYMARKUP* pnmMarkup = NULL;
if (pnmdr)
{
BOOL checked = FALSE;
switch (pnmdr->code)
{
case HDN_ITEMSTATEICONCLICK:
if (m_spsrm)
{
m_listview.ToggleAll(m_spsrm, (!(((LPNMHEADER)lParam)->pitem->fmt & HDF_CHECKED)));
_UpdateCounts();
}
break;
case LVN_GETEMPTYMARKUP:
pnmMarkup = (NMLVEMPTYMARKUP*)lParam;
pnmMarkup->dwFlags = EMF_CENTERED;
LoadString(g_hInst, IDS_LISTVIEW_EMPTY, pnmMarkup->szMarkup, ARRAYSIZE(pnmMarkup->szMarkup));
ret = TRUE;
break;
case LVN_BEGINLABELEDIT:
ret = TRUE;
break;
case LVN_KEYDOWN:
if (m_spsrm)
{
m_listview.OnKeyDown(m_spsrm, (LV_KEYDOWN*)pnmdr);
_UpdateCounts();
}
break;
case LVN_GETDISPINFO:
if (m_spsrm)
{
m_listview.GetDisplayInfo(m_spsrm, (LV_DISPINFO*)pnmlv);
}
break;
case NM_CLICK:
{
if (m_spsrm)
{
m_listview.OnClickList(m_spsrm, (NM_LISTVIEW*)pnmdr);
_UpdateCounts();
}
break;
}
}
}
return ret;
}
void CPowerRenameUI::_OnSearchReplaceChanged()
{
// Pass updated search and replace terms to the IPowerRenameRegEx handler
CComPtr<IPowerRenameRegEx> spRegEx;
if (m_spsrm && SUCCEEDED(m_spsrm->get_smartRenameRegEx(&spRegEx)))
{
wchar_t buffer[MAX_PATH] = { 0 };
GetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer, ARRAYSIZE(buffer));
spRegEx->put_searchTerm(buffer);
buffer[0] = L'\0';
GetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer, ARRAYSIZE(buffer));
spRegEx->put_replaceTerm(buffer);
}
}
DWORD CPowerRenameUI::_GetFlagsFromCheckboxes()
{
DWORD flags = 0;
for (int i = 0; i < ARRAYSIZE(g_flagCheckboxMap); i++)
{
if (Button_GetCheck(GetDlgItem(m_hwnd, g_flagCheckboxMap[i].id)) == BST_CHECKED)
{
flags |= g_flagCheckboxMap[i].flag;
}
}
// Ensure we update flags
if (m_spsrm)
{
m_spsrm->put_flags(flags);
}
return flags;
}
void CPowerRenameUI::_SetCheckboxesFromFlags(_In_ DWORD flags)
{
for (int i = 0; i < ARRAYSIZE(g_flagCheckboxMap); i++)
{
Button_SetCheck(GetDlgItem(m_hwnd, g_flagCheckboxMap[i].id), flags & g_flagCheckboxMap[i].flag);
}
}
void CPowerRenameUI::_ValidateFlagCheckbox(_In_ DWORD checkBoxId)
{
if (checkBoxId == IDC_CHECK_NAMEONLY)
{
if (Button_GetCheck(GetDlgItem(m_hwnd, IDC_CHECK_NAMEONLY)) == BST_CHECKED)
{
Button_SetCheck(GetDlgItem(m_hwnd, IDC_CHECK_EXTENSIONONLY), FALSE);
}
}
else if (checkBoxId == IDC_CHECK_EXTENSIONONLY)
{
if (Button_GetCheck(GetDlgItem(m_hwnd, IDC_CHECK_EXTENSIONONLY)) == BST_CHECKED)
{
Button_SetCheck(GetDlgItem(m_hwnd, IDC_CHECK_NAMEONLY), FALSE);
}
}
}
void CPowerRenameUI::_UpdateCounts()
{
// This method is CPU intensive. We disable it during certain operations
// for performance reasons.
if (m_disableCountUpdate)
{
return;
}
UINT selectedCount = 0;
UINT renamingCount = 0;
if (m_spsrm)
{
m_spsrm->GetSelectedItemCount(&selectedCount);
m_spsrm->GetRenameItemCount(&renamingCount);
}
if (m_selectedCount != selectedCount ||
m_renamingCount != renamingCount)
{
m_selectedCount = selectedCount;
m_renamingCount = renamingCount;
// Update selected and rename count label
wchar_t countsLabelFormat[100] = { 0 };
LoadString(g_hInst, IDS_COUNTSLABELFMT, countsLabelFormat, ARRAYSIZE(countsLabelFormat));
wchar_t countsLabel[100] = { 0 };
StringCchPrintf(countsLabel, ARRAYSIZE(countsLabel), countsLabelFormat, selectedCount, renamingCount);
SetDlgItemText(m_hwnd, IDC_STATUS_MESSAGE, countsLabel);
// Update Rename button state
EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), (renamingCount > 0));
}
}
void CPowerRenameListView::Init(_In_ HWND hwndLV)
{
if (hwndLV)
{
m_hwndLV = hwndLV;
EnableWindow(m_hwndLV, TRUE);
// Set the standard styles
DWORD dwLVStyle = (DWORD)GetWindowLongPtr(m_hwndLV, GWL_STYLE);
dwLVStyle |= LVS_ALIGNLEFT | LVS_REPORT | LVS_SHAREIMAGELISTS | LVS_SINGLESEL;
SetWindowLongPtr(m_hwndLV, GWL_STYLE, dwLVStyle);
// Set the extended view styles
ListView_SetExtendedListViewStyle(m_hwndLV, LVS_EX_CHECKBOXES | LVS_EX_DOUBLEBUFFER);
// Get the system image lists. Our list view is setup to not destroy
// these since the image list belongs to the entire explorer process
HIMAGELIST himlLarge;
HIMAGELIST himlSmall;
if (Shell_GetImageLists(&himlLarge, &himlSmall))
{
ListView_SetImageList(m_hwndLV, himlSmall, LVSIL_SMALL);
ListView_SetImageList(m_hwndLV, himlLarge, LVSIL_NORMAL);
}
_UpdateColumns();
}
}
void CPowerRenameListView::ToggleAll(_In_ IPowerRenameManager* psrm, _In_ bool selected)
{
if (m_hwndLV)
{
UINT itemCount = 0;
psrm->GetItemCount(&itemCount);
for (UINT i = 0; i < itemCount; i++)
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(psrm->GetItemByIndex(i, &spItem)))
{
spItem->put_selected(selected);
}
}
RedrawItems(0, itemCount);
}
}
void CPowerRenameListView::ToggleItem(_In_ IPowerRenameManager* psrm, _In_ int item)
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(psrm->GetItemByIndex(item, &spItem)))
{
bool selected = false;
spItem->get_selected(&selected);
spItem->put_selected(!selected);
RedrawItems(item, item);
}
}
void CPowerRenameListView::OnKeyDown(_In_ IPowerRenameManager* psrm, _In_ LV_KEYDOWN* lvKeyDown)
{
if (lvKeyDown->wVKey == VK_SPACE)
{
int selectionMark = ListView_GetSelectionMark(m_hwndLV);
if (selectionMark != -1)
{
ToggleItem(psrm, selectionMark);
}
}
}
void CPowerRenameListView::OnClickList(_In_ IPowerRenameManager* psrm, NM_LISTVIEW* pnmListView)
{
LVHITTESTINFO hitinfo;
//Copy click point
hitinfo.pt = pnmListView->ptAction;
//Make the hit test...
int item = ListView_HitTest(m_hwndLV, &hitinfo);
if (item != -1)
{
if ((hitinfo.flags & LVHT_ONITEM) != 0)
{
ToggleItem(psrm, item);
}
}
}
void CPowerRenameListView::UpdateItemCheckState(_In_ IPowerRenameManager* psrm, _In_ int iItem)
{
if (psrm && m_hwndLV && (iItem > -1))
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(psrm->GetItemByIndex(iItem, &spItem)))
{
bool checked = ListView_GetCheckState(m_hwndLV, iItem);
spItem->put_selected(checked);
UINT uSelected = (checked) ? LVIS_SELECTED : 0;
ListView_SetItemState(m_hwndLV, iItem, uSelected, LVIS_SELECTED);
// Update the rename column if necessary
int id = 0;
spItem->get_id(&id);
RedrawItems(id, id);
}
// Get the total number of list items and compare it to what is selected
// We need to update the column checkbox if all items are selected or if
// not all of the items are selected.
bool checkHeader = (ListView_GetSelectedCount(m_hwndLV) == ListView_GetItemCount(m_hwndLV));
_UpdateHeaderCheckState(checkHeader);
}
}
#define COL_ORIGINAL_NAME 0
#define COL_NEW_NAME 1
void CPowerRenameListView::GetDisplayInfo(_In_ IPowerRenameManager* psrm, _Inout_ LV_DISPINFO* plvdi)
{
UINT count = 0;
psrm->GetItemCount(&count);
if (plvdi->item.iItem < 0 || plvdi->item.iItem > static_cast<int>(count))
{
// Invalid index
return;
}
CComPtr<IPowerRenameItem> renameItem;
if (SUCCEEDED(psrm->GetItemByIndex((int)plvdi->item.iItem, &renameItem)))
{
if (plvdi->item.mask & LVIF_IMAGE)
{
renameItem->get_iconIndex(&plvdi->item.iImage);
}
if (plvdi->item.mask & LVIF_STATE)
{
plvdi->item.stateMask = LVIS_STATEIMAGEMASK;
bool isSelected = false;
renameItem->get_selected(&isSelected);
if (isSelected)
{
// Turn check box on
plvdi->item.state = INDEXTOSTATEIMAGEMASK(2);
}
else
{
// Turn check box off
plvdi->item.state = INDEXTOSTATEIMAGEMASK(1);
}
}
if (plvdi->item.mask & LVIF_PARAM)
{
int id = 0;
renameItem->get_id(&id);
plvdi->item.lParam = static_cast<LPARAM>(id);
}
if (plvdi->item.mask & LVIF_INDENT)
{
UINT depth = 0;
renameItem->get_depth(&depth);
plvdi->item.iIndent = static_cast<int>(depth);
}
if (plvdi->item.mask & LVIF_TEXT)
{
PWSTR subItemText = nullptr;
if (plvdi->item.iSubItem == COL_ORIGINAL_NAME)
{
renameItem->get_originalName(&subItemText);
}
else if (plvdi->item.iSubItem == COL_NEW_NAME)
{
DWORD flags = 0;
psrm->get_flags(&flags);
bool shouldRename = false;
if (SUCCEEDED(renameItem->ShouldRenameItem(flags, &shouldRename)) && shouldRename)
{
renameItem->get_newName(&subItemText);
}
}
StringCchCopy(plvdi->item.pszText, plvdi->item.cchTextMax, subItemText ? subItemText : L"");
CoTaskMemFree(subItemText);
subItemText = nullptr;
}
}
}
void CPowerRenameListView::RedrawItems(_In_ int first, _In_ int last)
{
ListView_RedrawItems(m_hwndLV, first, last);
}
void CPowerRenameListView::SetItemCount(_In_ UINT itemCount)
{
ListView_SetItemCount(m_hwndLV, itemCount);
}
void CPowerRenameListView::_UpdateColumns()
{
if (m_hwndLV)
{
// And the list view columns
int iInsertPoint = 0;
LV_COLUMN lvc = { 0 };
lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_WIDTH | LVCF_TEXT;
lvc.fmt = LVCFMT_LEFT;
lvc.iOrder = iInsertPoint;
wchar_t buffer[64] = { 0 };
LoadString(g_hInst, IDS_ORIGINAL, buffer, ARRAYSIZE(buffer));
lvc.pszText = buffer;
ListView_InsertColumn(m_hwndLV, iInsertPoint, &lvc);
iInsertPoint++;
lvc.iOrder = iInsertPoint;
LoadString(g_hInst, IDS_RENAMED, buffer, ARRAYSIZE(buffer));
lvc.pszText = buffer;
ListView_InsertColumn(m_hwndLV, iInsertPoint, &lvc);
// Get a handle to the header of the columns
HWND hwndHeader = ListView_GetHeader(m_hwndLV);
if (hwndHeader)
{
// Update the header style to allow checkboxes
DWORD dwHeaderStyle = (DWORD)GetWindowLongPtr(hwndHeader, GWL_STYLE);
dwHeaderStyle |= HDS_CHECKBOXES;
SetWindowLongPtr(hwndHeader, GWL_STYLE, dwHeaderStyle);
_UpdateHeaderCheckState(TRUE);
}
_UpdateColumnSizes();
}
}
void CPowerRenameListView::_UpdateColumnSizes()
{
if (m_hwndLV)
{
RECT rc;
GetClientRect(m_hwndLV, &rc);
ListView_SetColumnWidth(m_hwndLV, 0, (rc.right - rc.left) / 2);
ListView_SetColumnWidth(m_hwndLV, 1, (rc.right - rc.left) / 2);
}
}
void CPowerRenameListView::_UpdateHeaderCheckState(_In_ bool check)
{
// Get a handle to the header of the columns
HWND hwndHeader = ListView_GetHeader(m_hwndLV);
if (hwndHeader)
{
wchar_t szBuff[MAX_PATH] = { 0 };
// Retrieve the existing header first so we
// don't trash the text already there
HDITEM hdi = { 0 };
hdi.mask = HDI_FORMAT | HDI_TEXT;
hdi.pszText = szBuff;
hdi.cchTextMax = ARRAYSIZE(szBuff);
Header_GetItem(hwndHeader, 0, &hdi);
// Set the first column to contain a checkbox
hdi.fmt |= HDF_CHECKBOX;
hdi.fmt |= (check) ? HDF_CHECKED : 0;
Header_SetItem(hwndHeader, 0, &hdi);
}
}

View file

@ -0,0 +1,133 @@
#pragma once
#include <PowerRenameInterfaces.h>
class CPowerRenameListView
{
public:
CPowerRenameListView() = default;
~CPowerRenameListView() = default;
void Init(_In_ HWND hwndLV);
void ToggleAll(_In_ IPowerRenameManager* psrm, _In_ bool selected);
void ToggleItem(_In_ IPowerRenameManager* psrm, _In_ int item);
void UpdateItemCheckState(_In_ IPowerRenameManager* psrm, _In_ int iItem);
void RedrawItems(_In_ int first, _In_ int last);
void SetItemCount(_In_ UINT itemCount);
void OnKeyDown(_In_ IPowerRenameManager* psrm, _In_ LV_KEYDOWN* lvKeyDown);
void OnClickList(_In_ IPowerRenameManager* psrm, NM_LISTVIEW* pnmListView);
void GetDisplayInfo(_In_ IPowerRenameManager* psrm, _Inout_ LV_DISPINFO* plvdi);
HWND GetHWND() { return m_hwndLV; }
private:
void _UpdateColumns();
void _UpdateColumnSizes();
void _UpdateHeaderCheckState(_In_ bool check);
HWND m_hwndLV = nullptr;
};
class CPowerRenameUI :
public IDropTarget,
public IPowerRenameUI,
public IPowerRenameManagerEvents
{
public:
CPowerRenameUI() :
m_refCount(1)
{
(void)OleInitialize(nullptr);
}
// IUnknown
IFACEMETHODIMP QueryInterface(__in REFIID riid, __deref_out void** ppv);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameUI
IFACEMETHODIMP Show();
IFACEMETHODIMP Close();
IFACEMETHODIMP Update();
IFACEMETHODIMP get_hwnd(_Out_ HWND* hwnd);
IFACEMETHODIMP get_showUI(_Out_ bool* showUI);
// IPowerRenameManagerEvents
IFACEMETHODIMP OnItemAdded(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnUpdate(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnError(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnRegExStarted(_In_ DWORD threadId);
IFACEMETHODIMP OnRegExCanceled(_In_ DWORD threadId);
IFACEMETHODIMP OnRegExCompleted(_In_ DWORD threadId);
IFACEMETHODIMP OnRenameStarted();
IFACEMETHODIMP OnRenameCompleted();
// IDropTarget
IFACEMETHODIMP DragEnter(_In_ IDataObject* pdtobj, DWORD grfKeyState, POINTL pt, _Inout_ DWORD* pdwEffect);
IFACEMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, _Inout_ DWORD* pdwEffect);
IFACEMETHODIMP DragLeave();
IFACEMETHODIMP Drop(_In_ IDataObject* pdtobj, DWORD grfKeyState, POINTL pt, _Inout_ DWORD* pdwEffect);
static HRESULT s_CreateInstance(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop, _Outptr_ IPowerRenameUI** ppsrui);
private:
~CPowerRenameUI()
{
DeleteObject(m_iconMain);
OleUninitialize();
}
HRESULT _DoModal(__in_opt HWND hwnd);
static INT_PTR CALLBACK s_DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CPowerRenameUI* pDlg = reinterpret_cast<CPowerRenameUI*>(GetWindowLongPtr(hdlg, DWLP_USER));
if (uMsg == WM_INITDIALOG)
{
pDlg = reinterpret_cast<CPowerRenameUI*>(lParam);
pDlg->m_hwnd = hdlg;
SetWindowLongPtr(hdlg, DWLP_USER, reinterpret_cast<LONG_PTR>(pDlg));
}
return pDlg ? pDlg->_DlgProc(uMsg, wParam, lParam) : FALSE;
}
INT_PTR _DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void _OnCommand(_In_ WPARAM wParam, _In_ LPARAM lParam);
BOOL _OnNotify(_In_ WPARAM wParam, _In_ LPARAM lParam);
HRESULT _Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop);
void _Cleanup();
void _OnInitDlg();
void _OnRename();
void _OnAbout();
void _OnCloseDlg();
void _OnDestroyDlg();
void _OnClear();
void _OnSearchReplaceChanged();
HRESULT _ReadSettings();
HRESULT _WriteSettings();
DWORD _GetFlagsFromCheckboxes();
void _SetCheckboxesFromFlags(_In_ DWORD flags);
void _ValidateFlagCheckbox(_In_ DWORD checkBoxId);
void _EnumerateItems(_In_ IDataObject* pdtobj);
void _UpdateCounts();
long m_refCount = 0;
bool m_initialized = false;
bool m_enableDragDrop = false;
bool m_disableCountUpdate = false;
HWND m_hwnd = nullptr;
HWND m_hwndLV = nullptr;
HICON m_iconMain = nullptr;
DWORD m_cookie = 0;
DWORD m_currentRegExId = 0;
UINT m_selectedCount = 0;
UINT m_renamingCount = 0;
CComPtr<IPowerRenameManager> m_spsrm;
CComPtr<IDataObject> m_spdo;
CComPtr<IDropTargetHelper> m_spdth;
CPowerRenameListView m_listview;
};

View file

@ -0,0 +1,165 @@
// Microsoft Visual C++ generated resource script.
⼀⼀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀琀愀爀最攀琀瘀攀爀⸀栀∀ഀ<EFBFBD>
⌀攀渀搀椀昀ഀ<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀眀椀渀搀漀眀猀⸀栀∀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀 ℀搀攀昀椀渀攀搀䄀䘀堀开刀䔀匀伀唀刀䌀䔀开䐀䰀䰀⤀ 簀簀 搀攀昀椀渀攀搀䄀䘀堀开吀䄀刀䜀开䔀一唀⤀ഀ<EFBFBD>
䰀䄀一䜀唀䄀䜀䔀 䰀䄀一䜀开䔀一䜀䰀䤀匀䠀Ⰰ 匀唀䈀䰀䄀一䜀开䔀一䜀䰀䤀匀䠀开唀匀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䄀挀挀攀氀攀爀愀琀漀爀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䌀开匀䴀䄀刀吀刀䔀一䄀䴀䔀 䄀䌀䌀䔀䰀䔀刀䄀吀伀刀匀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀㼀∀Ⰰ            䤀䐀䴀开䄀䈀伀唀吀Ⰰ              䄀匀䌀䤀䤀Ⰰ  䄀䰀吀ഀ<EFBFBD>
    ∀⼀∀Ⰰ            䤀䐀䴀开䄀䈀伀唀吀Ⰰ              䄀匀䌀䤀䤀Ⰰ  䄀䰀吀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䐀椀愀氀漀最ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䐀开䴀䄀䤀一 䐀䤀䄀䰀伀䜀䔀堀     ㌀㔀㄀Ⰰ  㐀ഀ<EFBFBD>
匀吀夀䰀䔀 䐀匀开匀䔀吀䘀伀一吀  䐀匀开䴀伀䐀䄀䰀䘀刀䄀䴀䔀  䐀匀开䘀䤀堀䔀䐀匀夀匀  圀匀开䴀䤀一䤀䴀䤀娀䔀䈀伀堀  圀匀开倀伀倀唀倀  圀匀开䌀䄀倀吀䤀伀一  圀匀开匀夀匀䴀䔀一唀ഀ<EFBFBD>
䌀䄀倀吀䤀伀一 ∀倀漀眀攀爀 刀攀渀愀洀攀∀ഀ<EFBFBD>
䘀伀一吀 㠀Ⰰ ∀䴀匀 匀栀攀氀氀 䐀氀最∀Ⰰ       砀㄀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䔀䐀䤀吀吀䔀堀吀        䤀䐀䌀开䔀䐀䤀吀开匀䔀䄀刀䌀䠀䘀伀刀Ⰰ㜀㄀Ⰰ㈀ Ⰰ㈀㔀㤀Ⰰ㄀㌀Ⰰ䔀匀开䄀唀吀伀䠀匀䌀刀伀䰀䰀ഀ<EFBFBD>
    䔀䐀䤀吀吀䔀堀吀        䤀䐀䌀开䔀䐀䤀吀开刀䔀倀䰀䄀䌀䔀圀䤀吀䠀Ⰰ㜀㄀Ⰰ㌀㠀Ⰰ㈀㔀㤀Ⰰ㄀㌀Ⰰ䔀匀开䄀唀吀伀䠀匀䌀刀伀䰀䰀ഀ<EFBFBD>
    䌀伀一吀刀伀䰀         ∀唀猀攀 刀攀最甀氀愀爀 䔀砀瀀爀攀猀猀椀漀渀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开唀匀䔀刀䔀䜀䔀堀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㄀Ⰰ㠀㌀Ⰰ㤀㌀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䌀愀猀攀 匀攀渀猀椀琀椀瘀攀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䌀䄀匀䔀匀䔀一匀䤀吀䤀嘀䔀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㄀Ⰰ㤀㔀Ⰰ㘀㄀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䴀愀琀挀栀 䄀氀氀 伀挀挀甀爀攀渀挀攀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䴀䄀吀䌀䠀䄀䰀䰀伀䌀䌀刀䔀一䌀䔀匀Ⰰഀ<EFBFBD>
                    ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㄀Ⰰ㄀ 㜀Ⰰ㠀㔀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䔀砀挀氀甀搀攀 䘀椀氀攀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䔀堀䌀䰀唀䐀䔀䘀䤀䰀䔀匀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㄀㌀㈀Ⰰ㠀㌀Ⰰ㔀㠀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䔀砀挀氀甀搀攀 䘀漀氀搀攀爀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䔀堀䌀䰀唀䐀䔀䘀伀䰀䐀䔀刀匀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㄀㌀㈀Ⰰ㤀㔀Ⰰ㘀㠀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䔀砀挀氀甀搀攀 匀甀戀昀漀氀搀攀爀 䤀琀攀洀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䔀堀䌀䰀唀䐀䔀匀唀䈀䘀伀䰀䐀䔀刀匀Ⰰഀ<EFBFBD>
                    ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㄀㌀㈀Ⰰ㄀ 㜀Ⰰ㤀㈀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䔀渀甀洀攀爀愀琀攀 䤀琀攀洀猀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䔀一唀䴀䤀吀䔀䴀匀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㐀㄀Ⰰ㠀㌀Ⰰ㜀㈀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䤀琀攀洀 一愀洀攀 伀渀氀礀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开一䄀䴀䔀伀一䰀夀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㐀㄀Ⰰ㤀㔀Ⰰ㘀㤀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀䤀琀攀洀 䔀砀琀攀渀猀椀漀渀 伀渀氀礀∀Ⰰ䤀䐀䌀开䌀䠀䔀䌀䬀开䔀堀吀䔀一匀䤀伀一伀一䰀夀Ⰰ∀䈀甀琀琀漀渀∀Ⰰ䈀匀开䄀唀吀伀䌀䠀䔀䌀䬀䈀伀堀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㐀㄀Ⰰ㄀ 㜀Ⰰ㠀㈀Ⰰ㄀ <EFBFBD>
    䌀伀一吀刀伀䰀         ∀∀Ⰰ䤀䐀䌀开䰀䤀匀吀开倀刀䔀嘀䤀䔀圀Ⰰ∀匀礀猀䰀椀猀琀嘀椀攀眀㌀㈀∀Ⰰ䰀嘀匀开刀䔀倀伀刀吀  䰀嘀匀开䄀䰀䤀䜀一䰀䔀䘀吀  䰀嘀匀开伀圀一䔀刀䐀䄀吀䄀  圀匀开䈀伀刀䐀䔀刀  圀匀开吀䄀䈀匀吀伀倀Ⰰ㈀㈀Ⰰ㄀㐀㠀Ⰰ㌀ 㠀Ⰰ㄀㄀㘀ഀ<EFBFBD>
    倀唀匀䠀䈀唀吀吀伀一      ∀☀刀攀渀愀洀攀∀Ⰰ䤀䐀开刀䔀一䄀䴀䔀Ⰰ㄀㜀㠀Ⰰ㈀㠀㌀Ⰰ㔀 Ⰰ㄀㐀ഀ<EFBFBD>
    倀唀匀䠀䈀唀吀吀伀一      ∀☀䠀攀氀瀀∀Ⰰ䤀䐀开䄀䈀伀唀吀Ⰰ㈀㌀㐀Ⰰ㈀㠀㌀Ⰰ㔀 Ⰰ㄀㐀ഀ<EFBFBD>
    倀唀匀䠀䈀唀吀吀伀一      ∀☀䌀愀渀挀攀氀∀Ⰰ䤀䐀䌀䄀一䌀䔀䰀Ⰰ㈀㤀 Ⰰ㈀㠀㌀Ⰰ㔀 Ⰰ㄀㐀ഀ<EFBFBD>
    刀吀䔀堀吀           ∀匀攀愀爀挀栀 昀漀爀㨀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㈀㔀Ⰰ㈀㌀Ⰰ㌀㤀Ⰰ㠀ഀ<EFBFBD>
    䰀吀䔀堀吀           ∀刀攀瀀氀愀挀攀 眀椀琀栀㨀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㈀㄀Ⰰ㐀 Ⰰ㐀㌀Ⰰ㠀ഀ<EFBFBD>
    䰀吀䔀堀吀           ∀䤀琀攀洀猀 匀攀氀攀挀琀攀搀㨀    刀攀渀愀洀椀渀最㨀  ∀Ⰰ䤀䐀䌀开匀吀䄀吀唀匀开䴀䔀匀匀䄀䜀䔀Ⰰ㄀㄀Ⰰ㈀㠀㐀Ⰰ㄀㌀㜀Ⰰ㄀㌀ഀ<EFBFBD>
    䜀刀伀唀倀䈀伀堀        ∀伀瀀琀椀漀渀猀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㄀㄀Ⰰ㘀㠀Ⰰ㌀㈀㤀Ⰰ㔀㠀ഀ<EFBFBD>
    䜀刀伀唀倀䈀伀堀        ∀倀爀攀瘀椀攀眀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㄀㄀Ⰰ㄀㌀㌀Ⰰ㌀㈀㤀Ⰰ㄀㐀㈀ഀ<EFBFBD>
    䜀刀伀唀倀䈀伀堀        ∀䔀渀琀攀爀 琀栀攀 挀爀椀琀攀爀椀愀 戀攀氀漀眀 琀漀 爀攀渀愀洀攀 琀栀攀 椀琀攀洀猀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㄀㄀Ⰰ㜀Ⰰ㌀㈀㤀Ⰰ㔀㔀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䐀䔀匀䤀䜀一䤀一䘀伀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
䜀唀䤀䐀䔀䰀䤀一䔀匀 䐀䔀匀䤀䜀一䤀一䘀伀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䤀䐀䐀开䴀䄀䤀一Ⰰ 䐀䤀䄀䰀伀䜀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        䰀䔀䘀吀䴀䄀刀䜀䤀一Ⰰ ㄀㄀ഀ<EFBFBD>
        刀䤀䜀䠀吀䴀䄀刀䜀䤀一Ⰰ ㌀㐀 <EFBFBD>
        吀伀倀䴀䄀刀䜀䤀一Ⰰ 㜀ഀ<EFBFBD>
        䈀伀吀吀伀䴀䴀䄀刀䜀䤀一Ⰰ ㈀㤀㜀ഀ<EFBFBD>
    䔀一䐀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀爀攀猀漀甀爀挀攀⸀栀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀琀愀爀最攀琀瘀攀爀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀攀渀搀椀昀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀眀椀渀搀漀眀猀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀 <EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䤀挀漀渀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
⼀⼀ 䤀挀漀渀 眀椀琀栀 氀漀眀攀猀琀 䤀䐀 瘀愀氀甀攀 瀀氀愀挀攀搀 昀椀爀猀琀 琀漀 攀渀猀甀爀攀 愀瀀瀀氀椀挀愀琀椀漀渀 椀挀漀渀ഀ<EFBFBD>
⼀⼀ 爀攀洀愀椀渀猀 挀漀渀猀椀猀琀攀渀琀 漀渀 愀氀氀 猀礀猀琀攀洀猀⸀ഀ<EFBFBD>
䤀䐀䤀开刀䔀一䄀䴀䔀              䤀䌀伀一                    ∀刀攀渀愀洀攀⸀椀挀漀∀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 匀琀爀椀渀最 吀愀戀氀攀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
匀吀刀䤀一䜀吀䄀䈀䰀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䤀䐀匀开䄀倀倀开吀䤀吀䰀䔀           ∀倀漀眀攀爀刀攀渀愀洀攀∀ഀ<EFBFBD>
    䤀䐀匀开刀䔀一䄀䴀䔀䐀             ∀刀攀渀愀洀攀搀∀ഀ<EFBFBD>
    䤀䐀匀开伀刀䤀䜀䤀一䄀䰀            ∀伀爀椀最椀渀愀氀∀ഀ<EFBFBD>
    䤀䐀匀开䰀䤀匀吀嘀䤀䔀圀开䔀䴀倀吀夀      ∀䄀氀氀 椀琀攀洀猀 栀愀瘀攀 戀攀攀渀 昀椀氀琀攀爀攀搀 漀甀琀⸀尀渀倀氀攀愀猀攀 猀攀氀攀挀琀 昀爀漀洀 琀栀攀 漀瀀琀椀漀渀猀 愀戀漀瘀攀 琀漀 猀栀漀眀 椀琀攀洀猀⸀∀ഀ<EFBFBD>
    䤀䐀匀开䔀一吀䤀刀䔀䤀吀䔀䴀一䄀䴀䔀      ∀䤀琀攀洀 一愀洀攀 愀渀搀 䔀砀琀攀渀猀椀漀渀∀ഀ<EFBFBD>
    䤀䐀䌀开匀䴀䄀刀吀刀䔀一䄀䴀䔀         ∀匀䴀䄀刀吀刀䔀一䄀䴀䔀∀ഀ<EFBFBD>
    䤀䐀匀开䌀伀唀一吀匀䰀䄀䈀䔀䰀䘀䴀吀      ∀䤀琀攀洀猀 匀攀氀攀挀琀攀搀㨀 ─甀  刀攀渀愀洀椀渀最㨀 ─甀∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䔀渀最氀椀猀栀 唀渀椀琀攀搀 匀琀愀琀攀猀⤀ 爀攀猀漀甀爀挀攀猀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀  爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 渀漀琀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>

View file

@ -0,0 +1,187 @@
<?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>{0E072714-D127-460B-AFAD-B4C40B412798}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRename</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>PowerRenameUI</ProjectName>
</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'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(OutDir)PowerRenameLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</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;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</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;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="PowerRenameUI.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameUI.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>
<ItemGroup>
<ResourceCompile Include="PowerRenameUI.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="Rename.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

View file

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

View file

@ -0,0 +1,14 @@
#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>

View file

@ -0,0 +1,8 @@
#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>

View file

@ -0,0 +1,34 @@
#include "stdafx.h"
#include "MockPowerRenameItem.h"
HRESULT CMockPowerRenameItem::CreateInstance(_In_opt_ PCWSTR path, _In_opt_ PCWSTR originalName, _In_ UINT depth, _In_ bool isFolder, _Outptr_ IPowerRenameItem** ppItem)
{
*ppItem = nullptr;
CMockPowerRenameItem* newItem = new CMockPowerRenameItem();
HRESULT hr = newItem ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
newItem->Init(path, originalName, depth, isFolder);
hr = newItem->QueryInterface(IID_PPV_ARGS(ppItem));
newItem->Release();
}
return hr;
}
void CMockPowerRenameItem::Init(_In_opt_ PCWSTR path, _In_opt_ PCWSTR originalName, _In_ UINT depth, _In_ bool isFolder)
{
if (path != nullptr)
{
SHStrDup(path, &m_path);
}
if (originalName != nullptr)
{
SHStrDup(originalName, &m_originalName);
}
m_depth = depth;
m_isFolder = isFolder;
}

View file

@ -0,0 +1,12 @@
#pragma once
#include "stdafx.h"
#include <PowerRenameItem.h>
#include "srwlock.h"
class CMockPowerRenameItem :
public CPowerRenameItem
{
public:
static HRESULT CreateInstance(_In_opt_ PCWSTR path, _In_opt_ PCWSTR originalName, _In_ UINT depth, _In_ bool isFolder, _Outptr_ IPowerRenameItem** ppItem);
void Init(_In_opt_ PCWSTR path, _In_opt_ PCWSTR originalName, _In_ UINT depth, _In_ bool isFolder);
};

View file

@ -0,0 +1,92 @@
#include "stdafx.h"
#include "MockPowerRenameManagerEvents.h"
// IUnknown
IFACEMETHODIMP CMockPowerRenameManagerEvents::QueryInterface(__in REFIID riid, __deref_out void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CMockPowerRenameManagerEvents, IPowerRenameManagerEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) CMockPowerRenameManagerEvents::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CMockPowerRenameManagerEvents::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
// IPowerRenameManagerEvents
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnItemAdded(_In_ IPowerRenameItem* pItem)
{
m_itemAdded = pItem;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnUpdate(_In_ IPowerRenameItem* pItem)
{
m_itemUpdated = pItem;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnError(_In_ IPowerRenameItem* pItem)
{
m_itemError = pItem;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnRegExStarted(_In_ DWORD threadId)
{
m_regExStarted = true;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnRegExCanceled(_In_ DWORD threadId)
{
m_regExCanceled = true;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnRegExCompleted(_In_ DWORD threadId)
{
m_regExCompleted = true;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnRenameStarted()
{
m_renameStarted = true;
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameManagerEvents::OnRenameCompleted()
{
m_renameCompleted = true;
return S_OK;
}
HRESULT CMockPowerRenameManagerEvents::s_CreateInstance(_In_ IPowerRenameManager* psrm, _Outptr_ IPowerRenameUI** ppsrui)
{
*ppsrui = nullptr;
CMockPowerRenameManagerEvents* events = new CMockPowerRenameManagerEvents();
HRESULT hr = events != nullptr ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = events->QueryInterface(IID_PPV_ARGS(ppsrui));
events->Release();
}
return hr;
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <PowerRenameInterfaces.h>
class CMockPowerRenameManagerEvents :
public IPowerRenameManagerEvents
{
public:
CMockPowerRenameManagerEvents() :
m_refCount(1)
{
}
// IUnknown
IFACEMETHODIMP QueryInterface(__in REFIID riid, __deref_out void** ppv);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameManagerEvents
IFACEMETHODIMP OnItemAdded(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnUpdate(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnError(_In_ IPowerRenameItem* renameItem);
IFACEMETHODIMP OnRegExStarted(_In_ DWORD threadId);
IFACEMETHODIMP OnRegExCanceled(_In_ DWORD threadId);
IFACEMETHODIMP OnRegExCompleted(_In_ DWORD threadId);
IFACEMETHODIMP OnRenameStarted();
IFACEMETHODIMP OnRenameCompleted();
static HRESULT s_CreateInstance(_In_ IPowerRenameManager* psrm, _Outptr_ IPowerRenameUI** ppsrui);
~CMockPowerRenameManagerEvents()
{
}
CComPtr<IPowerRenameItem> m_itemAdded;
CComPtr<IPowerRenameItem> m_itemUpdated;
CComPtr<IPowerRenameItem> m_itemError;
bool m_regExStarted = false;
bool m_regExCanceled = false;
bool m_regExCompleted = false;
bool m_renameStarted = false;
bool m_renameCompleted = false;
long m_refCount = 0;
};

View file

@ -0,0 +1,69 @@
#include "stdafx.h"
#include "MockPowerRenameRegExEvents.h"
IFACEMETHODIMP_(ULONG) CMockPowerRenameRegExEvents::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CMockPowerRenameRegExEvents::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
IFACEMETHODIMP CMockPowerRenameRegExEvents::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
{
static const QITAB qit[] = {
QITABENT(CMockPowerRenameRegExEvents, IPowerRenameRegExEvents),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP CMockPowerRenameRegExEvents::OnSearchTermChanged(_In_ PCWSTR searchTerm)
{
CoTaskMemFree(m_searchTerm);
m_searchTerm = nullptr;
if (searchTerm != nullptr)
{
SHStrDup(searchTerm, &m_searchTerm);
}
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameRegExEvents::OnReplaceTermChanged(_In_ PCWSTR replaceTerm)
{
CoTaskMemFree(m_replaceTerm);
m_replaceTerm = nullptr;
if (replaceTerm != nullptr)
{
SHStrDup(replaceTerm, &m_replaceTerm);
}
return S_OK;
}
IFACEMETHODIMP CMockPowerRenameRegExEvents::OnFlagsChanged(_In_ DWORD flags)
{
m_flags = flags;
return S_OK;
}
HRESULT CMockPowerRenameRegExEvents::s_CreateInstance(_Outptr_ IPowerRenameRegExEvents** ppsrree)
{
*ppsrree = nullptr;
CMockPowerRenameRegExEvents* psrree = new CMockPowerRenameRegExEvents();
HRESULT hr = psrree ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = psrree->QueryInterface(IID_PPV_ARGS(ppsrree));
psrree->Release();
}
return hr;
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <vector>
#include "srwlock.h"
class CMockPowerRenameRegExEvents:
public IPowerRenameRegExEvents
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
// IPowerRenameRegExEvents
IFACEMETHODIMP OnSearchTermChanged(_In_ PCWSTR searchTerm);
IFACEMETHODIMP OnReplaceTermChanged(_In_ PCWSTR replaceTerm);
IFACEMETHODIMP OnFlagsChanged(_In_ DWORD flags);
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegExEvents** ppsrree);
CMockPowerRenameRegExEvents() :
m_refCount(1)
{
}
~CMockPowerRenameRegExEvents()
{
CoTaskMemFree(m_searchTerm);
CoTaskMemFree(m_replaceTerm);
}
PWSTR m_searchTerm = nullptr;
PWSTR m_replaceTerm = nullptr;
DWORD m_flags = 0;
long m_refCount;
};

View file

@ -0,0 +1,198 @@
<?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>{2151F984-E006-4A9F-92EF-C6DDE3DC8413}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameLibUnitTests</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>PowerRenameUnitTests</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</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'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;comctl32.lib;pathcch.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Pathcch.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameLib.lib;%(AdditionalDependencies);</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;comctl32.lib;pathcch.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Pathcch.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;$(OutDir)PowerRenameLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;comctl32.lib;pathcch.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Pathcch.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;comctl32.lib;pathcch.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Pathcch.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="MockPowerRenameItem.h" />
<ClInclude Include="MockPowerRenameManagerEvents.h" />
<ClInclude Include="MockPowerRenameRegExEvents.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="TestFileHelper.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="MockPowerRenameItem.cpp" />
<ClCompile Include="MockPowerRenameManagerEvents.cpp" />
<ClCompile Include="MockPowerRenameRegExEvents.cpp" />
<ClCompile Include="PowerRenameManagerTests.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>
<ClCompile Include="PowerRenameRegExTests.cpp" />
<ClCompile Include="TestFileHelper.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,241 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include <PowerRenameInterfaces.h>
#include <PowerRenameManager.h>
#include <PowerRenameItem.h>
#include "MockPowerRenameItem.h"
#include "MockPowerRenameManagerEvents.h"
#include "TestFileHelper.h"
#define DEFAULT_FLAGS MatchAllOccurences
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
HINSTANCE g_hInst = HINST_THISCOMPONENT;
namespace PowerRenameManagerTests
{
TEST_CLASS(SimpleTests)
{
public:
struct rename_pairs
{
std::wstring originalName;
std::wstring newName;
bool isFile;
bool shouldRename;
int depth;
};
void RenameHelper(_In_ rename_pairs* renamePairs, _In_ int numPairs, _In_ std::wstring searchTerm, _In_ std::wstring replaceTerm, _In_ DWORD flags)
{
// Create a single item (in a temp directory) and verify rename works as expected
CTestFileHelper testFileHelper;
for (int i = 0; i < numPairs; i++)
{
if (renamePairs[i].isFile)
{
Assert::IsTrue(testFileHelper.AddFile(renamePairs[i].originalName));
}
else
{
Assert::IsTrue(testFileHelper.AddFolder(renamePairs[i].originalName));
}
}
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
CMockPowerRenameManagerEvents* mockMgrEvents = new CMockPowerRenameManagerEvents();
CComPtr<IPowerRenameManagerEvents> mgrEvents;
Assert::IsTrue(mockMgrEvents->QueryInterface(IID_PPV_ARGS(&mgrEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(mgr->Advise(mgrEvents, &cookie) == S_OK);
for (int i = 0; i < numPairs; i++)
{
CComPtr<IPowerRenameItem> item;
CMockPowerRenameItem::CreateInstance(testFileHelper.GetFullPath(
renamePairs[i].originalName).c_str(),
renamePairs[i].originalName.c_str(),
renamePairs[i].depth,
!renamePairs[i].isFile,
&item);
int itemId = 0;
Assert::IsTrue(item->get_id(&itemId) == S_OK);
mgr->AddItem(item);
// Verify the item we added is the same from the event
Assert::IsTrue(mockMgrEvents->m_itemAdded != nullptr && mockMgrEvents->m_itemAdded == item);
int eventItemId = 0;
Assert::IsTrue(mockMgrEvents->m_itemAdded->get_id(&eventItemId) == S_OK);
Assert::IsTrue(itemId == eventItemId);
}
// TODO: Setup match and replace parameters
CComPtr<IPowerRenameRegEx> renRegEx;
Assert::IsTrue(mgr->get_smartRenameRegEx(&renRegEx) == S_OK);
renRegEx->put_flags(flags);
renRegEx->put_searchTerm(searchTerm.c_str());
renRegEx->put_replaceTerm(replaceTerm.c_str());
Sleep(1000);
// Perform the rename
Assert::IsTrue(mgr->Rename(0) == S_OK);
Sleep(1000);
// Verify the rename occurred
for (int i = 0; i < numPairs; i++)
{
Assert::IsTrue(testFileHelper.PathExists(renamePairs[i].originalName) == !renamePairs[i].shouldRename);
Assert::IsTrue(testFileHelper.PathExists(renamePairs[i].newName) == renamePairs[i].shouldRename);
}
Assert::IsTrue(mgr->Shutdown() == S_OK);
mockMgrEvents->Release();
}
TEST_METHOD(CreateTest)
{
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
}
TEST_METHOD(CreateAndShutdownTest)
{
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
Assert::IsTrue(mgr->Shutdown() == S_OK);
}
TEST_METHOD(AddItemTest)
{
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
CComPtr<IPowerRenameItem> item;
CMockPowerRenameItem::CreateInstance(L"foo", L"foo", 0, false, &item);
mgr->AddItem(item);
Assert::IsTrue(mgr->Shutdown() == S_OK);
}
TEST_METHOD(VerifySmartManagerEvents)
{
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
CMockPowerRenameManagerEvents* mockMgrEvents = new CMockPowerRenameManagerEvents();
CComPtr<IPowerRenameManagerEvents> mgrEvents;
Assert::IsTrue(mockMgrEvents->QueryInterface(IID_PPV_ARGS(&mgrEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(mgr->Advise(mgrEvents, &cookie) == S_OK);
CComPtr<IPowerRenameItem> item;
CMockPowerRenameItem::CreateInstance(L"foo", L"foo", 0, false, &item);
int itemId = 0;
Assert::IsTrue(item->get_id(&itemId) == S_OK);
mgr->AddItem(item);
// Verify the item we added is the same from the event
Assert::IsTrue(mockMgrEvents->m_itemAdded != nullptr && mockMgrEvents->m_itemAdded == item);
int eventItemId = 0;
Assert::IsTrue(mockMgrEvents->m_itemAdded->get_id(&eventItemId) == S_OK);
Assert::IsTrue(itemId == eventItemId);
Assert::IsTrue(mgr->Shutdown() == S_OK);
mockMgrEvents->Release();
}
TEST_METHOD(VerifySingleRename)
{
// Create a single item and verify rename works as expected
rename_pairs renamePairs[] =
{
{L"foo.txt", L"bar.txt", true, true}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS);
}
TEST_METHOD(VerifyMultiRename)
{
// Create a single item and verify rename works as expected
rename_pairs renamePairs[] =
{
{L"foo1.txt", L"bar1.txt", true, true, 0},
{L"foo2.txt", L"bar2.txt", true, true, 0},
{L"foo3.txt", L"bar3.txt", true, true, 0},
{L"foo4.txt", L"bar4.txt", true, true, 0},
{L"foo5.txt", L"bar5.txt", true, true, 0},
{L"baa.txt", L"baa_norename.txt", true, false, 0}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS);
}
TEST_METHOD(VerifyFilesOnlyRename)
{
// Verify only files are renamed when folders match too
rename_pairs renamePairs[] =
{
{L"foo.txt", L"bar.txt", true, true, 0},
{L"foo", L"foo_norename", false, false, 0}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS | ExcludeFolders);
}
TEST_METHOD(VerifyFoldersOnlyRename)
{
// Verify only folders are renamed when files match too
rename_pairs renamePairs[] =
{
{L"foo.txt", L"foo_norename.txt", true, false, 0},
{L"foo", L"bar", false, true, 0}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS | ExcludeFiles);
}
TEST_METHOD(VerifyFileNameOnlyRename)
{
// Verify only file name is renamed, not extension
rename_pairs renamePairs[] =
{
{L"foo.foo", L"bar.foo", true, true, 0},
{L"test.foo", L"test.foo_norename", true, false, 0}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS | NameOnly);
}
TEST_METHOD(VerifyFileExtensionOnlyRename)
{
// Verify only file extension is renamed, not name
rename_pairs renamePairs[] =
{
{L"foo.foo", L"foo.bar", true, true, 0},
{L"test.foo", L"test.bar", true, true, 0}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS | ExtensionOnly);
}
TEST_METHOD(VerifySubFoldersRename)
{
// Verify subfolders do not get renamed
rename_pairs renamePairs[] =
{
{L"foo1", L"bar1", false, true, 0},
{L"foo2", L"foo2_norename", false, false, 1}
};
RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", DEFAULT_FLAGS | ExcludeSubfolders);
}
};
}

View file

@ -0,0 +1,331 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include <PowerRenameInterfaces.h>
#include <PowerRenameRegEx.h>
#include "MockPowerRenameRegExEvents.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PowerRenameRegExTests
{
struct SearchReplaceExpected
{
PCWSTR search;
PCWSTR replace;
PCWSTR test;
PCWSTR expected;
};
TEST_CLASS(SimpleTests)
{
public:
TEST_METHOD(GeneralReplaceTest)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bigbar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoMatch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(L"notfound") == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"foobar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoSearchOrReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) != S_OK);
Assert::IsTrue(result == nullptr);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceEmptyStringReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(L"") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(VerifyDefaultFlags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->get_flags(&flags) == S_OK);
Assert::IsTrue(flags == MatchAllOccurences);
}
TEST_METHOD(VerifyCaseSensitiveSearch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = CaseSensitive;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"Foo", L"Foo", L"FooBar", L"FooBar" },
{ L"Foo", L"boo", L"FooBar", L"booBar" },
{ L"Foo", L"boo", L"foobar", L"foobar" },
{ L"123", L"654", L"123456", L"654456" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnly)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAll)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurences;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllCaseInsensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurences | CaseSensitive;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnlyUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurences | UseRegularExpressions;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegExCaseSensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyMatchAllWildcardUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurences | UseRegularExpressions;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L".*", L"Foo", L"AAAAAA", L"Foo" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstWildcardUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
SearchReplaceExpected sreTable[] =
{
{ L".*", L"Foo", L"AAAAAA", L"FooAAAA" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->put_searchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyEventsFire)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
CMockPowerRenameRegExEvents* mockEvents = new CMockPowerRenameRegExEvents();
CComPtr<IPowerRenameRegExEvents> regExEvents;
Assert::IsTrue(mockEvents->QueryInterface(IID_PPV_ARGS(&regExEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(renameRegEx->Advise(regExEvents, &cookie) == S_OK);
DWORD flags = MatchAllOccurences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->put_flags(flags) == S_OK);
Assert::IsTrue(renameRegEx->put_searchTerm(L"FOO") == S_OK);
Assert::IsTrue(renameRegEx->put_replaceTerm(L"BAR") == S_OK);
Assert::IsTrue(lstrcmpi(L"FOO", mockEvents->m_searchTerm) == 0);
Assert::IsTrue(lstrcmpi(L"BAR", mockEvents->m_replaceTerm) == 0);
Assert::IsTrue(flags == mockEvents->m_flags);
Assert::IsTrue(renameRegEx->UnAdvise(cookie) == S_OK);
mockEvents->Release();
}
};
}

View file

@ -0,0 +1,73 @@
#include "stdafx.h"
#include "TestFileHelper.h"
#include <iostream>
#include <fstream>
#include <Objbase.h>
namespace fs = std::filesystem;
CTestFileHelper::CTestFileHelper()
{
_CreateTempDirectory();
}
CTestFileHelper::~CTestFileHelper()
{
_DeleteTempDirectory();
}
// Pass a relative path which will be appended to the temp directory path
bool CTestFileHelper::AddFile(_In_ const std::wstring path)
{
fs::path newFilePath = _tempDirectory;
newFilePath.append(path);
std::ofstream ofs(newFilePath);
ofs.close();
return true;
}
// Pass a relative path which will be appended to the temp directory path
bool CTestFileHelper::AddFolder(_In_ const std::wstring path)
{
fs::path newFolderPath = _tempDirectory;
newFolderPath.append(path);
return fs::create_directory(fs::path(newFolderPath));
}
fs::path CTestFileHelper::GetFullPath(_In_ const std::wstring path)
{
fs::path fullPath = _tempDirectory;
fullPath.append(path);
return fullPath;
}
bool CTestFileHelper::PathExists(_In_ const std::wstring path)
{
fs::path fullPath = _tempDirectory;
fullPath.append(path);
return fs::exists(fullPath);
}
bool CTestFileHelper::_CreateTempDirectory()
{
// Initialize to the temp directory
_tempDirectory = fs::temp_directory_path();
// Create a unique folder name
GUID guid = { 0 };
CoCreateGuid(&guid);
wchar_t uniqueName[MAX_PATH] = { 0 };
StringFromGUID2(guid, uniqueName, ARRAYSIZE(uniqueName));
_tempDirectory.append(uniqueName);
return fs::create_directory(_tempDirectory);
}
void CTestFileHelper::_DeleteTempDirectory()
{
fs::remove_all(_tempDirectory);
}

View file

@ -0,0 +1,25 @@
#pragma once
#include <filesystem>
#include <string>
#include <windows.h>
class CTestFileHelper
{
public:
CTestFileHelper();
~CTestFileHelper();
bool AddFile(_In_ const std::wstring path);
bool AddFolder(_In_ const std::wstring path);
const std::filesystem::path GetTempDirectory() { return _tempDirectory; }
bool PathExists(_In_ const std::wstring path);
std::filesystem::path GetFullPath(_In_ const std::wstring path);
private:
bool _CreateTempDirectory();
void _DeleteTempDirectory();
std::filesystem::path _tempDirectory;
};

View file

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

View file

@ -0,0 +1,9 @@
#pragma once
#include "targetver.h"
#include <atlbase.h>
// Headers for CppUnitTest
#include "CppUnitTest.h"

View file

@ -0,0 +1,10 @@
#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>

View file

@ -53,7 +53,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// For now only load known DLLs
std::unordered_set<std::wstring> known_dlls = {
L"shortcut_guide.dll",
L"fancyzones.dll"
L"fancyzones.dll",
L"PowerRenameExt.dll"
};
for (auto& file : std::filesystem::directory_iterator(L"modules/")) {
if (file.path().extension() != L".dll")