mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-06 04:17:04 +01:00
Compare commits
4 Commits
leilzh/tes
...
leilzh/reg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5386572092 | ||
|
|
0f1ccaee2d | ||
|
|
68b708f2fd | ||
|
|
3088908202 |
@@ -262,6 +262,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
|
||||
src\common\utils\excluded_apps.h = src\common\utils\excluded_apps.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\exec.h = src\common\utils\exec.h
|
||||
src\common\utils\game_mode.h = src\common\utils\game_mode.h
|
||||
src\common\utils\gpo.h = src\common\utils\gpo.h
|
||||
|
||||
@@ -14,21 +14,6 @@
|
||||
<DirectoryRef Id="FileLocksmithAssetsInstallFolder" FileSource="$(var.FileLocksmithAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--FileLocksmithAssetsFiles_Component_Def-->
|
||||
<!-- !Warning! Make sure to change Component Guid if you update something here -->
|
||||
<Component Id="Module_FileLocksmith" Guid="108D3EC1-E6E0-4E81-88EF-25966133CB41" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{84D68575-E186-46AD-B0CB-BAEB45EE29C0}">
|
||||
<RegistryValue Type="string" Value="File Locksmith Shell Extension" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.FileLocksmithExt.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt">
|
||||
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt">
|
||||
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="FileLocksmithComponentGroup">
|
||||
@@ -38,7 +23,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderFileLocksmithAssetsFolder" Directory="FileLocksmithAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_FileLocksmith" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
|
||||
@@ -16,71 +16,6 @@
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--ImageResizerAssetsFiles_Component_Def-->
|
||||
|
||||
<Component Id="Module_ImageResizer_Registry" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32">
|
||||
<RegistryValue Value="[WinUI3AppsInstallFolder]PowerToys.ImageResizerExt.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Apartment" Type="string" />
|
||||
</RegistryKey>
|
||||
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\Directory\ShellEx\DragDropHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<!-- Registry Keys for the context menu handler for each of the following image formats: bmp, dib, gif, jfif, jpe, jpeg, jpg, jxr, png, rle, tif, tiff, wdp -->
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.bmp\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.dib\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.gif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jfif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpe\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpeg\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jpg\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.jxr\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.png\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.rle\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.tif\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.tiff\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
<RegistryValue Root="$(var.RegistryScope)"
|
||||
Key="SOFTWARE\Classes\SystemFileAssociations\.wdp\ShellEx\ContextMenuHandlers\ImageResizer"
|
||||
Value="{51B4D7E5-7568-4234-B4BB-47FB3C016A69}"
|
||||
Type="string" />
|
||||
</Component>
|
||||
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="ImageResizerComponentGroup">
|
||||
@@ -90,7 +25,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderImageResizerAssetsFolder" Directory="ImageResizerAssetsFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_ImageResizer_Registry" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -18,19 +18,6 @@
|
||||
<DirectoryRef Id="NewPlusAssetsInstallFolder" FileSource="$(var.NewPlusAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--NewPlusAssetsFiles_Component_Def-->
|
||||
|
||||
<!-- NewPlus Shell Extension for Win10 registration -->
|
||||
<Component Id="NewPlus_ShellExtension_win10" Guid="D5456D4A-6EEC-4B85-944D-6A6A4A74FFA6" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{FF90D477-E32A-4BE8-8CC5-A502A97F5401}">
|
||||
<RegistryValue Type="string" Value="NewPlus Shell Extension Win10" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.NewPlus.ShellExtension.win10.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\NewPlusShellExtensionWin10">
|
||||
<RegistryValue Type="string" Value="{FF90D477-E32A-4BE8-8CC5-A502A97F5401}"/>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="NewPlusComponentGroup">
|
||||
@@ -40,8 +27,7 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusAssetsFolder" Directory="NewPlusAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlus_ShellExtension_win10" />
|
||||
</ComponentGroup>
|
||||
</ComponentGroup>
|
||||
|
||||
|
||||
<!-- Example templates -->
|
||||
@@ -81,7 +67,7 @@
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlusTemplateFiles_Component" />
|
||||
<ComponentRef Id="NewPlusTemplateSubFiles_Component" />
|
||||
</ComponentGroup>
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -14,22 +14,6 @@
|
||||
<DirectoryRef Id="PowerRenameAssetsFolder" FileSource="$(var.PowerRenameAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--PowerRenameAssetsFiles_Component_Def-->
|
||||
<!-- !Warning! Make sure to change Component Guid if you update something here -->
|
||||
<Component Id="Module_PowerRename" Guid="40D43079-240E-402D-8CE8-571BFFA71175" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
|
||||
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.PowerRenameExt.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\PowerRenameExt">
|
||||
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\PowerRenameExt">
|
||||
<RegistryValue Type="string" Value="{0440049F-D1DC-4E46-B27B-98393D79486B}"/>
|
||||
</RegistryKey>
|
||||
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="PowerRenameComponentGroup">
|
||||
@@ -39,7 +23,6 @@
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderPowerRenameAssetsFolder" Directory="PowerRenameAssetsFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
|
||||
@@ -176,6 +176,18 @@
|
||||
<Custom Action="UnRegisterContextMenuPackages" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanImageResizerRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanFileLocksmithRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanPowerRenameRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="CleanNewPlusRuntimeRegistry" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="UnRegisterCmdPalPackage" Before="RemoveFiles">
|
||||
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
@@ -206,11 +218,6 @@
|
||||
<!-- Clean Video Conference Mute registry keys that might be around from previous installations. We've deprecated this utility since then. -->
|
||||
<Custom Action="CleanVideoConferenceRegistry" Before="InstallFinalize">NOT Installed</Custom>
|
||||
|
||||
<!-- User may have disabled the built-in New context menu via New+ -->
|
||||
<Custom Action="RestoreBuiltInNewContextMenu" Before="RemoveFiles">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<CustomAction Id="SetLaunchPowerToysParam"
|
||||
@@ -442,6 +449,35 @@
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="UnRegisterContextMenuPackagesCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="CleanImageResizerRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanImageResizerRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanFileLocksmithRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanFileLocksmithRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanPowerRenameRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanPowerRenameRuntimeRegistryCA"
|
||||
/>
|
||||
<CustomAction Id="CleanNewPlusRuntimeRegistry"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="CleanNewPlusRuntimeRegistryCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="UnRegisterCmdPalPackage"
|
||||
@@ -467,14 +503,6 @@
|
||||
DllEntry="InstallCmdPalPackageCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="RestoreBuiltInNewContextMenu"
|
||||
Return="ignore"
|
||||
Impersonate="yes"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="RestoreBuiltInNewContextMenuCA"
|
||||
/>
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
|
||||
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
|
||||
|
||||
@@ -1153,58 +1153,35 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall RestoreBuiltInNewContextMenuCA(MSIHANDLE hInstall)
|
||||
UINT __stdcall CleanImageResizerRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
// Must be run as administrator to open and modify the registry.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
|
||||
hr = WcaInitialize(hInstall, "RestoreBuiltInNewContextMenuCA");
|
||||
hr = WcaInitialize(hInstall, "CleanImageResizerRuntimeRegistryCA");
|
||||
|
||||
try
|
||||
{
|
||||
const std::wstring builtInNewRegistryPath = LR"(Directory\Background\shellex\ContextMenuHandlers\New)";
|
||||
const std::wstring newDisabledValuePrefix = L"0_";
|
||||
const wchar_t* CLSID_STR = L"{51B4D7E5-7568-4234-B4BB-47FB3C016A69}";
|
||||
const wchar_t* exts[] = { L".bmp", L".dib", L".gif", L".jfif", L".jpe", L".jpeg", L".jpg", L".jxr", L".png", L".rle", L".tif", L".tiff", L".wdp" };
|
||||
|
||||
auto regDeleter = [](HKEY* regKeyHandle) { if (regKeyHandle && *regKeyHandle) RegCloseKey(*regKeyHandle); delete regKeyHandle; };
|
||||
std::unique_ptr<HKEY, decltype(regDeleter)> regKeyHandle(new HKEY(nullptr), regDeleter);
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring &path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
|
||||
const LONG openStatus = RegOpenKeyExW(HKEY_CLASSES_ROOT, builtInNewRegistryPath.c_str(), 0, KEY_READ | KEY_WRITE, regKeyHandle.get());
|
||||
if (openStatus != ERROR_SUCCESS)
|
||||
// InprocServer32 chain root CLSID
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
// DragDrop handler
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\ShellEx\\DragDropHandlers\\ImageResizer");
|
||||
// Extensions
|
||||
for (auto ext : exts)
|
||||
{
|
||||
throw std::runtime_error("Failed to open New context menu registry key.");
|
||||
}
|
||||
|
||||
wchar_t buffer[256];
|
||||
DWORD bufferSize = sizeof(buffer);
|
||||
const LONG queryStatus = RegQueryValueExW(*regKeyHandle, nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer), &bufferSize);
|
||||
if (queryStatus != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to read New context menu registry key.");
|
||||
}
|
||||
|
||||
const std::wstring builtInNewHandlerValue(buffer);
|
||||
const bool startsWithPrefix = builtInNewHandlerValue.find(newDisabledValuePrefix) == 0;
|
||||
|
||||
if (!startsWithPrefix)
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
const std::wstring builtInNewEnabledValue = builtInNewHandlerValue.substr(newDisabledValuePrefix.length());
|
||||
const LONG setStatus = RegSetValueExW(*regKeyHandle, nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(builtInNewEnabledValue.c_str()), static_cast<DWORD>((builtInNewEnabledValue.length() + 1)) * sizeof(wchar_t));
|
||||
if (setStatus != ERROR_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("Failed to update/restore the New context menu shell extension in the registry.");
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\SystemFileAssociations\\" + std::wstring(ext) + L"\\ShellEx\\ContextMenuHandlers\\ImageResizer");
|
||||
}
|
||||
// Sentinel
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\ImageResizer");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
catch (...)
|
||||
{
|
||||
std::string errorMessage{ "Exception thrown while trying to restore built-in New: " };
|
||||
errorMessage += e.what();
|
||||
Logger::error(errorMessage);
|
||||
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
|
||||
@@ -1212,6 +1189,77 @@ UINT __stdcall RestoreBuiltInNewContextMenuCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanFileLocksmithRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanFileLocksmithRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{84D68575-E186-46AD-B0CB-BAEB45EE29C0}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt");
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Drive\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\FileLocksmith");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanPowerRenameRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanPowerRenameRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{0440049F-D1DC-4E46-B27B-98393D79486B}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt");
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\PowerRenameExt");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\PowerRename");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CleanNewPlusRuntimeRegistryCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "CleanNewPlusRuntimeRegistryCA");
|
||||
try
|
||||
{
|
||||
const wchar_t* CLSID_STR = L"{FF90D477-E32A-4BE8-8CC5-A502A97F5401}";
|
||||
auto deleteKeyRecursive = [](HKEY root, const std::wstring& path) {
|
||||
RegDeleteTreeW(root, path.c_str());
|
||||
};
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" + std::wstring(CLSID_STR));
|
||||
deleteKeyRecursive(HKEY_CURRENT_USER, L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\NewPlusShellExtensionWin10");
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Microsoft\\PowerToys\\NewPlus");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er = ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
er = er == ERROR_SUCCESS ? (SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE) : er;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
@@ -28,4 +28,7 @@ EXPORTS
|
||||
UninstallCommandNotFoundModuleCA
|
||||
UpgradeCommandNotFoundModuleCA
|
||||
UnsetAdvancedPasteAPIKeyCA
|
||||
RestoreBuiltInNewContextMenuCA
|
||||
CleanImageResizerRuntimeRegistryCA
|
||||
CleanFileLocksmithRuntimeRegistryCA
|
||||
CleanPowerRenameRuntimeRegistryCA
|
||||
CleanNewPlusRuntimeRegistryCA
|
||||
|
||||
266
src/common/utils/shell_ext_registration.h
Normal file
266
src/common/utils/shell_ext_registration.h
Normal file
@@ -0,0 +1,266 @@
|
||||
// Shared runtime shell extension registration utility for PowerToys modules.
|
||||
// Provides a generic EnsureRegistered function so individual modules only need
|
||||
// to supply a specification (CLSID, sentinel, handler key paths, etc.).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "../logger/logger.h"
|
||||
|
||||
namespace runtime_shell_ext
|
||||
{
|
||||
struct Spec
|
||||
{
|
||||
// Mandatory
|
||||
std::wstring clsid; // e.g. {GUID}
|
||||
std::wstring sentinelKey; // e.g. Software\\Microsoft\\PowerToys\\ModuleName
|
||||
std::wstring sentinelValue; // e.g. ContextMenuRegistered
|
||||
std::vector<std::wstring> dllFileCandidates; // relative filenames (pick first existing)
|
||||
std::vector<std::wstring> contextMenuHandlerKeyPaths; // full HKCU relative paths where default value = CLSID
|
||||
|
||||
// Optional
|
||||
std::wstring friendlyName; // if non-empty written as default under CLSID root
|
||||
bool writeOptInEmptyValue = true; // write ContextMenuOptIn="" under CLSID root (legacy pattern)
|
||||
bool writeThreadingModel = true; // write Apartment threading model
|
||||
std::vector<std::wstring> extraAssociationPaths; // additional key paths (DragDropHandlers etc.) default=CLSID
|
||||
std::vector<std::wstring> systemFileAssocExtensions; // e.g. .png -> Software\\Classes\\SystemFileAssociations\\.png\\ShellEx\\ContextMenuHandlers\\<HandlerName>
|
||||
std::wstring systemFileAssocHandlerName; // e.g. ImageResizer
|
||||
std::wstring representativeSystemExt; // used to decide if associations need repair (.png)
|
||||
bool logRepairs = true;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Minimal RAII wrapper for HKEY
|
||||
struct unique_hkey
|
||||
{
|
||||
HKEY h{ nullptr };
|
||||
unique_hkey() = default;
|
||||
explicit unique_hkey(HKEY handle) : h(handle) {}
|
||||
~unique_hkey() { if (h) RegCloseKey(h); }
|
||||
unique_hkey(const unique_hkey&) = delete;
|
||||
unique_hkey& operator=(const unique_hkey&) = delete;
|
||||
unique_hkey(unique_hkey&& other) noexcept : h(other.h) { other.h = nullptr; }
|
||||
unique_hkey& operator=(unique_hkey&& other) noexcept { if (this != &other) { if (h) RegCloseKey(h); h = other.h; other.h = nullptr; } return *this; }
|
||||
HKEY get() const { return h; }
|
||||
HKEY* put() { if (h) { RegCloseKey(h); h = nullptr; } return &h; }
|
||||
};
|
||||
inline std::wstring base_dir_from_module(HMODULE h)
|
||||
{
|
||||
wchar_t buf[MAX_PATH];
|
||||
if (GetModuleFileNameW(h, buf, MAX_PATH))
|
||||
{
|
||||
PathRemoveFileSpecW(buf);
|
||||
return buf;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline std::wstring pick_existing_dll(const std::wstring& base, const std::vector<std::wstring>& candidates)
|
||||
{
|
||||
for (const auto& rel : candidates)
|
||||
{
|
||||
std::wstring full = base + L"\\" + rel;
|
||||
if (GetFileAttributesW(full.c_str()) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return full;
|
||||
}
|
||||
}
|
||||
if (!candidates.empty())
|
||||
{
|
||||
return base + L"\\" + candidates.front();
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline bool sentinel_exists(const Spec& spec)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, KEY_READ, key.put()) != ERROR_SUCCESS)
|
||||
return false;
|
||||
DWORD v = 0; DWORD sz = sizeof(v);
|
||||
return RegQueryValueExW(key.get(), spec.sentinelValue.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&v), &sz) == ERROR_SUCCESS && v == 1;
|
||||
}
|
||||
|
||||
inline void write_sentinel(const Spec& spec)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD one = 1;
|
||||
RegSetValueExW(key.get(), spec.sentinelValue.c_str(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&one), sizeof(one));
|
||||
}
|
||||
}
|
||||
|
||||
inline void write_inproc_server(const Spec& spec, const std::wstring& dllPath)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
std::wstring clsidRoot = L"Software\\Classes\\CLSID\\"s + spec.clsid;
|
||||
std::wstring inprocKey = clsidRoot + L"\\InprocServer32";
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, clsidRoot.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
if (!spec.friendlyName.empty())
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(spec.friendlyName.c_str()), static_cast<DWORD>((spec.friendlyName.size() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
if (spec.writeOptInEmptyValue)
|
||||
{
|
||||
const wchar_t* optIn = L"ContextMenuOptIn";
|
||||
const wchar_t empty = L'\0';
|
||||
RegSetValueExW(key.get(), optIn, 0, REG_SZ, reinterpret_cast<const BYTE*>(&empty), sizeof(empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, inprocKey.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(dllPath.c_str()), static_cast<DWORD>((dllPath.size() + 1) * sizeof(wchar_t)));
|
||||
if (spec.writeThreadingModel)
|
||||
{
|
||||
const wchar_t* tm = L"Apartment";
|
||||
RegSetValueExW(key.get(), L"ThreadingModel", 0, REG_SZ, reinterpret_cast<const BYTE*>(tm), static_cast<DWORD>((wcslen(tm) + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::wstring read_inproc_server(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
std::wstring inprocKey = L"Software\\Classes\\CLSID\\"s + spec.clsid + L"\\InprocServer32";
|
||||
unique_hkey key;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, inprocKey.c_str(), 0, KEY_READ, key.put()) != ERROR_SUCCESS)
|
||||
return L"";
|
||||
wchar_t buf[MAX_PATH]; DWORD sz = sizeof(buf);
|
||||
if (RegQueryValueExW(key.get(), nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(buf), &sz) == ERROR_SUCCESS)
|
||||
return std::wstring(buf);
|
||||
return L"";
|
||||
}
|
||||
|
||||
inline void write_default_value_key(const std::wstring& keyPath, const std::wstring& value)
|
||||
{
|
||||
unique_hkey key;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, keyPath.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, key.put(), nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(key.get(), nullptr, 0, REG_SZ, reinterpret_cast<const BYTE*>(value.c_str()), static_cast<DWORD>((value.size() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool representative_association_exists(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
if (spec.representativeSystemExt.empty() || spec.systemFileAssocHandlerName.empty())
|
||||
return true;
|
||||
std::wstring keyPath = L"Software\\Classes\\SystemFileAssociations\\"s + spec.representativeSystemExt + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
unique_hkey key;
|
||||
return RegOpenKeyExW(HKEY_CURRENT_USER, keyPath.c_str(), 0, KEY_READ, key.put()) == ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered(const Spec& spec, HMODULE moduleInstance)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
auto base = detail::base_dir_from_module(moduleInstance);
|
||||
auto dllPath = detail::pick_existing_dll(base, spec.dllFileCandidates);
|
||||
if (dllPath.empty())
|
||||
{
|
||||
Logger::error(L"Runtime registration: cannot locate dll path for CLSID {}", spec.clsid);
|
||||
return false;
|
||||
}
|
||||
bool exists = detail::sentinel_exists(spec);
|
||||
bool repaired = false;
|
||||
if (exists)
|
||||
{
|
||||
auto current = detail::read_inproc_server(spec);
|
||||
if (_wcsicmp(current.c_str(), dllPath.c_str()) != 0)
|
||||
{
|
||||
detail::write_inproc_server(spec, dllPath);
|
||||
repaired = true;
|
||||
}
|
||||
if (!detail::representative_association_exists(spec))
|
||||
{
|
||||
repaired = true;
|
||||
}
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
detail::write_inproc_server(spec, dllPath);
|
||||
}
|
||||
if (!exists || repaired)
|
||||
{
|
||||
for (const auto& path : spec.contextMenuHandlerKeyPaths)
|
||||
{
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
for (const auto& path : spec.extraAssociationPaths)
|
||||
{
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
if (!spec.systemFileAssocExtensions.empty() && !spec.systemFileAssocHandlerName.empty())
|
||||
{
|
||||
for (const auto& ext : spec.systemFileAssocExtensions)
|
||||
{
|
||||
std::wstring path = L"Software\\Classes\\SystemFileAssociations\\"s + ext + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
detail::write_default_value_key(path, spec.clsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
detail::write_sentinel(spec);
|
||||
Logger::info(L"Runtime registration completed for CLSID {}", spec.clsid);
|
||||
}
|
||||
else if (repaired && spec.logRepairs)
|
||||
{
|
||||
Logger::info(L"Runtime registration repaired for CLSID {}", spec.clsid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Unregister(const Spec& spec)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
// Remove handler key paths
|
||||
for (const auto& path : spec.contextMenuHandlerKeyPaths)
|
||||
{
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, path.c_str());
|
||||
}
|
||||
// Remove extra association paths (e.g., drag & drop handlers)
|
||||
for (const auto& path : spec.extraAssociationPaths)
|
||||
{
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, path.c_str());
|
||||
}
|
||||
// Remove per-extension system file association handler keys
|
||||
if (!spec.systemFileAssocExtensions.empty() && !spec.systemFileAssocHandlerName.empty())
|
||||
{
|
||||
for (const auto& ext : spec.systemFileAssocExtensions)
|
||||
{
|
||||
std::wstring keyPath = L"Software\\Classes\\SystemFileAssociations\\"s + ext + L"\\ShellEx\\ContextMenuHandlers\\" + spec.systemFileAssocHandlerName;
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, keyPath.c_str());
|
||||
}
|
||||
}
|
||||
// Remove CLSID branch
|
||||
if (!spec.clsid.empty())
|
||||
{
|
||||
std::wstring clsidRoot = L"Software\\Classes\\CLSID\\"s + spec.clsid;
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, clsidRoot.c_str());
|
||||
}
|
||||
// Remove sentinel value (not deleting entire key to avoid disturbing other values)
|
||||
if (!spec.sentinelKey.empty() && !spec.sentinelValue.empty())
|
||||
{
|
||||
HKEY hKey{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, spec.sentinelKey.c_str(), 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegDeleteValueW(hKey, spec.sentinelValue.c_str());
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
Logger::info(L"Successfully unregistered CLSID {}", spec.clsid);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,7 @@
|
||||
<ClInclude Include="ClassFactory.h" />
|
||||
<ClInclude Include="dllmain.h" />
|
||||
<ClInclude Include="ExplorerCommand.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="resource.base.h" />
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
<ClInclude Include="dllmain.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "FileLocksmithLib/Constants.h"
|
||||
#include "FileLocksmithLib/Settings.h"
|
||||
#include "FileLocksmithLib/Trace.h"
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
#include "dllmain.h"
|
||||
#include "Generated Files/resource.h"
|
||||
@@ -82,12 +83,17 @@ public:
|
||||
{
|
||||
std::wstring path = get_module_folderpath(globals::instance);
|
||||
std::wstring packageUri = path + L"\\FileLocksmithContextMenuPackage.msix";
|
||||
|
||||
if (!package::IsPackageRegisteredWithPowerToysVersion(constants::nonlocalizable::ContextMenuPackageName))
|
||||
{
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
}
|
||||
|
||||
m_enabled = true;
|
||||
}
|
||||
@@ -95,6 +101,13 @@ public:
|
||||
virtual void disable() override
|
||||
{
|
||||
Logger::info(L"File Locksmith disabled");
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::Unregister();
|
||||
Logger::info(L"File Locksmith context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Header-only runtime registration for FileLocksmith context menu extension.
|
||||
#pragma once
|
||||
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
namespace globals { extern HMODULE instance; }
|
||||
|
||||
namespace FileLocksmithRuntimeRegistration
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{84D68575-E186-46AD-B0CB-BAEB45EE29C0}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\FileLocksmith";
|
||||
spec.sentinelValue = L"ContextMenuRegistered";
|
||||
spec.dllFileCandidates = { L"PowerToys.FileLocksmithExt.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = {
|
||||
L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt",
|
||||
L"Software\\Classes\\Drive\\ShellEx\\ContextMenuHandlers\\FileLocksmithExt" };
|
||||
spec.friendlyName = L"File Locksmith Shell Extension";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), globals::instance);
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
||||
<ClInclude Include="settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="new_utilities.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="resource.base.h" />
|
||||
<ClInclude Include="template_folder.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<ClInclude Include="helpers_variables.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Header-only runtime registration for New+ Win10 context menu.
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
// Provided by dll_main.cpp
|
||||
extern HMODULE module_instance_handle;
|
||||
|
||||
namespace NewPlusRuntimeRegistration
|
||||
{
|
||||
namespace {
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{FF90D477-E32A-4BE8-8CC5-A502A97F5401}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\NewPlus";
|
||||
spec.sentinelValue = L"ContextMenuRegisteredWin10";
|
||||
spec.dllFileCandidates = { L"PowerToys.NewPlus.ShellExtension.win10.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = { L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\NewPlusShellExtensionWin10" };
|
||||
spec.friendlyName = L"NewPlus Shell Extension Win10";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegisteredWin10()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), module_instance_handle);
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "trace.h"
|
||||
#include "new_utilities.h"
|
||||
#include "Generated Files/resource.h"
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
// Note: Settings are managed via Settings and UI Settings
|
||||
class NewModule : public PowertoyModuleIface
|
||||
@@ -93,8 +94,16 @@ public:
|
||||
|
||||
// Log telemetry
|
||||
Trace::EventToggleOnOff(true);
|
||||
|
||||
newplus::utilities::register_msix_package();
|
||||
if (package::IsWin11OrGreater())
|
||||
{
|
||||
newplus::utilities::register_msix_package();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::EnsureRegisteredWin10();
|
||||
#endif
|
||||
}
|
||||
|
||||
powertoy_new_enabled = true;
|
||||
}
|
||||
@@ -141,6 +150,13 @@ private:
|
||||
{
|
||||
Trace::EventToggleOnOff(false);
|
||||
}
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::Unregister();
|
||||
Logger::info(L"New+ context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
powertoy_new_enabled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,29 +170,20 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
// TODO: just added a lock around all of this anyway, but keeping the clone
|
||||
// while looking on some other ways to improve this; can be removed later.
|
||||
List<TopLevelViewModel> clone = [.. TopLevelCommands];
|
||||
var startIndex = -1;
|
||||
|
||||
var startIndex = FindIndexForFirstProviderItem(clone, sender.ProviderId);
|
||||
clone.RemoveAll(item => item.CommandProviderId == sender.ProviderId);
|
||||
clone.InsertRange(startIndex, newItems);
|
||||
|
||||
ListHelpers.InPlaceUpdateList(TopLevelCommands, clone);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
static int FindIndexForFirstProviderItem(List<TopLevelViewModel> topLevelItems, string providerId)
|
||||
{
|
||||
// Tricky: all Commands from a single provider get added to the
|
||||
// top-level list all together, in a row. So if we find just the first
|
||||
// one, we can slice it out and insert the new ones there.
|
||||
for (var i = 0; i < topLevelItems.Count; i++)
|
||||
for (var i = 0; i < clone.Count; i++)
|
||||
{
|
||||
var wrapper = topLevelItems[i];
|
||||
var wrapper = clone[i];
|
||||
try
|
||||
{
|
||||
if (providerId == wrapper.CommandProviderId)
|
||||
if (sender.ProviderId == wrapper.CommandProviderId)
|
||||
{
|
||||
return i;
|
||||
startIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -200,8 +191,9 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find any, then we just append the new commands to the end of the list.
|
||||
return topLevelItems.Count;
|
||||
clone.RemoveAll(item => item.CommandProviderId == sender.ProviderId);
|
||||
clone.InsertRange(startIndex, newItems);
|
||||
ListHelpers.InPlaceUpdateList(TopLevelCommands, clone);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -36,17 +35,6 @@ public partial class ContentIcon : FontIcon
|
||||
{
|
||||
if (this.FindDescendants().OfType<Grid>().FirstOrDefault() is Grid grid && Content is not null)
|
||||
{
|
||||
if (grid.Children.Contains(Content))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Content is FrameworkElement element && element.Parent is not null)
|
||||
{
|
||||
Debug.Assert(false, $"IconBoxElement Content is already parented to {element.Parent.GetType().Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
grid.Children.Add(Content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
<Rectangle
|
||||
Height="1"
|
||||
Margin="-16,-12,-12,-12"
|
||||
Fill="{ThemeResource MenuFlyoutSeparatorBackground}" />
|
||||
Fill="{ThemeResource MenuFlyoutSeparatorThemeBrush}" />
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="Generated Files/resource.h" />
|
||||
<ClInclude Include="ImageResizerExt_i.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
<ClInclude Include="Generated Files/resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ImageResizerExt.rgs">
|
||||
|
||||
38
src/modules/imageresizer/dll/RuntimeRegistration.h
Normal file
38
src/modules/imageresizer/dll/RuntimeRegistration.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Header-only runtime registration for ImageResizer shell extension.
|
||||
#pragma once
|
||||
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase; // provided by linker
|
||||
|
||||
namespace ImageResizerRuntimeRegistration
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{51B4D7E5-7568-4234-B4BB-47FB3C016A69}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\ImageResizer";
|
||||
spec.sentinelValue = L"ContextMenuRegistered";
|
||||
spec.dllFileCandidates = { L"PowerToys.ImageResizerExt.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = { };
|
||||
spec.systemFileAssocHandlerName = L"ImageResizer";
|
||||
spec.systemFileAssocExtensions = { L".bmp", L".dib", L".gif", L".jfif", L".jpe", L".jpeg", L".jpg", L".jxr", L".png", L".rle", L".tif", L".tiff", L".wdp" };
|
||||
spec.representativeSystemExt = L".png"; // probe for repair
|
||||
spec.extraAssociationPaths = { L"Software\\Classes\\Directory\\ShellEx\\DragDropHandlers\\ImageResizer" };
|
||||
spec.friendlyName = L"ImageResizer Shell Extension";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
CImageResizerExtModule _AtlModule;
|
||||
HINSTANCE g_hInst_imageResizer = 0;
|
||||
@@ -106,12 +107,17 @@ public:
|
||||
{
|
||||
std::wstring path = get_module_folderpath(g_hInst_imageResizer);
|
||||
std::wstring packageUri = path + L"\\ImageResizerContextMenuPackage.msix";
|
||||
|
||||
if (!package::IsPackageRegisteredWithPowerToysVersion(ImageResizerConstants::ModulePackageDisplayName))
|
||||
{
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
}
|
||||
|
||||
Trace::EnableImageResizer(m_enabled);
|
||||
}
|
||||
@@ -121,6 +127,13 @@ public:
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableImageResizer(m_enabled);
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::Unregister();
|
||||
Logger::info(L"ImageResizer context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<ClInclude Include="Generated Files/resource.h" />
|
||||
<ClInclude Include="PowerRenameConstants.h" />
|
||||
<ClInclude Include="PowerRenameExt.h" />
|
||||
<ClInclude Include="RuntimeRegistration.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<ClInclude Include="PowerRenameConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RuntimeRegistration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PowerRenameExt.cpp">
|
||||
|
||||
37
src/modules/powerrename/dll/RuntimeRegistration.h
Normal file
37
src/modules/powerrename/dll/RuntimeRegistration.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Header-only runtime registration for PowerRename context menu extension.
|
||||
#pragma once
|
||||
|
||||
#include <common/utils/shell_ext_registration.h>
|
||||
|
||||
// Provided by dllmain.cpp
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
namespace PowerRenameRuntimeRegistration
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline runtime_shell_ext::Spec BuildSpec()
|
||||
{
|
||||
runtime_shell_ext::Spec spec;
|
||||
spec.clsid = L"{0440049F-D1DC-4E46-B27B-98393D79486B}";
|
||||
spec.sentinelKey = L"Software\\Microsoft\\PowerToys\\PowerRename";
|
||||
spec.sentinelValue = L"ContextMenuRegistered";
|
||||
spec.dllFileCandidates = { L"PowerToys.PowerRenameExt.dll" };
|
||||
spec.contextMenuHandlerKeyPaths = {
|
||||
L"Software\\Classes\\AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt",
|
||||
L"Software\\Classes\\Directory\\background\\ShellEx\\ContextMenuHandlers\\PowerRenameExt" };
|
||||
spec.friendlyName = L"PowerRename Shell Extension";
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EnsureRegistered()
|
||||
{
|
||||
return runtime_shell_ext::EnsureRegistered(BuildSpec(), g_hInst);
|
||||
}
|
||||
|
||||
inline void Unregister()
|
||||
{
|
||||
runtime_shell_ext::Unregister(BuildSpec());
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <common/utils/package.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include "RuntimeRegistration.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -196,12 +197,17 @@ public:
|
||||
{
|
||||
std::wstring path = get_module_folderpath(g_hInst);
|
||||
std::wstring packageUri = path + L"\\PowerRenameContextMenuPackage.msix";
|
||||
|
||||
if (!package::IsPackageRegisteredWithPowerToysVersion(PowerRenameConstants::ModulePackageDisplayName))
|
||||
{
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
@@ -209,6 +215,13 @@ public:
|
||||
{
|
||||
m_enabled = false;
|
||||
Logger::info(L"PowerRename disabled");
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::Unregister();
|
||||
Logger::info(L"PowerRename context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the powertoy is enabled
|
||||
|
||||
@@ -84,15 +84,6 @@
|
||||
<TextBlock x:Uid="NewPlus_Hide_Starting_Digits_Description" />
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_BuiltIn_New_Toggle" IsEnabled="{x:Bind ViewModel.IsDisableBuiltInNewSettingsCardEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="DisableBuiltInNewToggle" IsOn="{x:Bind ViewModel.HideBuiltInNew, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="Elevation_Required"
|
||||
IsClosable="True"
|
||||
IsOpen="{x:Bind ViewModel.IsEnabledAndNotElevated, Mode=OneWay}"
|
||||
Severity="Informational" />
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_behavior" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
@@ -4434,10 +4434,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Ignores digits, spaces, and dots at the start of filenames—useful for sorting templates without showing those characters</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_BuiltIn_New_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide the built-in New context menu</value>
|
||||
<comment>Localize New in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_behavior.Header" xml:space="preserve">
|
||||
<value>Behavior</value>
|
||||
<comment>New+ behavior related settings label</comment>
|
||||
@@ -5131,7 +5127,4 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="KeyBack" xml:space="preserve">
|
||||
<value>Back key</value>
|
||||
</data>
|
||||
<data name="Elevation_Required.Title" xml:space="preserve">
|
||||
<value>To change this setting you'll need to run PowerToys as administrator. You can restart PowerToys as administrator on the General page.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security.Principal;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -18,7 +17,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||
using Microsoft.PowerToys.Settings.UI.SerializationContext;
|
||||
using Microsoft.Win32;
|
||||
|
||||
using static Microsoft.PowerToys.Settings.UI.Helpers.ShellGetFolder;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
@@ -32,9 +31,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private NewPlusSettings Settings { get; set; }
|
||||
|
||||
private const string ModuleName = NewPlusSettings.ModuleName;
|
||||
private const string BuiltInNewRegistryPath = @"HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\New";
|
||||
private const string NewDisabledValuePrefix = "0_";
|
||||
private const string BuiltNewCOMGuid = "{D969A300-E7FF-11d0-A93B-00A0C90F2719}";
|
||||
|
||||
public NewPlusViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
@@ -55,8 +51,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
InitializeEnabledValue();
|
||||
InitializeGpoValues();
|
||||
|
||||
_disableBuiltInNew = !IsBuiltInNewEnabled();
|
||||
|
||||
// set the callback functions value to handle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
@@ -102,8 +96,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
OnPropertyChanged(nameof(IsHideFileExtSettingGPOConfigured));
|
||||
OnPropertyChanged(nameof(IsReplaceVariablesSettingGPOConfigured));
|
||||
OnPropertyChanged(nameof(IsReplaceVariablesSettingsCardEnabled));
|
||||
OnPropertyChanged(nameof(IsDisableBuiltInNewSettingsCardEnabled));
|
||||
OnPropertyChanged(nameof(IsEnabledAndNotElevated));
|
||||
|
||||
OutGoingGeneralSettings outgoingMessage = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoingMessage.ToString());
|
||||
@@ -118,13 +110,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsElevated()
|
||||
{
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
|
||||
public bool IsWin10OrLower
|
||||
{
|
||||
get => !OSVersionHelper.IsWindows11();
|
||||
@@ -179,8 +164,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
public bool IsReplaceVariablesSettingGPOConfigured => _isNewPlusEnabled && _replaceVariablesIsGPOConfigured;
|
||||
|
||||
public bool IsDisableBuiltInNewSettingsCardEnabled => _isNewPlusEnabled && IsElevated();
|
||||
|
||||
public bool HideStartingDigits
|
||||
{
|
||||
get => _hideStartingDigits;
|
||||
@@ -223,44 +206,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool HideBuiltInNew
|
||||
{
|
||||
get
|
||||
{
|
||||
return _disableBuiltInNew;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_disableBuiltInNew != value)
|
||||
{
|
||||
if (_disableBuiltInNew)
|
||||
{
|
||||
EnableBuiltInNew();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableBuiltInNew();
|
||||
}
|
||||
|
||||
_disableBuiltInNew = value;
|
||||
OnPropertyChanged(nameof(HideBuiltInNew));
|
||||
|
||||
NotifySettingsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabledGpoConfigured
|
||||
{
|
||||
get => _enabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public bool IsEnabledAndNotElevated
|
||||
{
|
||||
get => _isNewPlusEnabled && !IsElevated();
|
||||
}
|
||||
|
||||
public ButtonClickCommand OpenCurrentNewTemplateFolder => new ButtonClickCommand(OpenNewTemplateFolder);
|
||||
|
||||
public ButtonClickCommand PickAnotherNewTemplateFolder => new ButtonClickCommand(PickNewTemplateFolder);
|
||||
@@ -321,7 +271,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private bool _hideFileExtension;
|
||||
private bool _hideStartingDigits;
|
||||
private bool _replaceVariables;
|
||||
private bool _disableBuiltInNew;
|
||||
|
||||
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
||||
private bool _enabledStateIsGPOConfigured;
|
||||
@@ -368,69 +317,5 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.GetSettingsWindow());
|
||||
return await Task.FromResult(GetFolderDialogWithFlags(hwnd, FolderDialogFlags._BIF_NEWDIALOGSTYLE));
|
||||
}
|
||||
|
||||
private bool IsBuiltInNewEnabled()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
return IsValidRegistryCOMFormatGuid(builtInNewHandlerValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to determine built-in New enablement status.", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsValidRegistryCOMFormatGuid(string input)
|
||||
{
|
||||
return Guid.TryParseExact(input, "B", out _);
|
||||
}
|
||||
|
||||
private void DisableBuiltInNew()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
if (builtInNewHandlerValue.StartsWith(NewDisabledValuePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Already disabled
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(builtInNewHandlerValue == BuiltNewCOMGuid, "Unexpected GUID encountered while disabling built-in New");
|
||||
string newDisabledValue = NewDisabledValuePrefix + builtInNewHandlerValue;
|
||||
Registry.SetValue(BuiltInNewRegistryPath, string.Empty, newDisabledValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to disable built-in New in the registry.", ex);
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableBuiltInNew()
|
||||
{
|
||||
try
|
||||
{
|
||||
string builtInNewHandlerValue = Registry.GetValue(BuiltInNewRegistryPath, string.Empty, null) as string;
|
||||
|
||||
if (builtInNewHandlerValue.StartsWith(NewDisabledValuePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string newEnabledValue = builtInNewHandlerValue.Substring(NewDisabledValuePrefix.Length);
|
||||
Debug.Assert(newEnabledValue == BuiltNewCOMGuid, "Unexpected GUID encountered while reenabling built-in New");
|
||||
Registry.SetValue(BuiltInNewRegistryPath, string.Empty, newEnabledValue);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to enable built-in New in the registry.", ex);
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user