Registry Preview: complete feature with integration with Settings and the Launcher UX (#23709)
* Initial src for Registry Preview Initial collection of files * Update MainWindow.Utilities.cs fixing a few spelling items * Update expect.txt * Update App.xaml.cs * Update MainWindow.Events.cs * Update MainWindow.Utilities.cs * Update MainWindow.xaml.cs * Update expect.txt * Update MainWindow.Events.cs * Rename AddPreviewtoRegfile.reg to AddPreviewToRegfile.reg * Rename RemovePreviewtoRegfile.reg to RemovePreviewToRegfile.reg * Update Resources.resw * Update MainWindow.xaml * Turns on self-contained mode Updates the csproj file to compile the app as self-contained . Includes fixes for code that expected the app to be in an ApplicationContainer. Updates WindowsAppSDK from 1.1.5 to 1.2.230118.102. * Updated to align with StyleCop errors Multiple changes across the codebase that now aligns with StyleCop guidelines. Tested again after the changes, to make sure no new bugs crept in. * Added comments for spell-checker Unclear if this side step should be done or not, but the kxz comes from a GUID and the other three names are constants. * Adding code-custom.dic Comments didn't work; trying a dic file * Added four new terms to expects.txt file Cleaning up attempt to update the spell-checker with dic file and moved it to expects.txt file * Adding one more string Adding one more string for Spell-Check * Adding back egfile Seems this is needed. * Correcting a variable name Seems one of the variable names that changed globally got missed in a XAML file. * Update project to be more PowerToys friendly Tweaking names and output file name to fit better with PowerToys. * First pass at integration into Settings and Launcher This PR is not as large as it seems: - RegistryPreview's source moved around to a "better" directory that makes it look like the whole app changed. It didn't. In fact, I opened it in Beyond Compare and there's not much difference in the RegistryPreview app. - Added RegistryPreviewExt that produces a DLL that the Launcher can run the EXE - Changes to Runner calls the Ext DLL rather than the app - Settings UI got a bunch of changes to enable the Settings page for enable/disable across ViewModels, Views, and string tables. Still todo: - Add "Preview" to .REG files, when the app is enable (and remove it when disabled) - Update the thumbnail-screenshot in the Settings page - Add support for OOBE * Update expect.txt Added REGISTRYPREVIEWEXT for recent changes and corrected an alphabetic sorting error. * Updating project file for Release mode Build failed due to a bad Includes path in Release mode. * Adds REG registration but breaks settings This update will update the HKCU branch of the Registry for REG files: if the app in PowerToys is enabled, it adds a Preview item to the context menu of REG files and disabling in PowerToys removes the menu item. While working on this, I noticed that the application settings were broken, after moving to a self-contained EXE: there must have been old settings from past builds, when it was still using containers and family names. Added TODO's to add a new way to save settings, likely as JSON. * Re-enabled app settings Moved from using ApplicationDataContainer for app settings and now use simple JSON. Also cleaned up handling the scenario where the Launcher send in the PID from PowerToys' main thread. Fixed past spelling errors as well. * Update RegistryPreview.png Captured new screenshot. * Integration into OOBE Integrates new page for Registry Preview into OOBE process. * Removing old comment and unneeded calls Two bits of source removed as they aren't needed any longer Removing a chunk of old commented out code that doesn't make sense anymore. * Merging file from upstream Updating some files due to three merge conflicts from upstream changes and a couple of other changes to keep up. * Update .gitignore Adding two vcxproj files that have local updates for atls.lib locations. * Update Resources.resw Fixing a typo that involved a missing closing tag. * Fix analyzer warnings * Fix CI build * Fix ARM64 build Project file cleanup * Add to installer * expect.txt * Remove unneeded dll * Update MainWindow.xaml.cs Added check for current Theme and adjust TextBox Foreground accordingly. * Update expect.txt Cleaning up merge cruft. * Revert wrong .gitignore changes * Fix ARM installer * Update Brushes for textBox to use Theme based versions Finally figured out how to use the built-in, Theme-aware Brushes for the font colors in the onscreen textBox. Also have it aligning the font color for the hover state. * Align configuration in PowerToys.sln * [installer] Add missing files * Fix bad merge * Fixes for stefansjfw's review Includes: - two new strings for UX localization - adds compatibility section for Windows 10 - fix to only track successful activations - Removes two REG files that were there for examples * Fixes from review from htcfreek Updates: - Fixed an issue where TextBox_TextChanged was firing when you simply opened a file. - Added clamp to prevent files larger than 10MB from being opened. - Added support in the UX to show Keys and Values that are deleted via the file - Added support to specially handle Keys that start with - and Values that have =- in them (delete scenario) - Changed AppBarButton icon for Edit from Rename to NewWindow * Create deleted-folder32.png * Added Registry Preview to GPO * Update expect.txt Updating spellchecker works * Updating Size/Move code for better results - Moved the size/move to the MainWindow layer - Cleaned up the JSON settings handling to avoid an access denied on first run * Improving text handling Changed how special characters are parse, which helps with live entry. * Updates to parsing and other fixes - Renamed the value PNG for parity - Added new error image - Added check that values have " at start and finish. - Added support for a new "ERROR" type for Values - Fixed support for @ versus "@" in values - Fixed bug where Save wasn't activating in all scernarios * Fix signing and versioning * Update src/settings-ui/Settings.UI/ViewModels/RegistryPreviewViewModel.cs Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> * Apply suggestions from code review Adds Launch button to the settings page. Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> * Update Resources.resw Adding strings for new launch button * Adding new version for GPO Moving to 0.69.0 * More parsing bug fixes - Changes to look for [- instead of -[ for syntax deleting keys (fix for developer's mental hiccup) - Moved [- to top of the decision making stack, as it needs to come before [ - Added new StripEscapedCharacters function for both sides of a Value line - Fixed crashing bug for scenario where no Keys are parsed before a Value * Bug fixes from most recent review. - Dictionary will now be case insensitive when searching for keys - Added tool tips (and strings) to the images of the Keys and Values - Updated delete handling for Keys, so that only the leaf-most node gets marked as deleted; also stops the top most roots from being marked deleted. * Tweaking for @=- Forces the UX to take @=- and treat it as @="" since that's what Registry Editor would do. * Removing unused usings * Updates app description * Update src/gpo/assets/PowerToys.admx Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> * cleanup proj file launch process only if module is enabled add process to bugreport process list * Add context menu icon * Update src/modules/registrypreview/RegistryPreviewUI/MainWindow.Utilities.cs Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> * Use modulesRegistry.h to apply/unapply registry changes * Tweaked window settings Moved the loading of the settings a little later in the initialization code, which gives more time for things to initialize. * Update registry.h Moving the definition out of the detail namespace to the registry name space to fix a compilation issue in RegistryPreviewExt. * Unapply on creation If module is disabled in settings.json, on startup reg entries should be unnaplied. TODO: read m_enabled from settings file on creation * Removing size/move main window Added a TODO comment that responds to the size/position settings that are being saved out in the JSON blob on close as it doesn't always work on every PC, as the MainWindow initializes at different times. * Change to always keep Save As active No reason for this to be disabled, honestly. --------- Co-authored-by: Clint Rutkas <clint@rutkas.com> Co-authored-by: Stefan Markovic <stefan@janeasystems.com> Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
14
.github/actions/spell-check/expect.txt
vendored
@ -65,6 +65,7 @@ applicationframehost
|
||||
Applist
|
||||
applog
|
||||
appmanifest
|
||||
APPNAME
|
||||
appref
|
||||
apps
|
||||
appwindow
|
||||
@ -217,6 +218,7 @@ CLIPCHILDREN
|
||||
CLIPSIBLINGS
|
||||
Cloneable
|
||||
clrcall
|
||||
clrcompression
|
||||
Cls
|
||||
CLSCTX
|
||||
clsid
|
||||
@ -350,6 +352,7 @@ DCOM
|
||||
dcommon
|
||||
dcomp
|
||||
dcompi
|
||||
DCompiler
|
||||
DComposition
|
||||
DCR
|
||||
DCs
|
||||
@ -373,6 +376,7 @@ DEFERERASE
|
||||
DEFPUSHBUTTON
|
||||
deinitialization
|
||||
DELA
|
||||
DELETEDKEYIMAGE
|
||||
DELETESCANS
|
||||
deletethis
|
||||
Delimarsky
|
||||
@ -469,6 +473,7 @@ editkeyboardwindow
|
||||
EDITSHORTCUTS
|
||||
editshortcutswindow
|
||||
EFile
|
||||
egfile
|
||||
ekus
|
||||
emmintrin
|
||||
Emoji
|
||||
@ -508,6 +513,7 @@ EWXREBOOT
|
||||
EWXSHUTDOWN
|
||||
examplehandler
|
||||
examplepowertoy
|
||||
EXAND
|
||||
EXCLUDEFROMCAPTURE
|
||||
exdisp
|
||||
executionpolicy
|
||||
@ -748,6 +754,7 @@ IMAGERESIZEREXT
|
||||
imageresizerinput
|
||||
imageresizersettings
|
||||
imagingdevices
|
||||
Imc
|
||||
ime
|
||||
imeutil
|
||||
inetcpl
|
||||
@ -836,6 +843,7 @@ keydown
|
||||
keydropdowncontrol
|
||||
keyevent
|
||||
KEYEVENTF
|
||||
KEYIMAGE
|
||||
keynum
|
||||
keyremaps
|
||||
Keytool
|
||||
@ -1293,6 +1301,7 @@ pinfo
|
||||
pinvoke
|
||||
pipename
|
||||
PKBDLLHOOKSTRUCT
|
||||
Pkcs
|
||||
PKEY
|
||||
plib
|
||||
PLK
|
||||
@ -1435,7 +1444,10 @@ regfile
|
||||
REGFILTER
|
||||
REGFILTERPINS
|
||||
REGISTERCLASSFAILED
|
||||
REGISTRYHEADER
|
||||
registrypath
|
||||
registrypreview
|
||||
REGISTRYPREVIEWEXT
|
||||
regkey
|
||||
REGPINTYPES
|
||||
regsvr
|
||||
@ -2043,6 +2055,7 @@ wox
|
||||
wparam
|
||||
wpf
|
||||
wpfdepsjsonpath
|
||||
wpfgfx
|
||||
wpftmp
|
||||
wpr
|
||||
wprp
|
||||
@ -2091,6 +2104,7 @@ XStr
|
||||
XUP
|
||||
XVIRTUALSCREEN
|
||||
YAxis
|
||||
Yeet
|
||||
YIncrement
|
||||
yinle
|
||||
yinwang
|
||||
|
@ -147,6 +147,10 @@
|
||||
"modules\\PowerRename\\PowerToys.PowerRenameContextMenu.dll",
|
||||
"modules\\PowerRename\\PowerRenameContextMenuPackage.msix",
|
||||
|
||||
"modules\\RegistryPreview\\PowerToys.RegistryPreviewExt.dll",
|
||||
"modules\\RegistryPreview\\PowerToys.RegistryPreview.dll",
|
||||
"modules\\RegistryPreview\\PowerToys.RegistryPreview.exe",
|
||||
|
||||
"modules\\ShortcutGuide\\ShortcutGuide\\PowerToys.ShortcutGuide.exe",
|
||||
"modules\\ShortcutGuide\\ShortcutGuideModuleInterface\\PowerToys.ShortcutGuideModuleInterface.dll",
|
||||
|
||||
@ -240,6 +244,8 @@
|
||||
"modules\\PowerAccent\\Vanara.PInvoke.Shell32.dll",
|
||||
"modules\\PowerAccent\\Vanara.PInvoke.ShlwApi.dll",
|
||||
"modules\\PowerAccent\\Vanara.PInvoke.User32.dll",
|
||||
"modules\\RegistryPreview\\clrcompression.dll",
|
||||
"modules\\RegistryPreview\\Microsoft.Graphics.Canvas.Interop.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.Core.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.WinForms.dll",
|
||||
"modules\\FileExplorerPreview\\Microsoft.Web.WebView2.Wpf.dll",
|
||||
|
@ -18,7 +18,8 @@ $versionExceptions = @(
|
||||
"Microsoft.Xaml.Interactions.dll",
|
||||
"Microsoft.Xaml.Interactivity.dll",
|
||||
"hyjiacan.py4n.dll",
|
||||
"Microsoft.WindowsAppRuntime.Release.Net.dll") -join '|';
|
||||
"Microsoft.WindowsAppRuntime.Release.Net.dll",
|
||||
"Microsoft.Windows.Widgets.Projection.dll") -join '|';
|
||||
$nullVersionExceptions = @(
|
||||
"codicon.ttf",
|
||||
"e_sqlite3.dll",
|
||||
@ -32,7 +33,8 @@ $nullVersionExceptions = @(
|
||||
"MRM.dll",
|
||||
"PushNotificationsLongRunningTask.ProxyStub.dll",
|
||||
"WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll",
|
||||
"System.Diagnostics.EventLog.Messages.dll") -join '|';
|
||||
"System.Diagnostics.EventLog.Messages.dll",
|
||||
"Microsoft.Windows.Widgets.dll") -join '|';
|
||||
$totalFailure = 0;
|
||||
|
||||
Write-Host $DirPath;
|
||||
|
@ -494,6 +494,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PastePlainModuleInterface",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllExperiments", "src\common\AllExperiments\AllExperiments.csproj", "{9CE59ED5-7087-4353-88EB-788038A73CEC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreviewUI", "src\modules\registrypreview\RegistryPreviewUI\RegistryPreviewUI.csproj", "{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegistryPreviewExt", "src\modules\registrypreview\RegistryPreviewExt\RegistryPreviewExt.vcxproj", "{697C6AF9-0A48-49A9-866C-67DA12384015}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RegistryPreview", "RegistryPreview", "{929C1324-22E8-4412-A9A8-80E85F3985A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -2066,6 +2072,30 @@ Global
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x64.Build.0 = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x86.ActiveCfg = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x86.Build.0 = Release|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|x64.Build.0 = Debug|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Debug|x86.Build.0 = Debug|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|x64.ActiveCfg = Release|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|x64.Build.0 = Release|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|x86.ActiveCfg = Release|x64
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}.Release|x86.Build.0 = Release|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|x64.Build.0 = Debug|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Debug|x86.Build.0 = Debug|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|x64.ActiveCfg = Release|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|x64.Build.0 = Release|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|x86.ActiveCfg = Release|x64
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2240,6 +2270,9 @@ Global
|
||||
{9873BA05-4C41-4819-9283-CF45D795431B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{FC373B24-3293-453C-AAF5-CF2909DCEE6A} = {9873BA05-4C41-4819-9283-CF45D795431B}
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{FD86C06A-FB54-4D5E-9831-1CDADF60D45F} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
|
||||
{697C6AF9-0A48-49A9-866C-67DA12384015} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
|
||||
{929C1324-22E8-4412-A9A8-80E85F3985A5} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -15,6 +15,7 @@
|
||||
<?define MeasureToolProjectName="MeasureTool"?>
|
||||
<?define HostsProjectName="Hosts"?>
|
||||
<?define PastePlainProjectName="PastePlain"?>
|
||||
<?define RegistryPreviewProjectName="RegistryPreview"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?if $(var.Platform) = x64?>
|
||||
|
@ -77,6 +77,7 @@ call "..\..\publish.cmd" arm64
|
||||
<Compile Include="PastePlain.wxs" />
|
||||
<Compile Include="PowerAccent.wxs" />
|
||||
<Compile Include="PowerRename.wxs" />
|
||||
<Compile Include="RegistryPreview.wxs" />
|
||||
<Compile Include="Run.wxs" />
|
||||
<Compile Include="Settings.wxs" />
|
||||
<Compile Include="ShortcutGuide.wxs" />
|
||||
|
@ -68,6 +68,7 @@
|
||||
<ComponentGroupRef Id="PastePlainComponentGroup" />
|
||||
<ComponentGroupRef Id="PowerAccentComponentGroup" />
|
||||
<ComponentGroupRef Id="PowerRenameComponentGroup" />
|
||||
<ComponentGroupRef Id="RegistryPreviewComponentGroup" />
|
||||
<ComponentGroupRef Id="RunComponentGroup" />
|
||||
<ComponentGroupRef Id="SettingsComponentGroup" />
|
||||
<ComponentGroupRef Id="ShortcutGuideComponentGroup" />
|
||||
@ -485,6 +486,11 @@
|
||||
<Directory Id="PastePlainInstallFolder" Name="$(var.PastePlainProjectName)">
|
||||
</Directory>
|
||||
|
||||
<!-- RegistryPreview -->
|
||||
<Directory Id="RegistryPreviewInstallFolder" Name="$(var.RegistryPreviewProjectName)">
|
||||
<Directory Id="RegistryPreviewAssetsInstallFolder" Name="Assets" />
|
||||
</Directory>
|
||||
|
||||
<!-- AlwaysOnTop -->
|
||||
<Directory Id="AlwaysOnTopInstallFolder" Name="$(var.AlwaysOnTopProjectName)">
|
||||
</Directory>
|
||||
|
44
installer/PowerToysSetup/RegistryPreview.wxs
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" >
|
||||
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define RegistryPreviewFiles=ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;CommunityToolkit.WinUI.dll;ControlzEx.dll;Ijwhost.dll;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.Graphics.Canvas.dll;Microsoft.Graphics.Display.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.WinUI.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.AppNotifications.Builder.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.Security.AccessControl.Projection.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.Windows.Widgets.Projection.dll;Microsoft.Windows.Widgets.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.Xaml.Behaviors.dll;PowerToys.Common.UI.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.RegistryPreview.deps.json;PowerToys.RegistryPreview.dll;PowerToys.RegistryPreview.exe;PowerToys.RegistryPreview.runtimeconfig.json;PowerToys.RegistryPreviewExt.dll;PowerToys.Settings.UI.Lib.dll;System.CodeDom.dll;System.IO.Abstractions.dll;System.Management.dll;WinRT.Runtime.dll;app.ico;resources.pri?>
|
||||
<?if $(var.Platform) = x64?>
|
||||
<?define RegistryPreviewFiles=$(var.RegistryPreviewFiles);clrcompression.dll?>
|
||||
<?endif?>
|
||||
|
||||
<?define RegistryPreviewAssets=data32.png;folder32.png;string32.png?>
|
||||
|
||||
<Fragment>
|
||||
<!-- Registry Preview -->
|
||||
<DirectoryRef Id="RegistryPreviewInstallFolder" FileSource="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)">
|
||||
<?foreach File in $(var.RegistryPreviewFiles)?>
|
||||
<Component Id="RegistryPreviewComp_$(var.File)" Win64="yes">
|
||||
<File Id="RegistryPreviewFile_$(var.File)" Source="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)\$(var.File)" />
|
||||
</Component>
|
||||
<?endforeach?>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="RegistryPreviewAssetsInstallFolder" FileSource="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)\Assets">
|
||||
<?foreach File in $(var.RegistryPreviewAssets)?>
|
||||
<Component Id="RegistryPreviewAssetsComp_$(var.File)" Win64="yes">
|
||||
<File Id="RegistryPreviewAssetsFile_$(var.File)" Source="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)\Assets\$(var.File)" />
|
||||
</Component>
|
||||
<?endforeach?>
|
||||
</DirectoryRef>
|
||||
|
||||
|
||||
<ComponentGroup Id="RegistryPreviewComponentGroup" Directory="INSTALLFOLDER">
|
||||
<?foreach File in $(var.RegistryPreviewFiles)?>
|
||||
<ComponentRef Id="RegistryPreviewComp_$(var.File)" />
|
||||
<?endforeach?>
|
||||
<?foreach File in $(var.RegistryPreviewAssets)?>
|
||||
<ComponentRef Id="RegistryPreviewAssetsComp_$(var.File)" />
|
||||
<?endforeach?>
|
||||
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
@ -5,9 +5,9 @@
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define SettingsV2Files=WinUIEx.dll;backup_restore_settings.json;Ijwhost.dll;ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.Labs.WinUI.SettingsControls.dll;CommunityToolkit.WinUI.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;icon.ico;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.deps.json;PowerToys.Settings.dll;PowerToys.Settings.exe;PowerToys.Settings.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;resources.pri;System.CodeDom.dll;System.IO.Abstractions.dll;WinRT.Runtime.dll;Microsoft.Graphics.Canvas.dll;System.Management.dll;PowerToys.GPOWrapper.dll;System.Text.Json.dll;WindowsBase.dll;PowerToys.AllExperiments.dll?>
|
||||
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PastePlain.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?define SettingsV2OOBEAssetsModulesFiles=ColorPicker.gif;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;FancyZones.gif;FileExplorer.png;FileLocksmith.gif;ImageResizer.gif;KBM.gif;MouseUtils.gif;PastePlain.gif;PowerAccent.gif;PowerOCR.gif;PowerRename.gif;Run.gif;ScreenRuler.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png;OOBEPTHeroShort.png?>
|
||||
<?define SettingsV2OOBEAssetsFluentIconsFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;Awake.png;FileExplorerPreview.png;FindMyMouse.png;Hosts.png;ImageResizer.png;KeyboardManager.png;MouseHighlighter.png;MouseJump.png;MouseCrosshairs.png;MouseUtils.png;PastePlain.png;PowerAccent.png;PowerOcr.png;PowerRename.png;PowerToys.png;PowerToysRun.png;ScreenRuler.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png?>
|
||||
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PastePlain.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;RegistryPreview.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?define SettingsV2OOBEAssetsModulesFiles=ColorPicker.gif;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;FancyZones.gif;FileExplorer.png;FileLocksmith.gif;ImageResizer.gif;KBM.gif;MouseUtils.gif;PastePlain.gif;PowerAccent.gif;PowerOCR.gif;PowerRename.gif;RegistryPreview.png;Run.gif;ScreenRuler.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png;OOBEPTHeroShort.png?>
|
||||
<?define SettingsV2OOBEAssetsFluentIconsFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;Awake.png;FileExplorerPreview.png;FindMyMouse.png;Hosts.png;ImageResizer.png;KeyboardManager.png;MouseHighlighter.png;MouseJump.png;MouseCrosshairs.png;MouseUtils.png;PastePlain.png;PowerAccent.png;PowerOcr.png;PowerRename.png;PowerToys.png;PowerToysRun.png;RegistryPreview.png;ScreenRuler.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png?>
|
||||
<?define SettingsV2MicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<!-- These files are needed for release builds to contain the experimentation DLLs -->
|
||||
|
@ -18,7 +18,7 @@
|
||||
<?endforeach?>
|
||||
</DirectoryRef>
|
||||
|
||||
<?foreach ParentDirectory in SettingsV2InstallFolder;PowerRenameInstallFolder;MeasureToolInstallFolder;HostsInstallFolder;FileLocksmithInstallFolder?>
|
||||
<?foreach ParentDirectory in SettingsV2InstallFolder;PowerRenameInstallFolder;MeasureToolInstallFolder;HostsInstallFolder;FileLocksmithInstallFolder;RegistryPreviewInstallFolder?>
|
||||
<DirectoryRef Id="$(var.ParentDirectory)">
|
||||
<?foreach Language in $(var.WinAppSDKLocLanguageList)?>
|
||||
<?if $(var.Language) = af-ZA?>
|
||||
@ -351,6 +351,13 @@
|
||||
<File Id="FileLocksmith_WinAppSDKLoc_$(var.IdSafeLanguage)_XamlMui_File" Source="$(var.BinDir)modules\$(var.FileLocksmithProjectName)\$(var.Language)\Microsoft.ui.xaml.dll.mui" />
|
||||
<File Id="FileLocksmith_WinAppSDKLoc_$(var.IdSafeLanguage)_XamlPhoneMui_File" Source="$(var.BinDir)modules\$(var.FileLocksmithProjectName)\$(var.Language)\Microsoft.UI.Xaml.Phone.dll.mui" />
|
||||
</Component>
|
||||
<Component
|
||||
Id="RegistryPreview_WinAppSDKLoc_$(var.IdSafeLanguage)_Component"
|
||||
Directory="WinAppSDKLoc$(var.IdSafeLanguage)RegistryPreviewInstallFolder"
|
||||
Guid="$(var.CompGUIDPrefix)06">
|
||||
<File Id="RegistryPreview_WinAppSDKLoc_$(var.IdSafeLanguage)_XamlMui_File" Source="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)\$(var.Language)\Microsoft.ui.xaml.dll.mui" />
|
||||
<File Id="RegistryPreview_WinAppSDKLoc_$(var.IdSafeLanguage)_XamlPhoneMui_File" Source="$(var.BinDir)modules\$(var.RegistryPreviewProjectName)\$(var.Language)\Microsoft.UI.Xaml.Phone.dll.mui" />
|
||||
</Component>
|
||||
<?undef IdSafeLanguage?>
|
||||
<?undef CompGUIDPrefix?>
|
||||
<?endforeach?>
|
||||
|
@ -22,3 +22,5 @@ msbuild !PTRoot!\src\modules\previewpane\SvgThumbnailProvider\SvgThumbnailProvid
|
||||
msbuild !PTRoot!\src\modules\MeasureTool\MeasureToolUI\MeasureToolUI.csproj -t:Publish -p:Configuration="Release" -p:Platform="!PlatformArg!" -p:AppxBundle=Never -p:PowerToysRoot=!PTRoot! -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=InstallationPublishProfile.pubxml
|
||||
|
||||
msbuild !PTRoot!\src\modules\FileLocksmith\FileLocksmithUI\FileLocksmithUI.csproj -t:Publish -p:Configuration="Release" -p:Platform="!PlatformArg!" -p:AppxBundle=Never -p:PowerToysRoot=!PTRoot! -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=InstallationPublishProfile.pubxml
|
||||
|
||||
msbuild !PTRoot!\src\modules\registrypreview\RegistryPreviewUI\RegistryPreviewUI.csproj -t:Publish -p:Configuration="Release" -p:Platform="!PlatformArg!" -p:AppxBundle=Never -p:PowerToysRoot=!PTRoot! -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=InstallationPublishProfile.pubxml
|
||||
|
@ -984,6 +984,7 @@ const std::wstring WinAppSDKConsumers[] =
|
||||
L"modules\\MeasureTool",
|
||||
L"modules\\FileLocksmith",
|
||||
L"modules\\Hosts",
|
||||
L"modules\\RegistryPreview",
|
||||
};
|
||||
|
||||
UINT __stdcall CreateWinAppSDKHardlinksCA(MSIHANDLE hInstall)
|
||||
@ -1037,6 +1038,7 @@ const std::wstring PTInteropConsumers[] =
|
||||
L"modules\\Hosts",
|
||||
L"modules\\FileExplorerPreview",
|
||||
L"modules\\MouseUtils\\MouseJumpUI",
|
||||
L"modules\\RegistryPreview",
|
||||
};
|
||||
|
||||
UINT __stdcall CreatePTInteropHardlinksCA(MSIHANDLE hInstall)
|
||||
@ -1081,7 +1083,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
UINT er = ERROR_SUCCESS;
|
||||
std::wstring installationFolder, dotnetRuntimeFilesSrcDir, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
|
||||
imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir, hostsDir, fileLocksmithDir,
|
||||
mouseJumpDir;
|
||||
mouseJumpDir, registryPreviewDir;
|
||||
|
||||
hr = WcaInitialize(hInstall, "CreateDotnetRuntimeHardlinksCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
@ -1103,6 +1105,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
hostsDir = installationFolder + L"modules\\Hosts\\";
|
||||
fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
|
||||
mouseJumpDir = installationFolder + L"modules\\MouseUtils\\MouseJumpUI\\";
|
||||
registryPreviewDir = installationFolder + L"modules\\RegistryPreview\\";
|
||||
|
||||
for (auto file : dotnetRuntimeFiles)
|
||||
{
|
||||
@ -1120,6 +1123,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileLocksmithDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mouseJumpDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (registryPreviewDir + file).c_str(), ec);
|
||||
|
||||
if (ec.value() != S_OK)
|
||||
{
|
||||
@ -1144,6 +1148,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mouseJumpDir + file).c_str(), ec);
|
||||
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (registryPreviewDir + file).c_str(), ec);
|
||||
|
||||
if (ec.value() != S_OK)
|
||||
{
|
||||
@ -1238,7 +1243,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
UINT er = ERROR_SUCCESS;
|
||||
std::wstring installationFolder, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
|
||||
imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir,
|
||||
hostsDir, fileLocksmithDir, mouseJumpDir;
|
||||
hostsDir, fileLocksmithDir, mouseJumpDir, registryPreviewDir;
|
||||
|
||||
hr = WcaInitialize(hInstall, "DeleteDotnetRuntimeHardlinksCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
@ -1259,6 +1264,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
hostsDir = installationFolder + L"modules\\Hosts\\";
|
||||
fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
|
||||
mouseJumpDir = installationFolder + L"modules\\MouseUtils\\MouseJumpUI\\";
|
||||
registryPreviewDir = installationFolder + L"modules\\RegistryPreview\\";
|
||||
|
||||
try
|
||||
{
|
||||
@ -1277,6 +1283,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
DeleteFile((hostsDir + file).c_str());
|
||||
DeleteFile((fileLocksmithDir + file).c_str());
|
||||
DeleteFile((mouseJumpDir + file).c_str());
|
||||
DeleteFile((registryPreviewDir + file).c_str());
|
||||
}
|
||||
|
||||
for (auto file : dotnetRuntimeWPFFiles)
|
||||
@ -1291,6 +1298,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
|
||||
DeleteFile((fileExplorerAddOnsDir + file).c_str());
|
||||
DeleteFile((hostsDir + file).c_str());
|
||||
DeleteFile((mouseJumpDir + file).c_str());
|
||||
DeleteFile((registryPreviewDir + file).c_str());
|
||||
}
|
||||
}
|
||||
catch (std::exception e)
|
||||
@ -1324,7 +1332,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
}
|
||||
processes.resize(bytes / sizeof(processes[0]));
|
||||
|
||||
std::array<std::wstring_view, 10> processesToTerminate = {
|
||||
std::array<std::wstring_view, 11> processesToTerminate = {
|
||||
L"PowerToys.PowerLauncher.exe",
|
||||
L"PowerToys.Settings.exe",
|
||||
L"PowerToys.Awake.exe",
|
||||
@ -1334,7 +1342,8 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
L"PowerToys.MouseJumpUI.exe",
|
||||
L"PowerToys.ColorPickerUI.exe",
|
||||
L"PowerToys.AlwaysOnTop.exe",
|
||||
L"PowerToys.exe"
|
||||
L"PowerToys.exe",
|
||||
L"PowerToys.RegistryPreview.exe",
|
||||
};
|
||||
|
||||
for (const auto procID : processes)
|
||||
|
@ -24,6 +24,7 @@ namespace Common.UI
|
||||
ShortcutGuide,
|
||||
VideoConference,
|
||||
Hosts,
|
||||
RegistryPreview,
|
||||
}
|
||||
|
||||
private static string SettingsWindowNameToString(SettingsWindow value)
|
||||
@ -56,6 +57,8 @@ namespace Common.UI
|
||||
return "VideoConference";
|
||||
case SettingsWindow.Hosts:
|
||||
return "Hosts";
|
||||
case SettingsWindow.RegistryPreview:
|
||||
return "RegistryPreview";
|
||||
default:
|
||||
{
|
||||
return string.Empty;
|
||||
|
@ -100,6 +100,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredQuickAccentEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredRegistryPreviewEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredRegistryPreviewEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredScreenRulerEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredScreenRulerEnabledValue());
|
||||
|
@ -31,6 +31,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredRegistryPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredScreenRulerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredShortcutGuideEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue();
|
||||
|
@ -35,6 +35,7 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredRegistryPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredScreenRulerEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredShortcutGuideEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue();
|
||||
|
@ -215,10 +215,14 @@ public
|
||||
return gcnew String(CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT);
|
||||
}
|
||||
|
||||
static String
|
||||
^ MeasureToolTriggerEvent() {
|
||||
static String ^ RegistryPreviewTriggerEvent() {
|
||||
return gcnew String(CommonSharedConstants::REGISTRY_PREVIEW_TRIGGER_EVENT);
|
||||
}
|
||||
|
||||
static String ^ MeasureToolTriggerEvent() {
|
||||
return gcnew String(CommonSharedConstants::MEASURE_TOOL_TRIGGER_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
static String ^ GcodePreviewResizeEvent() {
|
||||
return gcnew String(CommonSharedConstants::GCODE_PREVIEW_RESIZE_EVENT);
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ namespace CommonSharedConstants
|
||||
// Path to the event used by PowerOCR
|
||||
const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a";
|
||||
|
||||
// Path to the event used by RegistryPreview
|
||||
const wchar_t REGISTRY_PREVIEW_TRIGGER_EVENT[] = L"Local\\RegistryPreviewEvent-4C559468-F75A-4E7F-BC4F-9C9688316687";
|
||||
|
||||
// Path to the event used by MeasureTool
|
||||
const wchar_t MEASURE_TOOL_TRIGGER_EVENT[] = L"Local\\MeasureToolEvent-3d46745f-09b3-4671-a577-236be7abd199";
|
||||
|
||||
|
@ -57,6 +57,8 @@ struct LogSettings
|
||||
inline const static std::wstring alwaysOnTopLogPath = L"always-on-top-log.txt";
|
||||
inline const static std::string hostsLoggerName = "hosts";
|
||||
inline const static std::wstring hostsLogPath = L"Logs\\hosts-log.txt";
|
||||
inline const static std::string registryPreviewLoggerName = "registrypreview";
|
||||
inline const static std::wstring registryPreviewLogPath = L"Logs\\registryPreview-log.txt";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
LogSettings();
|
||||
|
@ -48,6 +48,7 @@ namespace powertoys_gpo {
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_TEXT_EXTRACTOR = L"ConfigureEnabledUtilityTextExtractor";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_PASTE_PLAIN = L"ConfigureEnabledUtilityPastePlain";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE = L"ConfigureEnabledUtilityVideoConferenceMute";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW = L"ConfigureEnabledUtilityRegistryPreview";
|
||||
|
||||
// The registry value names for PowerToys installer and update policies.
|
||||
const std::wstring POLICY_DISABLE_AUTOMATIC_UPDATE_DOWNLOAD = L"AutomaticUpdateDownloadDisabled";
|
||||
@ -255,6 +256,10 @@ namespace powertoys_gpo {
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredRegistryPreviewEnabledValue()
|
||||
{
|
||||
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW);
|
||||
}
|
||||
inline gpo_rule_configured_t getDisableAutomaticUpdateDownloadValue()
|
||||
{
|
||||
return getConfiguredValue(POLICY_DISABLE_AUTOMATIC_UPDATE_DOWNLOAD);
|
||||
|
@ -192,6 +192,24 @@ inline registry::ChangeSet getStlThumbnailHandlerChangeSet(const std::wstring in
|
||||
NonLocalizable::ExtSTL);
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getRegistryPreviewChangeSet(const std::wstring installationDir,const bool perUser)
|
||||
{
|
||||
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
||||
|
||||
using vec_t = std::vector<registry::ValueChange>;
|
||||
vec_t changes;
|
||||
|
||||
std::wstring command = installationDir;
|
||||
command.append(L"\\modules\\RegistryPreview\\PowerToys.RegistryPreview.exe \"%1\"");
|
||||
changes.push_back({ scope, L"Software\\Classes\\regfile\\shell\\preview\\command", std::nullopt, command });
|
||||
|
||||
std::wstring icon_path = installationDir;
|
||||
icon_path.append(L"\\modules\\RegistryPreview\\app.ico");
|
||||
changes.push_back({ scope, L"Software\\Classes\\regfile\\shell\\preview", L"icon", icon_path });
|
||||
|
||||
return { changes };
|
||||
}
|
||||
|
||||
inline std::vector<registry::ChangeSet> getAllOnByDefaultModulesChangeSets(const std::wstring installationDir)
|
||||
{
|
||||
constexpr bool PER_USER = true;
|
||||
@ -201,7 +219,8 @@ inline std::vector<registry::ChangeSet> getAllOnByDefaultModulesChangeSets(const
|
||||
getGcodePreviewHandlerChangeSet(installationDir, PER_USER),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER) };
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getRegistryPreviewChangeSet(installationDir, PER_USER) };
|
||||
}
|
||||
|
||||
inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstring installationDir)
|
||||
@ -215,5 +234,6 @@ inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstri
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER) };
|
||||
getStlThumbnailHandlerChangeSet(installationDir, PER_USER),
|
||||
getRegistryPreviewChangeSet(installationDir, PER_USER) };
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
namespace registry
|
||||
{
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct on_exit
|
||||
@ -27,9 +30,6 @@ namespace registry
|
||||
~on_exit() { f(); }
|
||||
};
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
|
@ -269,7 +269,17 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityScreenRuler" class="Both" displayName="$(string.ConfigureEnabledUtilityScreenRuler)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityScreenRuler">
|
||||
<policy name="ConfigureEnabledUtilityRegistryPreview" class="Both" displayName="$(string.ConfigureEnabledUtilityRegistryPreview)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityRegistryPreview">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_69_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityScreenRuler" class="Both" displayName="$(string.ConfigureEnabledUtilityScreenRuler)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityScreenRuler">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" />
|
||||
<enabledValue>
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
<string id="SUPPORTED_POWERTOYS_0_64_0">PowerToys version 0.64.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_68_0">PowerToys version 0.68.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_69_0">PowerToys version 0.69.0 or later</string>
|
||||
|
||||
<string id="ConfigureEnabledUtilityDescription">This policy configures the enabled state for a PowerToys utility.
|
||||
|
||||
@ -81,6 +82,7 @@ If this setting is disabled, experimentation is not allowed.
|
||||
<string id="ConfigureEnabledUtilityPowerRename">Power Rename: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityPowerLauncher">PowerToys Run: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityQuickAccent">Quick Accent: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityRegistryPreview">Registry Preview: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityScreenRuler">Screen Ruler: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityShortcutGuide">Shortcut Guide: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityTextExtractor">Text Extractor: Configure enabled state</string>
|
||||
|
@ -0,0 +1,7 @@
|
||||
#include <string>
|
||||
|
||||
namespace RegistryPreviewConstants
|
||||
{
|
||||
// Name of the powertoy module.
|
||||
inline const std::wstring ModuleKey = L"RegistryPreview";
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_REGISTRYPREVIEW_NAME "Registry Preview"
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</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>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{697C6AF9-0A48-49A9-866C-67DA12384015}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>RegistryPreviewExt</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup>
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\RegistryPreview\</OutDir>
|
||||
<TargetName>PowerToys.RegistryPreviewExt</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;REGISTRYPREVIEWEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;REGISTRYPREVIEWEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Constants.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="RegistryPreviewExt.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220929.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,53 @@
|
||||
<?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;c++;cppm;ixx;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;h++;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="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="RegistryPreviewExt.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
40
src/modules/registrypreview/RegistryPreviewExt/Trace.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
// Log if the user has enabled or disabled the app
|
||||
void Trace::EnableRegistryPreview(_In_ bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"RegistryPreview_EnableRegistryPreview",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user tried to activate the app
|
||||
void Trace::ActivateEditor() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"RegistryPreview_Activate",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
14
src/modules/registrypreview/RegistryPreviewExt/Trace.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
|
||||
// Log if the user has enabled or disabled the app
|
||||
static void EnableRegistryPreview(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user tried to activate the app
|
||||
static void ActivateEditor() noexcept;
|
||||
};
|
265
src/modules/registrypreview/RegistryPreviewExt/dllmain.cpp
Normal file
@ -0,0 +1,265 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/utils/string_utils.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/EventWaiter.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/modulesRegistry.h>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
#include "resource.h"
|
||||
#include "Constants.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const static wchar_t* MODULE_NAME = L"RegistryPreview";
|
||||
const static wchar_t* MODULE_DESC = L"A quick little utility to visualize and edit complex Windows Registry files.";
|
||||
|
||||
class RegistryPreviewModule : public PowertoyModuleIface
|
||||
{
|
||||
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
|
||||
//Hotkey m_hotkey;
|
||||
HANDLE m_hProcess;
|
||||
|
||||
HANDLE triggerEvent;
|
||||
EventWaiter triggerEventWaiter;
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void launch_process()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Starting Registry Preview process");
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"";
|
||||
executable_args.append(std::to_wstring(powertoys_pid));
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\RegistryPreview\\PowerToys.RegistryPreview.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (ShellExecuteExW(&sei))
|
||||
{
|
||||
Logger::trace("Successfully started the Registry Preview process");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Registry Preview failed to start. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
}
|
||||
|
||||
void terminate_process()
|
||||
{
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
}
|
||||
|
||||
public:
|
||||
RegistryPreviewModule()
|
||||
{
|
||||
LoggerHelpers::init_logger(GET_RESOURCE_STRING(IDS_REGISTRYPREVIEW_NAME), L"ModuleInterface", "RegistryPreview");
|
||||
Logger::info("Registry Preview object is constructing");
|
||||
|
||||
if (!m_enabled)
|
||||
{
|
||||
const std::wstring installationDir = get_module_folderpath();
|
||||
|
||||
auto regChanges = getRegistryPreviewChangeSet(installationDir, true);
|
||||
|
||||
if (!regChanges.unApply())
|
||||
{
|
||||
Logger::error(L"Unapplying registry changes failed");
|
||||
}
|
||||
}
|
||||
|
||||
triggerEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::REGISTRY_PREVIEW_TRIGGER_EVENT);
|
||||
triggerEventWaiter = EventWaiter(CommonSharedConstants::REGISTRY_PREVIEW_TRIGGER_EVENT, [this](int) {
|
||||
on_hotkey(0);
|
||||
});
|
||||
}
|
||||
|
||||
~RegistryPreviewModule()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
terminate_process();
|
||||
}
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the configured status for the gpo policy for the module
|
||||
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||
{
|
||||
return powertoys_gpo::getConfiguredRegistryPreviewEnabledValue();
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Pop open the app, if the OOBE page asks it to
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::CustomActionObject action_object =
|
||||
PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
|
||||
if (action_object.get_name() == L"Launch")
|
||||
{
|
||||
launch_process();
|
||||
Trace::ActivateEditor();
|
||||
}
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error(L"Failed to parse action. {}", action);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
// If you don't need to do any custom processing of the settings, proceed
|
||||
// to persists the values.
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
const std::wstring installationDir = get_module_folderpath();
|
||||
|
||||
if (!getRegistryPreviewChangeSet(installationDir, true).apply())
|
||||
{
|
||||
Logger::error(L"Applying registry changes failed");
|
||||
}
|
||||
|
||||
// let the DLL enable the app
|
||||
m_enabled = true;
|
||||
Trace::EnableRegistryPreview(true);
|
||||
};
|
||||
|
||||
virtual void disable()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
// let the DLL disable the app
|
||||
terminate_process();
|
||||
|
||||
Trace::EnableRegistryPreview(false);
|
||||
Logger::trace(L"Disabling Registry Preview...");
|
||||
|
||||
// Yeet the Registry setting so preview doesn't work anymore
|
||||
const std::wstring installationDir = get_module_folderpath();
|
||||
|
||||
if (!getRegistryPreviewChangeSet(installationDir, true).unApply())
|
||||
{
|
||||
Logger::error(L"Unapplying registry changes failed");
|
||||
}
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Respond to a "click" from the launcher
|
||||
virtual bool on_hotkey(size_t /*hotkeyId*/) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Registry Preview hotkey pressed");
|
||||
if (is_process_running())
|
||||
{
|
||||
terminate_process();
|
||||
}
|
||||
else
|
||||
{
|
||||
launch_process();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new RegistryPreviewModule();
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.220929.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220914.1" targetFramework="native" />
|
||||
</packages>
|
1
src/modules/registrypreview/RegistryPreviewExt/pch.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "pch.h"
|
16
src/modules/registrypreview/RegistryPreviewExt/pch.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
//#include <winrt/Windows.Foundation.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
//#include <Shlwapi.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
21
src/modules/registrypreview/RegistryPreviewExt/resource.h
Normal file
@ -0,0 +1,21 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Awake.rc
|
||||
//
|
||||
#define IDS_REGISTRYPREVIEW_NAME 101
|
||||
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys Registry Preview Module"
|
||||
#define INTERNAL_NAME "PowerToys.RegistryPreview"
|
||||
#define ORIGINAL_FILENAME "PowerToys.RegistryPreview.dll"
|
||||
|
||||
// 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
|
15
src/modules/registrypreview/RegistryPreviewUI/App.xaml
Normal file
@ -0,0 +1,15 @@
|
||||
<Application
|
||||
x:Class="RegistryPreview.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:RegistryPreview">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
66
src/modules/registrypreview/RegistryPreviewUI/App.xaml.cs
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using LaunchActivatedEventArgs = Windows.ApplicationModel.Activation.LaunchActivatedEventArgs;
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="App"/> class.
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||
{
|
||||
// Grab the command line parameters directly from the Environment since this is expected to be run
|
||||
// via Context Menu of a REG file.
|
||||
string[] cmdArgs = Environment.GetCommandLineArgs();
|
||||
if (cmdArgs == null)
|
||||
{
|
||||
// Covers the double click exe scenario and treated as no file loaded
|
||||
AppFilename = string.Empty;
|
||||
}
|
||||
else if (cmdArgs.Length == 2)
|
||||
{
|
||||
// GetCommandLineArgs() send in the called EXE as 0 and the selected filename as 1
|
||||
AppFilename = cmdArgs[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Anything else should be treated as no file loaded
|
||||
AppFilename = string.Empty;
|
||||
}
|
||||
|
||||
// Start the application
|
||||
appWindow = new MainWindow();
|
||||
appWindow.Activate();
|
||||
}
|
||||
|
||||
private Window appWindow;
|
||||
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
#pragma warning disable CA2211 // Non-constant fields should not be visible. TODO: consider making it a property
|
||||
public static string AppFilename;
|
||||
#pragma warning restore CA2211 // Non-constant fields should not be visible
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
}
|
||||
}
|
BIN
src/modules/registrypreview/RegistryPreviewUI/Assets/data32.png
Normal file
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
BIN
src/modules/registrypreview/RegistryPreviewUI/Assets/error32.png
Normal file
After Width: | Height: | Size: 678 B |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 356 B |
@ -0,0 +1,385 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using CommunityToolkit.WinUI.UI.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.Data.Json;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler to grab the main window's size and position before it closes
|
||||
/// </summary>
|
||||
private void AppWindow_Closing(Microsoft.UI.Windowing.AppWindow sender, Microsoft.UI.Windowing.AppWindowClosingEventArgs args)
|
||||
{
|
||||
jsonSettings.SetNamedValue("appWindow.Position.X", JsonValue.CreateNumberValue(appWindow.Position.X));
|
||||
jsonSettings.SetNamedValue("appWindow.Position.Y", JsonValue.CreateNumberValue(appWindow.Position.Y));
|
||||
jsonSettings.SetNamedValue("appWindow.Size.Width", JsonValue.CreateNumberValue(appWindow.Size.Width));
|
||||
jsonSettings.SetNamedValue("appWindow.Size.Height", JsonValue.CreateNumberValue(appWindow.Size.Height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is will prevent the app from closing if the "save file" flag is active
|
||||
/// </summary>
|
||||
public void Window_Closed(object sender, WindowEventArgs args)
|
||||
{
|
||||
// Only block closing if the REG file has been edited but not yet saved
|
||||
if (saveButton.IsEnabled)
|
||||
{
|
||||
// if true, the app will not close
|
||||
args.Handled = true;
|
||||
|
||||
// ask the user if they want to save, discard or cancel the close; strings must be loaded here and passed to avoid timing issues
|
||||
HandleDirtyClosing(
|
||||
resourceLoader.GetString("YesNoCancelDialogTitle"),
|
||||
resourceLoader.GetString("YesNoCancelDialogContent"),
|
||||
resourceLoader.GetString("YesNoCancelDialogPrimaryButtonText"),
|
||||
resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
resourceLoader.GetString("YesNoCancelDialogCloseButtonText"));
|
||||
}
|
||||
|
||||
// Save app settings
|
||||
jsonSettings.SetNamedValue("checkBoxTextBox.Checked", JsonValue.CreateBooleanValue(checkBoxTextBox.IsChecked.Value));
|
||||
SaveSettingsFile(settingsFolder, settingsFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired after the visual tree has been fully loaded; the app opens the reg file from here so it can show a message box successfully
|
||||
/// </summary>
|
||||
private void GridPreview_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// static flag to track whether the Visual Tree is ready - if the main Grid has been loaded, the tree is ready.
|
||||
visualTreeReady = true;
|
||||
|
||||
// Load and restore app settings
|
||||
if (jsonSettings.ContainsKey("checkBoxTextBox.Checked"))
|
||||
{
|
||||
checkBoxTextBox.IsChecked = jsonSettings.GetNamedBoolean("checkBoxTextBox.Checked");
|
||||
}
|
||||
|
||||
// Check to see if the REG file was opened and parsed successfully
|
||||
if (OpenRegistryFile(App.AppFilename) == false)
|
||||
{
|
||||
if (File.Exists(App.AppFilename))
|
||||
{
|
||||
// Allow Refresh and Edit to be enabled because a broken Reg file might be fixable
|
||||
UpdateToolBarAndUI(false, true, true);
|
||||
UpdateWindowTitle(resourceLoader.GetString("InvalidRegistryFileTitle"));
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateToolBarAndUI(false, false, false);
|
||||
UpdateWindowTitle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
|
||||
textBox.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses a picker to select a new file to open
|
||||
/// </summary>
|
||||
private async void OpenButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Check to see if the current file has been saved
|
||||
if (saveButton.IsEnabled)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = resourceLoader.GetString("YesNoCancelDialogTitle"),
|
||||
Content = resourceLoader.GetString("YesNoCancelDialogContent"),
|
||||
PrimaryButtonText = resourceLoader.GetString("YesNoCancelDialogPrimaryButtonText"),
|
||||
SecondaryButtonText = resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
CloseButtonText = resourceLoader.GetString("YesNoCancelDialogCloseButtonText"),
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then continue the file open
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the file open!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Don't open the new file!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Pull in a new REG file
|
||||
FileOpenPicker fileOpenPicker = new FileOpenPicker();
|
||||
fileOpenPicker.ViewMode = PickerViewMode.List;
|
||||
fileOpenPicker.CommitButtonText = resourceLoader.GetString("OpenButtonText");
|
||||
fileOpenPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
|
||||
fileOpenPicker.FileTypeFilter.Add(".reg");
|
||||
|
||||
// Get the HWND so we an open the modal
|
||||
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
InitializeWithWindow.Initialize(fileOpenPicker, hWnd);
|
||||
|
||||
StorageFile storageFile = await fileOpenPicker.PickSingleFileAsync();
|
||||
|
||||
if (storageFile != null)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
textBox.TextChanged -= TextBox_TextChanged;
|
||||
|
||||
App.AppFilename = storageFile.Path;
|
||||
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
|
||||
|
||||
// disable the Save button as it's a new file
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// Restore the event handler as we're loaded
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the currently opened file in place
|
||||
/// </summary>
|
||||
private void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SaveFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses a picker to save out a copy of the current reg file
|
||||
/// </summary>
|
||||
private async void SaveAsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Save out a new REG file and then open it
|
||||
FileSavePicker fileSavePicker = new FileSavePicker();
|
||||
fileSavePicker.CommitButtonText = resourceLoader.GetString("SaveButtonText");
|
||||
fileSavePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
|
||||
fileSavePicker.FileTypeChoices.Add("Registry file", new List<string>() { ".reg" });
|
||||
fileSavePicker.SuggestedFileName = resourceLoader.GetString("SuggestFileName");
|
||||
|
||||
// Get the HWND so we an save the modal
|
||||
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
InitializeWithWindow.Initialize(fileSavePicker, hWnd);
|
||||
|
||||
StorageFile storageFile = await fileSavePicker.PickSaveFileAsync();
|
||||
|
||||
if (storageFile != null)
|
||||
{
|
||||
App.AppFilename = storageFile.Path;
|
||||
SaveFile();
|
||||
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the current REG file from storage
|
||||
/// </summary>
|
||||
private void RefreshButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
textBox.TextChanged -= TextBox_TextChanged;
|
||||
|
||||
// reload the current Registry file and update the toolbar accordingly.
|
||||
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename), true, true);
|
||||
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// restore the TextChanged handler
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the Registry Editor; UAC is handled by the request to open
|
||||
/// </summary>
|
||||
private void RegistryButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// pass in an empty string as we have no file to open
|
||||
OpenRegistryEditor(string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges the currently saved file into the Registry Editor; UAC is handled by the request to open
|
||||
/// </summary>
|
||||
private async void WriteButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Check to see if the current file has been saved
|
||||
if (saveButton.IsEnabled)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = resourceLoader.GetString("YesNoCancelDialogTitle"),
|
||||
Content = resourceLoader.GetString("YesNoCancelDialogContent"),
|
||||
PrimaryButtonText = resourceLoader.GetString("YesNoCancelDialogPrimaryButtonText"),
|
||||
SecondaryButtonText = resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
CloseButtonText = resourceLoader.GetString("YesNoCancelDialogCloseButtonText"),
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then continue the file open
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the file open!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Don't open the new file!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// pass in the filename so we can edit the current file
|
||||
OpenRegistryEditor(App.AppFilename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the currently saved file in the PC's default REG file editor (often Notepad)
|
||||
/// </summary>
|
||||
private void EditButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// use the REG file's filename and verb so we can respect the selected editor
|
||||
Process process = new Process();
|
||||
process.StartInfo.FileName = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", App.AppFilename);
|
||||
process.StartInfo.Verb = "Edit";
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("ErrorDialogTitle"),
|
||||
resourceLoader.GetString("FileEditorError"),
|
||||
resourceLoader.GetString("OkButtonText"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trigger that fires when a node in treeView is clicked and which populates dataGrid
|
||||
/// Can also be fired from elsewhere in the code
|
||||
/// </summary>
|
||||
private void TreeView_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs args)
|
||||
{
|
||||
TreeViewItemInvokedEventArgs localArgs = args as TreeViewItemInvokedEventArgs;
|
||||
TreeViewNode treeViewNode = null;
|
||||
|
||||
// if there are no args, the mouse didn't get clicked but we want to believe it did
|
||||
if (args != null)
|
||||
{
|
||||
treeViewNode = args.InvokedItem as TreeViewNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
treeViewNode = treeView.SelectedNode;
|
||||
}
|
||||
|
||||
// Grab the object that has Registry data in it from the currently selected treeView node
|
||||
RegistryKey registryKey = (RegistryKey)treeViewNode.Content;
|
||||
|
||||
// no matter what happens, clear the ListView of items on each click
|
||||
ClearTable();
|
||||
|
||||
// if there's no ListView items stored for the selected node, dataGrid is clear so get out now
|
||||
if (registryKey.Tag == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if there WAS something in the Tag property, cast it to a list and Populate the ListView
|
||||
ArrayList arrayList = (ArrayList)registryKey.Tag;
|
||||
listRegistryValues = new List<RegistryValue>();
|
||||
|
||||
for (int i = 0; i < arrayList.Count; i++)
|
||||
{
|
||||
RegistryValue listViewItem = (RegistryValue)arrayList[i];
|
||||
listRegistryValues.Add(listViewItem);
|
||||
}
|
||||
|
||||
// create a new binding for dataGrid and reattach it, updating the rows
|
||||
Binding listRegistryValuesBinding = new Binding { Source = listRegistryValues };
|
||||
dataGrid.SetBinding(DataGrid.ItemsSourceProperty, listRegistryValuesBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the text in textBox changes, reload treeView and possibly dataGrid and reset the save button
|
||||
/// </summary>
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
RefreshRegistryFile();
|
||||
saveButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Readonly checkbox is checked, set textBox to read only; also update the font color so it has a hint of being "disabled" (also the hover state!)
|
||||
/// </summary>
|
||||
private void CheckBoxTextBox_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
textBox.IsReadOnly = true;
|
||||
SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 120, 120, 120)); // (SolidColorBrush)Application.Current.Resources["TextBoxDisabledForegroundThemeBrush"];
|
||||
if (brush != null)
|
||||
{
|
||||
textBox.Foreground = brush;
|
||||
textBox.Resources["TextControlForegroundPointerOver"] = brush;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Readonly checkbox is unchecked, set textBox to be editable; also update the font color back to a theme friendly foreground (also the hover state!)
|
||||
/// </summary>
|
||||
private void CheckBoxTextBox_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
textBox.IsReadOnly = false;
|
||||
SolidColorBrush brush = (SolidColorBrush)Application.Current.Resources["TextControlForeground"];
|
||||
if (brush != null)
|
||||
{
|
||||
textBox.Foreground = brush;
|
||||
textBox.Resources["TextControlForegroundPointerOver"] = brush;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,896 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Method that opens and processes the passed in file name; expected to be an absolute path and a first time open
|
||||
/// </summary>
|
||||
private bool OpenRegistryFile(string filename)
|
||||
{
|
||||
// clamp to prevent attempts to open a file larger than 10MB
|
||||
try
|
||||
{
|
||||
long fileLength = new System.IO.FileInfo(filename).Length;
|
||||
if (fileLength > 1048576)
|
||||
{
|
||||
ShowMessageBox(resourceLoader.GetString("LargeRegistryFileTitle"), App.AppFilename + resourceLoader.GetString("LargeRegistryFile"), resourceLoader.GetString("OkButtonText"));
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing here - a missing or invalid file will be caught below
|
||||
}
|
||||
|
||||
// Disable parts of the UI that can cause trouble when loading
|
||||
ChangeCursor(gridPreview, true);
|
||||
textBox.Text = string.Empty;
|
||||
|
||||
// clear the treeView and dataGrid no matter what
|
||||
treeView.RootNodes.Clear();
|
||||
ClearTable();
|
||||
|
||||
// update the current window's title with the current filename
|
||||
UpdateWindowTitle(filename);
|
||||
|
||||
// Load in the whole file in one call and plop it all into textBox
|
||||
FileStream fileStream = null;
|
||||
try
|
||||
{
|
||||
FileStreamOptions fileStreamOptions = new FileStreamOptions();
|
||||
fileStreamOptions.Access = FileAccess.Read;
|
||||
fileStreamOptions.Share = FileShare.ReadWrite;
|
||||
fileStreamOptions.Mode = FileMode.Open;
|
||||
|
||||
fileStream = new FileStream(filename, fileStreamOptions);
|
||||
StreamReader streamReader = new StreamReader(fileStream);
|
||||
|
||||
string filenameText = streamReader.ReadToEnd();
|
||||
textBox.Text = filenameText;
|
||||
streamReader.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// restore TextChanged handler to make for clean UI
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
|
||||
// Reset the cursor but leave textBox disabled as no content got loaded
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// clean up no matter what
|
||||
if (fileStream != null)
|
||||
{
|
||||
fileStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// now that the file is loaded and in textBox, parse the data
|
||||
ParseRegistryFile(textBox.Text);
|
||||
|
||||
// Getting here means that the entire REG file was parsed without incident
|
||||
// so select the root of the tree and celebrate
|
||||
if (treeView.RootNodes.Count > 0)
|
||||
{
|
||||
treeView.SelectedNode = treeView.RootNodes[0];
|
||||
treeView.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
// reset the cursor
|
||||
ChangeCursor(gridPreview, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method that re-opens and processes the filename the app already knows about; expected to not be a first time open
|
||||
/// </summary>
|
||||
private void RefreshRegistryFile()
|
||||
{
|
||||
// Disable parts of the UI that can cause trouble when loading
|
||||
ChangeCursor(gridPreview, true);
|
||||
|
||||
// Get the current selected node so we can return focus to an existing node
|
||||
TreeViewNode currentNode = treeView.SelectedNode;
|
||||
|
||||
// clear the treeView and dataGrid no matter what
|
||||
treeView.RootNodes.Clear();
|
||||
ClearTable();
|
||||
|
||||
// the existing text is still in textBox so parse the data again
|
||||
ParseRegistryFile(textBox.Text);
|
||||
|
||||
// check to see if there was a key in treeView before the refresh happened
|
||||
if (currentNode != null)
|
||||
{
|
||||
// since there is a valid node, get the FullPath of the key that was selected
|
||||
string selectedFullPath = ((RegistryKey)currentNode.Content).FullPath;
|
||||
|
||||
// check to see if we still have the key in the new Dictionary of keys
|
||||
if (mapRegistryKeys.ContainsKey(selectedFullPath))
|
||||
{
|
||||
// we found it! select it in the tree and pretend it was selected
|
||||
TreeViewNode treeViewNode;
|
||||
mapRegistryKeys.TryGetValue(selectedFullPath, out treeViewNode);
|
||||
treeView.SelectedNode = treeViewNode;
|
||||
TreeView_ItemInvoked(treeView, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we failed to find an existing node; it could have been deleted in the edit
|
||||
if (treeView.RootNodes.Count > 0)
|
||||
{
|
||||
treeView.SelectedNode = treeView.RootNodes[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no node was previously selected so check for a RootNode and select it
|
||||
if (treeView.RootNodes.Count > 0)
|
||||
{
|
||||
treeView.SelectedNode = treeView.RootNodes[0];
|
||||
}
|
||||
}
|
||||
|
||||
// enable the UI
|
||||
ChangeCursor(gridPreview, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the text that is passed in, which should be the same text that's in textBox
|
||||
/// </summary>
|
||||
private bool ParseRegistryFile(string filenameText)
|
||||
{
|
||||
// if this is a not-first open, clear out the Dictionary of nodes
|
||||
if (mapRegistryKeys != null)
|
||||
{
|
||||
mapRegistryKeys.Clear();
|
||||
mapRegistryKeys = null;
|
||||
}
|
||||
|
||||
// set up a new dictionary
|
||||
mapRegistryKeys = new Dictionary<string, TreeViewNode>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
// As we'll be processing the text one line at a time, this string will be the current line
|
||||
string registryLine;
|
||||
|
||||
// Brute force editing: for textBox to show Cr-Lf corrected, we need to strip out the \n's
|
||||
filenameText = filenameText.Replace("\r\n", "\r");
|
||||
|
||||
// split apart all of the text in textBox, where one element in the array represents one line
|
||||
string[] registryLines = filenameText.Split("\r");
|
||||
if (registryLines.Length <= 1)
|
||||
{
|
||||
// after the split, we have no lines so get out
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// REG files have to start with one of two headers and it's case insensitive
|
||||
registryLine = registryLines[0];
|
||||
registryLine = registryLine.ToLowerInvariant();
|
||||
|
||||
// make sure that this is a valid REG file, based on the first line of the file
|
||||
switch (registryLine)
|
||||
{
|
||||
case REGISTRYHEADER4:
|
||||
case REGISTRYHEADER5:
|
||||
break;
|
||||
default:
|
||||
ShowMessageBox(APPNAME, App.AppFilename + resourceLoader.GetString("InvalidRegistryFile"), resourceLoader.GetString("OkButtonText"));
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// these are used for populating the tree as we read in one line at a time
|
||||
TreeViewNode treeViewNode = null;
|
||||
RegistryValue registryValue = null;
|
||||
|
||||
// start with the first element of the array
|
||||
int index = 1;
|
||||
registryLine = registryLines[index];
|
||||
|
||||
while (index < registryLines.Length)
|
||||
{
|
||||
// special case for when the registryLine begins with a @ - make some tweaks and
|
||||
// let the regular processing handle the rest.
|
||||
if (registryLine.StartsWith("@=-", StringComparison.InvariantCulture))
|
||||
{
|
||||
// REG file has a callout to delete the @ Value which won't work *but* the Registry Editor will
|
||||
// clear the value of the @ Value instead, so it's still a valid line.
|
||||
registryLine = registryLine.Replace("@=-", "\"(Default)\"=\"\"");
|
||||
}
|
||||
else if (registryLine.StartsWith("@=", StringComparison.InvariantCulture))
|
||||
{
|
||||
// This is the a Value called "(Default)" so we tweak the line for the UX
|
||||
registryLine = registryLine.Replace("@=", "\"(Default)\"=");
|
||||
}
|
||||
|
||||
// continue until we have nothing left to read
|
||||
// switch logic, based off what the current line we're reading is
|
||||
if (registryLine.StartsWith("[-", StringComparison.InvariantCulture))
|
||||
{
|
||||
// remove the - as we won't need it but it will get special treatment in the UI
|
||||
registryLine = registryLine.Remove(1, 1);
|
||||
|
||||
// this is a key, so remove the first [ and last ]
|
||||
registryLine = StripFirstAndLast(registryLine);
|
||||
|
||||
// do not track the result of this node, since it should have no children
|
||||
AddTextToTree(registryLine, DELETEDKEYIMAGE);
|
||||
}
|
||||
else if (registryLine.StartsWith("[", StringComparison.InvariantCulture))
|
||||
{
|
||||
// this is a key, so remove the first [ and last ]
|
||||
registryLine = StripFirstAndLast(registryLine);
|
||||
|
||||
treeViewNode = AddTextToTree(registryLine, KEYIMAGE);
|
||||
}
|
||||
else if (registryLine.StartsWith("\"", StringComparison.InvariantCulture) && registryLine.EndsWith("=-", StringComparison.InvariantCulture))
|
||||
{
|
||||
// this line deletes this value so it gets special treatment for the UI
|
||||
registryLine = registryLine.Replace("=-", string.Empty);
|
||||
|
||||
// remove the "'s without removing all of them
|
||||
registryLine = StripFirstAndLast(registryLine);
|
||||
|
||||
// Create a new listview item that will be used to display the delete value and store it
|
||||
registryValue = new RegistryValue(registryLine, string.Empty, string.Empty);
|
||||
SetValueToolTip(registryValue);
|
||||
|
||||
// store the ListViewItem, if we have a valid Key to attach to
|
||||
if (treeViewNode != null)
|
||||
{
|
||||
StoreTheListValue((RegistryKey)treeViewNode.Content, registryValue);
|
||||
}
|
||||
}
|
||||
else if (registryLine.StartsWith("\"", StringComparison.InvariantCulture))
|
||||
{
|
||||
// this is a named value
|
||||
|
||||
// split up the name from the value by looking for the first found =
|
||||
int equal = registryLine.IndexOf('=');
|
||||
if ((equal < 0) || (equal > registryLine.Length - 1))
|
||||
{
|
||||
// something is very wrong
|
||||
Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "SOMETHING WENT WRONG: {0}", registryLine));
|
||||
break;
|
||||
}
|
||||
|
||||
// set the name and the value
|
||||
string name = registryLine.Substring(0, equal);
|
||||
name = StripFirstAndLast(name);
|
||||
|
||||
// Clean out any escaped characters in the value, only for the preview
|
||||
name = StripEscapedCharacters(name);
|
||||
|
||||
string value = registryLine.Substring(equal + 1);
|
||||
|
||||
// Create a new listview item that will be used to display the value
|
||||
registryValue = new RegistryValue(name, "REG_SZ", string.Empty);
|
||||
|
||||
// if the first and last character is a " then this is a string value; get rid of the first and last "
|
||||
if (value.StartsWith("\"", StringComparison.InvariantCulture) && value.EndsWith("\"", StringComparison.InvariantCulture))
|
||||
{
|
||||
value = StripFirstAndLast(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is an invalid value as there are no "s in the right side of the =
|
||||
registryValue.Type = "ERROR";
|
||||
}
|
||||
|
||||
if (value.StartsWith("dword:", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
registryValue.Type = "REG_DWORD";
|
||||
value = value.Replace("dword:", string.Empty);
|
||||
}
|
||||
else if (value.StartsWith("hex(b):", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
registryValue.Type = "REG_QWORD";
|
||||
value = value.Replace("hex(b):", string.Empty);
|
||||
}
|
||||
else if (value.StartsWith("hex:", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
registryValue.Type = "REG_BINARY";
|
||||
value = value.Replace("hex:", string.Empty);
|
||||
}
|
||||
else if (value.StartsWith("hex(2):", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
registryValue.Type = "REG_EXAND_SZ";
|
||||
value = value.Replace("hex(2):", string.Empty);
|
||||
}
|
||||
else if (value.StartsWith("hex(7):", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
registryValue.Type = "REG_MULTI_SZ";
|
||||
value = value.Replace("hex(7):", string.Empty);
|
||||
}
|
||||
|
||||
// If the end of a decimal line ends in a \ then you have to keep
|
||||
// reading the block as a single value!
|
||||
while (value.EndsWith(@",\", StringComparison.InvariantCulture))
|
||||
{
|
||||
value = value.TrimEnd('\\');
|
||||
index++;
|
||||
if (index >= registryLines.Length)
|
||||
{
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
registryLine = registryLines[index];
|
||||
registryLine = registryLine.TrimStart();
|
||||
value += registryLine;
|
||||
}
|
||||
|
||||
// Clean out any escaped characters in the value, only for the preview
|
||||
value = StripEscapedCharacters(value);
|
||||
|
||||
// update the ListViewItem with this information
|
||||
if (registryValue.Type != "ERROR")
|
||||
{
|
||||
registryValue.Value = value;
|
||||
}
|
||||
|
||||
// update the ToolTip
|
||||
SetValueToolTip(registryValue);
|
||||
|
||||
// store the ListViewItem, if we have a valid Key to attach to
|
||||
if (treeViewNode != null)
|
||||
{
|
||||
StoreTheListValue((RegistryKey)treeViewNode.Content, registryValue);
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here, it's not a Key (starts with [) or Value (starts with ") so it's likely waste (comments that start with ; fall out here)
|
||||
|
||||
// read the next line from the REG file
|
||||
index++;
|
||||
|
||||
// if we've gone too far, escape the proc!
|
||||
if (index >= registryLines.Length)
|
||||
{
|
||||
// check to see if anything got parsed!
|
||||
if (treeView.RootNodes.Count <= 0)
|
||||
{
|
||||
ShowMessageBox(APPNAME, App.AppFilename + resourceLoader.GetString("InvalidRegistryFile"), resourceLoader.GetString("OkButtonText"));
|
||||
}
|
||||
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// carry on with the next line
|
||||
registryLine = registryLines[index];
|
||||
}
|
||||
|
||||
// last check, to see if anything got parsed!
|
||||
if (treeView.RootNodes.Count <= 0)
|
||||
{
|
||||
ShowMessageBox(APPNAME, App.AppFilename + resourceLoader.GetString("InvalidRegistryFile"), resourceLoader.GetString("OkButtonText"));
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We're going to store this ListViewItem in an ArrayList which will then
|
||||
/// be attached to the most recently returned TreeNode that came back from
|
||||
/// AddTextToTree. If there's already a list there, we will use that list and
|
||||
/// add our new node to it.
|
||||
/// </summary>
|
||||
private void StoreTheListValue(RegistryKey registryKey, RegistryValue registryValue)
|
||||
{
|
||||
ArrayList arrayList = null;
|
||||
if (registryKey.Tag == null)
|
||||
{
|
||||
arrayList = new ArrayList();
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayList = (ArrayList)registryKey.Tag;
|
||||
}
|
||||
|
||||
arrayList.Add(registryValue);
|
||||
|
||||
// shove the updated array into the Tag property
|
||||
registryKey.Tag = arrayList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the REG file that's being currently being viewed to the app's title bar
|
||||
/// </summary>
|
||||
private void UpdateWindowTitle(string filename)
|
||||
{
|
||||
string[] file = filename.Split('\\');
|
||||
if (file.Length > 0)
|
||||
{
|
||||
appWindow.Title = file[file.Length - 1] + " - " + APPNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
appWindow.Title = filename + " - " + APPNAME;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No REG file was opened, so leave the app's title bar alone
|
||||
/// </summary>
|
||||
private void UpdateWindowTitle()
|
||||
{
|
||||
appWindow.Title = APPNAME;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that assumes everything is enabled/disabled together
|
||||
/// </summary>
|
||||
private void UpdateToolBarAndUI(bool enable)
|
||||
{
|
||||
UpdateToolBarAndUI(enable, enable, enable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable command bar buttons and textBox.
|
||||
/// Note that writeButton and textBox all update with the same value on purpose
|
||||
/// </summary>
|
||||
private void UpdateToolBarAndUI(bool enableWrite, bool enableRefresh, bool enableEdit)
|
||||
{
|
||||
refreshButton.IsEnabled = enableRefresh;
|
||||
editButton.IsEnabled = enableEdit;
|
||||
writeButton.IsEnabled = enableWrite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a new TreeView node, attaches it to a parent if any, and then passes the new node back to the caller
|
||||
/// mapRegistryKeys is a collection of all of the [] lines in the file
|
||||
/// keys comes from the REG file and represents a bunch of nodes
|
||||
/// </summary>
|
||||
private TreeViewNode AddTextToTree(string keys, string image)
|
||||
{
|
||||
string[] individualKeys = keys.Split('\\');
|
||||
string fullPath = keys;
|
||||
TreeViewNode returnNewNode = null, newNode = null, previousNode = null;
|
||||
|
||||
// Walk the list of keys backwards
|
||||
for (int i = individualKeys.Length - 1; i >= 0; i--)
|
||||
{
|
||||
// when a Key is marked for deletion, make sure it only sets the icon for the bottom most leaf
|
||||
if (image == DELETEDKEYIMAGE)
|
||||
{
|
||||
if (i < individualKeys.Length - 1)
|
||||
{
|
||||
image = KEYIMAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// special casing for Registry roots
|
||||
switch (individualKeys[i])
|
||||
{
|
||||
case "HKEY_CLASSES_ROOT":
|
||||
case "HKEY_CURRENT_USER":
|
||||
case "HKEY_LOCAL_MACHINE":
|
||||
case "HKEY_USERS":
|
||||
case "HKEY_CURRENT_CONFIG":
|
||||
image = KEYIMAGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First check the dictionary, and return the current node if it already exists
|
||||
if (mapRegistryKeys.ContainsKey(fullPath))
|
||||
{
|
||||
// was a new node created?
|
||||
if (returnNewNode == null)
|
||||
{
|
||||
// if no new nodes have been created, send out the node we should have already
|
||||
mapRegistryKeys.TryGetValue(fullPath, out returnNewNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// as a new node was created, hook it up to this found parent
|
||||
mapRegistryKeys.TryGetValue(fullPath, out newNode);
|
||||
newNode.Children.Add(previousNode);
|
||||
}
|
||||
|
||||
// return the new node no matter what
|
||||
return returnNewNode;
|
||||
}
|
||||
|
||||
// Since the path is not in the tree, create a new node and add it to the dictionary
|
||||
RegistryKey registryKey = new RegistryKey(individualKeys[i], fullPath, image, GetFolderToolTip(image));
|
||||
|
||||
newNode = new TreeViewNode() { Content = registryKey, IsExpanded = true };
|
||||
mapRegistryKeys.Add(fullPath, newNode);
|
||||
|
||||
// if this is the first new node we're creating, we need to return it to the caller
|
||||
if (previousNode == null)
|
||||
{
|
||||
// capture the first node so it can be returned
|
||||
returnNewNode = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The newly created node is a parent to the previously created node, as add it here.
|
||||
newNode.Children.Add(previousNode);
|
||||
}
|
||||
|
||||
// before moving onto the next node, tag the previous node and update the path
|
||||
previousNode = newNode;
|
||||
fullPath = fullPath.Replace(string.Format(CultureInfo.InvariantCulture, @"\{0}", individualKeys[i]), string.Empty);
|
||||
|
||||
// One last check: if we get here, the parent of this node is not yet in the tree, so we need to add it as a RootNode
|
||||
if (i == 0)
|
||||
{
|
||||
treeView.RootNodes.Add(newNode);
|
||||
treeView.UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
return returnNewNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that shows a simple one-button message box, parented by the main application window
|
||||
/// </summary>
|
||||
private async void ShowMessageBox(string title, string content, string closeButtonText)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = title,
|
||||
Content = content,
|
||||
CloseButtonText = closeButtonText,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that shows a Save/Don't Save/Cancel message box, parented by the main application window and shown when closing the app
|
||||
/// </summary>
|
||||
private async void HandleDirtyClosing(string title, string content, string primaryButtonText, string secondaryButtonText, string closeButtonText)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = title,
|
||||
Content = content,
|
||||
PrimaryButtonText = primaryButtonText,
|
||||
SecondaryButtonText = secondaryButtonText,
|
||||
CloseButtonText = closeButtonText,
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then close
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save, and then close!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Cancel closing!
|
||||
return;
|
||||
}
|
||||
|
||||
// if we got here, we should try to close again
|
||||
App.Current.Exit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method will open the Registry Editor or merge the current REG file into the Registry via the Editor
|
||||
/// Process will prompt for elevation if it needs it.
|
||||
/// </summary>
|
||||
private void OpenRegistryEditor(string fileMerge)
|
||||
{
|
||||
Process process = new Process();
|
||||
process.StartInfo.FileName = "regedit.exe";
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
if (File.Exists(fileMerge))
|
||||
{
|
||||
// If Merge was called, pass in the filename as a param to the Editor
|
||||
process.StartInfo.Arguments = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", fileMerge);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("UACDialogTitle"),
|
||||
resourceLoader.GetString("UACDialogError"),
|
||||
resourceLoader.GetString("OkButtonText"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility method that clears out the GridView as there's no other way to do it.
|
||||
/// </summary>
|
||||
private void ClearTable()
|
||||
{
|
||||
if (listRegistryValues != null)
|
||||
{
|
||||
listRegistryValues.Clear();
|
||||
}
|
||||
|
||||
dataGrid.ItemsSource = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the current app cursor at the grid level to be a wait cursor. Sort of works, sort of doesn't, but it's a nice attempt.
|
||||
/// </summary>
|
||||
public void ChangeCursor(UIElement uiElement, bool wait)
|
||||
{
|
||||
// You can only change the Cursor if the visual tree is loaded
|
||||
if (!visualTreeReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InputCursor cursor = InputSystemCursor.Create(wait ? InputSystemCursorShape.Wait : InputSystemCursorShape.Arrow);
|
||||
System.Type type = typeof(UIElement);
|
||||
type.InvokeMember("ProtectedCursor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, uiElement, new object[] { cursor }, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that saves the current file in place, using the current text in textBox.
|
||||
/// </summary>
|
||||
private void SaveFile()
|
||||
{
|
||||
ChangeCursor(gridPreview, true);
|
||||
|
||||
// set up the FileStream for all writing
|
||||
FileStream fileStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
// attempt to open the existing file for writing
|
||||
FileStreamOptions fileStreamOptions = new FileStreamOptions();
|
||||
fileStreamOptions.Access = FileAccess.Write;
|
||||
fileStreamOptions.Share = FileShare.Write;
|
||||
fileStreamOptions.Mode = FileMode.OpenOrCreate;
|
||||
|
||||
fileStream = new FileStream(App.AppFilename, fileStreamOptions);
|
||||
StreamWriter streamWriter = new StreamWriter(fileStream, System.Text.Encoding.Unicode);
|
||||
|
||||
// if we get here, the file is open and writable so dump the whole contents of textBox
|
||||
string filenameText = textBox.Text;
|
||||
streamWriter.Write(filenameText);
|
||||
streamWriter.Flush();
|
||||
streamWriter.Close();
|
||||
|
||||
// only change when the save is successful
|
||||
saveButton.IsEnabled = false;
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
// this exception is thrown if the file is there but marked as read only
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("ErrorDialogTitle"),
|
||||
ex.Message,
|
||||
resourceLoader.GetString("OkButtonText"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// this catch handles all other exceptions thrown when trying to write the file out
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("ErrorDialogTitle"),
|
||||
resourceLoader.GetString("FileSaveError"),
|
||||
resourceLoader.GetString("OkButtonText"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// clean up no matter what
|
||||
if (fileStream != null)
|
||||
{
|
||||
fileStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// restore the cursor
|
||||
ChangeCursor(gridPreview, false);
|
||||
}
|
||||
|
||||
private async void OpenSettingsFile(string path, string filename)
|
||||
{
|
||||
StorageFolder storageFolder = null;
|
||||
StorageFile storageFile = null;
|
||||
string fileContents = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
storageFolder = await StorageFolder.GetFolderFromPathAsync(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (storageFolder != null)
|
||||
{
|
||||
storageFile = await storageFolder.GetFileAsync(filename);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (storageFile != null)
|
||||
{
|
||||
fileContents = await Windows.Storage.FileIO.ReadTextAsync(storageFile);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
jsonSettings = Windows.Data.Json.JsonObject.Parse(fileContents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// set up default JSON blob
|
||||
fileContents = "{ }";
|
||||
jsonSettings = Windows.Data.Json.JsonObject.Parse(fileContents);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the settings JSON blob out to a local file
|
||||
/// </summary>
|
||||
private async void SaveSettingsFile(string path, string filename)
|
||||
{
|
||||
StorageFolder storageFolder = null;
|
||||
StorageFile storageFile = null;
|
||||
string fileContents = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
storageFolder = await StorageFolder.GetFolderFromPathAsync(path);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
Directory.CreateDirectory(path);
|
||||
storageFolder = await StorageFolder.GetFolderFromPathAsync(path);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
storageFile = await storageFolder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
storageFile = await storageFolder.CreateFileAsync(filename);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileContents = jsonSettings.Stringify();
|
||||
await Windows.Storage.FileIO.WriteTextAsync(storageFile, fileContents);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rip the first and last character off a string,
|
||||
/// checking that the string is at least 2 characters long to avoid errors
|
||||
/// </summary>
|
||||
private string StripFirstAndLast(string line)
|
||||
{
|
||||
if (line.Length > 1)
|
||||
{
|
||||
line = line.Remove(line.Length - 1, 1);
|
||||
line = line.Remove(0, 1);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace any escaped characters in the REG file with their counterparts, for the UX
|
||||
/// </summary>
|
||||
private string StripEscapedCharacters(string value)
|
||||
{
|
||||
value = value.Replace("\\\\", "\\"); // Replace \\ with \ in the UI
|
||||
value = value.Replace("\\\"", "\""); // Replace \" with " in the UI
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads and returns a string for a given Key's image in the tree, based off the current set image
|
||||
/// </summary>
|
||||
private string GetFolderToolTip(string key)
|
||||
{
|
||||
string value = string.Empty;
|
||||
switch (key)
|
||||
{
|
||||
case DELETEDKEYIMAGE:
|
||||
value = resourceLoader.GetString("ToolTipDeletedKey");
|
||||
break;
|
||||
case KEYIMAGE:
|
||||
value = resourceLoader.GetString("ToolTipAddedKey");
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a string for a given Value's image in the grid, based off the current type and updates the RegistryValue that's passed in
|
||||
/// </summary>
|
||||
private void SetValueToolTip(RegistryValue registryValue)
|
||||
{
|
||||
string value = string.Empty;
|
||||
switch (registryValue.Type)
|
||||
{
|
||||
case "REG_SZ":
|
||||
case "REG_EXAND_SZ":
|
||||
case "REG_MULTI_SZ":
|
||||
value = resourceLoader.GetString("ToolTipStringValue");
|
||||
break;
|
||||
case "ERROR":
|
||||
value = resourceLoader.GetString("ToolTipErrorValue");
|
||||
break;
|
||||
case "":
|
||||
value = resourceLoader.GetString("ToolTipDeletedValue");
|
||||
break;
|
||||
default:
|
||||
value = resourceLoader.GetString("ToolTipBinaryValue");
|
||||
break;
|
||||
}
|
||||
|
||||
registryValue.ToolTipText = value;
|
||||
}
|
||||
}
|
||||
}
|
212
src/modules/registrypreview/RegistryPreviewUI/MainWindow.xaml
Normal file
@ -0,0 +1,212 @@
|
||||
<Window
|
||||
x:Class="RegistryPreview.MainWindow"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:RegistryPreview"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Closed="Window_Closed"
|
||||
>
|
||||
<Grid
|
||||
x:Name="gridPreview"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
Width="Auto"
|
||||
Height="Auto"
|
||||
TabFocusNavigation="Cycle"
|
||||
x:FieldModifier="public"
|
||||
Loaded="GridPreview_Loaded"
|
||||
>
|
||||
<Grid.ColumnDefinitions>
|
||||
<!-- Left, Splitter, Right -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="6"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<!-- CommandBar, Tree, Splitter, List, StackPanel -->
|
||||
<RowDefinition Height="48"/>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="6" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="32"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<CommandBar
|
||||
Name="commandBar"
|
||||
Background="Transparent"
|
||||
IsOpen="True"
|
||||
DefaultLabelPosition="Right"
|
||||
HorizontalAlignment="Left"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
IsTabStop="False"
|
||||
>
|
||||
<AppBarButton x:Name="openButton" x:Uid="OpenButton" Icon="OpenFile" IsTabStop="False" Click="OpenButton_Click" HorizontalAlignment="Left">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="Control" Key="O" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="saveButton" x:Uid="SaveButton" Icon="Save" IsTabStop="False" Click="SaveButton_Click" HorizontalAlignment="Left" IsEnabled="False">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="None" Key="F2" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="saveAsButton" x:Uid="SaveAsButton" Icon="SaveLocal" IsTabStop="False" Click="SaveAsButton_Click" HorizontalAlignment="Left" IsEnabled="True">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="Shift" Key="F2" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="editButton" x:Uid="EditButton" Icon="NewWindow" IsTabStop="False" Click="EditButton_Click" HorizontalAlignment="Left">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="Control" Key="E" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="refreshButton" x:Uid="RefreshButton" Icon="Refresh" IsTabStop="False" Click="RefreshButton_Click" HorizontalAlignment="Left">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="F5" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="writeButton" x:Uid="WriteButton" Icon="Share" IsTabStop="False" Click="WriteButton_Click" HorizontalAlignment="Left">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="Control" Key="W" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Name="registryButton" x:Uid="RegistryButton" Icon="Go" IsTabStop="False" Click="RegistryButton_Click" HorizontalAlignment="Left">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Modifiers="Control" Key="R" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
</AppBarButton>
|
||||
</CommandBar>
|
||||
|
||||
<TextBox
|
||||
x:Name="textBox"
|
||||
x:Uid="textBox"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsTabStop="True"
|
||||
TabIndex="0"
|
||||
IsTextPredictionEnabled="False"
|
||||
IsSpellCheckEnabled="False"
|
||||
AcceptsReturn="True"
|
||||
PlaceholderText="{Binding PlaceholderText}"
|
||||
TextWrapping="NoWrap"
|
||||
CanBeScrollAnchor="False"
|
||||
ScrollViewer.IsVerticalRailEnabled ="True"
|
||||
ScrollViewer.IsHorizontalRailEnabled="True"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Visible"
|
||||
FontFamily="Cascadia Mono, Consolas, Courier New"
|
||||
/>
|
||||
|
||||
<StackPanel
|
||||
x:Name="stackPanelTextBox"
|
||||
Grid.Column="0"
|
||||
Grid.Row="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsTabStop="False"
|
||||
Background="Transparent"
|
||||
>
|
||||
<CheckBox
|
||||
x:Name="checkBoxTextBox"
|
||||
x:Uid="checkBoxTextBox"
|
||||
Content="{Binding Content}"
|
||||
IsChecked="True"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsTabStop="True"
|
||||
TabIndex="1"
|
||||
Checked="CheckBoxTextBox_Checked"
|
||||
Unchecked="CheckBoxTextBox_Unchecked"
|
||||
/>
|
||||
</StackPanel>
|
||||
|
||||
<TreeView
|
||||
x:Name="treeView"
|
||||
Grid.Column="2"
|
||||
Grid.Row="1"
|
||||
Background="Transparent"
|
||||
CanDragItems="False"
|
||||
AllowDrop="False"
|
||||
AllowFocusOnInteraction="True"
|
||||
CanReorderItems="False"
|
||||
IsEnabled="True"
|
||||
ScrollViewer.BringIntoViewOnFocusChange="True"
|
||||
ScrollViewer.VerticalScrollMode="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Visible"
|
||||
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||
ItemInvoked="TreeView_ItemInvoked"
|
||||
Padding="0,0,0,0"
|
||||
IsTabStop="False"
|
||||
TabIndex="2"
|
||||
>
|
||||
<TreeView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Padding="0,0,0,0" IsTabStop="False">
|
||||
<Image Source="{Binding Path=Content.Image}" MaxHeight="16" MaxWidth="16" ToolTipService.ToolTip="{Binding Path=Content.ToolTipText}"/>
|
||||
<TextBlock Padding="5,0,0,0" Text="{Binding Path=Content.Name}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
|
||||
<controls:DataGrid
|
||||
x:Name="dataGrid"
|
||||
Background="Transparent"
|
||||
Grid.Column="2"
|
||||
Grid.Row="3"
|
||||
Grid.RowSpan="2"
|
||||
CanDrag="False"
|
||||
SelectionMode="Single"
|
||||
AllowDrop="False"
|
||||
AreRowDetailsFrozen="True"
|
||||
HeadersVisibility="Column"
|
||||
RowDetailsVisibilityMode="Collapsed"
|
||||
IsReadOnly="True"
|
||||
AutoGenerateColumns="False"
|
||||
ItemsSource="{x:Bind listRegistryValues}"
|
||||
IsTabStop="true"
|
||||
TabIndex="3"
|
||||
>
|
||||
<controls:DataGrid.Columns>
|
||||
<controls:DataGridTemplateColumn
|
||||
x:Uid="NameColumn"
|
||||
Width="Auto"
|
||||
IsReadOnly="True"
|
||||
>
|
||||
<controls:DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Padding="10,0,0,0" Text=" " FontSize="14" IsTabStop="False"/>
|
||||
<Image Source="{Binding ImageUri}" MaxHeight="16" MaxWidth="16" IsTabStop="False" ToolTipService.ToolTip="{Binding ToolTipText}" />
|
||||
<TextBlock Padding="5, 0, 10, 0" Text="{Binding Name}" FontSize="14" IsTabStop="False"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</controls:DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumn>
|
||||
<controls:DataGridTextColumn
|
||||
x:Uid="TypeColumn"
|
||||
Width="Auto"
|
||||
Binding="{Binding Type}"
|
||||
FontSize="14"
|
||||
/>
|
||||
<controls:DataGridTextColumn
|
||||
x:Uid="ValueColumn"
|
||||
Width="Auto"
|
||||
Binding="{Binding Value}"
|
||||
FontSize="14"
|
||||
/>
|
||||
</controls:DataGrid.Columns>
|
||||
</controls:DataGrid>
|
||||
|
||||
<controls:GridSplitter x:Name="verticalSplitter" Grid.Column="1" Grid.Row="1" Grid.RowSpan="4" CursorBehavior="ChangeOnSplitterHover" Background="{ThemeResource TextControlBorderBrush}" VerticalAlignment="Stretch" GripperCursor="SizeWestEast" IsTabStop="False"/>
|
||||
<controls:GridSplitter x:Name="horizontalSplitter" Grid.Column="2" Grid.Row="2" CursorBehavior="ChangeOnSplitterHover" Background="{ThemeResource TextControlBorderBrush}" HorizontalAlignment="Stretch" GripperCursor="SizeNorthSouth" IsTabStop="False"/>
|
||||
</Grid>
|
||||
</Window>
|
@ -0,0 +1,93 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Data.Json;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
// Const values
|
||||
private const string REGISTRYHEADER4 = "regedit4";
|
||||
private const string REGISTRYHEADER5 = "windows registry editor version 5.00";
|
||||
private const string APPNAME = "Registry Preview";
|
||||
private const string KEYIMAGE = "ms-appx:///Assets/folder32.png";
|
||||
private const string DELETEDKEYIMAGE = "ms-appx:///Assets/deleted-folder32.png";
|
||||
|
||||
// private members
|
||||
private Microsoft.UI.Windowing.AppWindow appWindow;
|
||||
private ResourceLoader resourceLoader;
|
||||
private bool visualTreeReady;
|
||||
private Dictionary<string, TreeViewNode> mapRegistryKeys;
|
||||
private List<RegistryValue> listRegistryValues;
|
||||
private JsonObject jsonSettings;
|
||||
private string settingsFolder = string.Empty;
|
||||
private string settingsFile = string.Empty;
|
||||
|
||||
internal MainWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
// Initialize the string table
|
||||
resourceLoader = ResourceLoader.GetForViewIndependentUse();
|
||||
|
||||
// Removed this on 2/15/23 as it doesn't seem to be doing anything any more
|
||||
// Attempts to force the visual tree to load faster
|
||||
// this.Activate();
|
||||
|
||||
// Update the Win32 looking window with the correct icon (and grab the appWindow handle for later)
|
||||
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle);
|
||||
appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
|
||||
appWindow.SetIcon("app.ico");
|
||||
appWindow.Closing += AppWindow_Closing;
|
||||
|
||||
// Open settings file; this moved to after the window tweak because it gives the window time to start up
|
||||
settingsFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerToys\" + APPNAME;
|
||||
settingsFile = APPNAME + "_settings.json";
|
||||
OpenSettingsFile(settingsFolder, settingsFile);
|
||||
|
||||
// TODO: figure out a way to only call this once after MainWindow is initialized but before it shows itself
|
||||
// Calling it from here only successfully resizes/moves the window and it seems to be based off timing, which is horrible.
|
||||
// Calling it from GridPreview_Loaded() works 100% of the time, but the initial state of the window flashes before sizing/moving it
|
||||
//
|
||||
// // if have settings, update the location of the window
|
||||
// if (jsonSettings != null)
|
||||
// {
|
||||
// // resize the window
|
||||
// if (jsonSettings.ContainsKey("appWindow.Size.Width") && jsonSettings.ContainsKey("appWindow.Size.Height"))
|
||||
// {
|
||||
// SizeInt32 size;
|
||||
// size.Width = (int)jsonSettings.GetNamedNumber("appWindow.Size.Width");
|
||||
// size.Height = (int)jsonSettings.GetNamedNumber("appWindow.Size.Height");
|
||||
// appWindow.Resize(size);
|
||||
// }
|
||||
//
|
||||
// // reposition the window
|
||||
// if (jsonSettings.ContainsKey("appWindow.Position.X") && jsonSettings.ContainsKey("appWindow.Position.Y"))
|
||||
// {
|
||||
// PointInt32 point;
|
||||
// point.X = (int)jsonSettings.GetNamedNumber("appWindow.Position.X");
|
||||
// point.Y = (int)jsonSettings.GetNamedNumber("appWindow.Position.Y");
|
||||
// appWindow.Move(point);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Update Toolbar
|
||||
if ((App.AppFilename == null) || (File.Exists(App.AppFilename) != true))
|
||||
{
|
||||
UpdateToolBarAndUI(false);
|
||||
UpdateWindowTitle(resourceLoader.GetString("FileNotFound"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing an each item in the tree view, each one a Registry Key;
|
||||
/// FullPath is so we can re-select the node after a live update
|
||||
/// Tag is an Array of ListViewItems that stores all the children for the current object
|
||||
/// </summary>
|
||||
public class RegistryKey
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string FullPath { get; set; }
|
||||
|
||||
public string Image { get; set; }
|
||||
|
||||
public string ToolTipText { get; set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
public RegistryKey(string name, string fullPath, string image, string toolTipText)
|
||||
{
|
||||
this.Name = name;
|
||||
this.FullPath = fullPath;
|
||||
this.Image = image;
|
||||
this.ToolTipText = toolTipText;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<Platforms>x86;x64;arm64</Platforms>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\RegistryPreview</OutputPath>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<UseWindowsForms>False</UseWindowsForms>
|
||||
<ApplicationIcon>app.ico</ApplicationIcon>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<SelfContained>true</SelfContained>
|
||||
<Product>$(AssemblyName)</Product>
|
||||
<AssemblyName>PowerToys.RegistryPreview</AssemblyName>
|
||||
<AssemblyTitle>PowerToys.RegistryPreview</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys RegistryPreview</AssemblyDescription>
|
||||
<RootNamespace>RegistryPreview</RootNamespace>
|
||||
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
|
||||
<PropertyGroup Condition="'$(Platform)'=='x64'">
|
||||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
|
||||
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="app.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Needed for CommunityToolkit.Labs.WinUI.SettingsControls, on local builds and PR CI. -->
|
||||
<PropertyGroup Condition="'$(IsPipeline)' == ''">
|
||||
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json</RestoreAdditionalProjectSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\data32.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\string32.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<!--TargetFramework>net6.0-windows10.0.19041.0</TargetFramework-->
|
@ -0,0 +1,57 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
|
||||
namespace RegistryPreview
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing an each item in the list view, each one a Registry Value.
|
||||
/// </summary>
|
||||
public class RegistryValue
|
||||
{
|
||||
// Static members
|
||||
private static Uri uriStringValue = new Uri("ms-appx:///Assets/string32.png");
|
||||
private static Uri uriBinaryValue = new Uri("ms-appx:///Assets/data32.png");
|
||||
private static Uri uriDeleteValue = new Uri("ms-appx:///Assets/deleted-value32.png");
|
||||
private static Uri uriErrorValue = new Uri("ms-appx:///Assets/error32.png");
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string ToolTipText { get; set; }
|
||||
|
||||
public Uri ImageUri
|
||||
{
|
||||
// Based off the Type of the item, pass back the correct image Uri used by the Binding of the DataGrid
|
||||
get
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case "REG_SZ":
|
||||
case "REG_EXAND_SZ":
|
||||
case "REG_MULTI_SZ":
|
||||
return uriStringValue;
|
||||
case "ERROR":
|
||||
return uriErrorValue;
|
||||
case "":
|
||||
return uriDeleteValue;
|
||||
}
|
||||
|
||||
return uriBinaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
public RegistryValue(string name, string type, string value)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Type = type;
|
||||
this.Value = value;
|
||||
this.ToolTipText = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="checkBoxTextBox.Content" xml:space="preserve">
|
||||
<value>Read only</value>
|
||||
</data>
|
||||
<data name="EditButton.Label" xml:space="preserve">
|
||||
<value>Edit file...</value>
|
||||
</data>
|
||||
<data name="ErrorDialogTitle" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="FileEditorError" xml:space="preserve">
|
||||
<value>The REG file editor could not be opened.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>File was not found!</value>
|
||||
</data>
|
||||
<data name="FileSaveError" xml:space="preserve">
|
||||
<value>The REG file cannot be written to.</value>
|
||||
</data>
|
||||
<data name="InvalidRegistryFile" xml:space="preserve">
|
||||
<value> doesn't appear to be a valid registry file!</value>
|
||||
</data>
|
||||
<data name="InvalidRegistryFileTitle" xml:space="preserve">
|
||||
<value>File was not a Registry file!</value>
|
||||
</data>
|
||||
<data name="LargeRegistryFile" xml:space="preserve">
|
||||
<value> is larger than 10MB which is too large for this application.</value>
|
||||
</data>
|
||||
<data name="LargeRegistryFileTitle" xml:space="preserve">
|
||||
<value>File is too large!</value>
|
||||
</data>
|
||||
<data name="NameColumn.Header" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="OkButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="OpenButton.Label" xml:space="preserve">
|
||||
<value>Open file...</value>
|
||||
</data>
|
||||
<data name="OpenButtonText" xml:space="preserve">
|
||||
<value>Open</value>
|
||||
</data>
|
||||
<data name="RefreshButton.Label" xml:space="preserve">
|
||||
<value>Reload from file</value>
|
||||
</data>
|
||||
<data name="RegistryButton.Label" xml:space="preserve">
|
||||
<value>Open Registry Editor...</value>
|
||||
</data>
|
||||
<data name="SaveAsButton.Label" xml:space="preserve">
|
||||
<value>Save file as...</value>
|
||||
</data>
|
||||
<data name="SaveButton.Label" xml:space="preserve">
|
||||
<value>Save file</value>
|
||||
</data>
|
||||
<data name="SaveButtonText" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="SuggestFileName" xml:space="preserve">
|
||||
<value>New Registry File</value>
|
||||
</data>
|
||||
<data name="textBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Registry file text will appear here...</value>
|
||||
</data>
|
||||
<data name="ToolTipAddedKey" xml:space="preserve">
|
||||
<value>Key will be added, if needed</value>
|
||||
</data>
|
||||
<data name="ToolTipBinaryValue" xml:space="preserve">
|
||||
<value>Binary value will be updated</value>
|
||||
</data>
|
||||
<data name="ToolTipDeletedKey" xml:space="preserve">
|
||||
<value>Key will be deleted</value>
|
||||
</data>
|
||||
<data name="ToolTipDeletedValue" xml:space="preserve">
|
||||
<value>Value will be deleted</value>
|
||||
</data>
|
||||
<data name="ToolTipErrorValue" xml:space="preserve">
|
||||
<value>Value has a syntax error</value>
|
||||
</data>
|
||||
<data name="ToolTipStringValue" xml:space="preserve">
|
||||
<value>String value will be updated</value>
|
||||
</data>
|
||||
<data name="TypeColumn.Header" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="UACDialogError" xml:space="preserve">
|
||||
<value>You must click Yes on the previous popup if you want to run the Registry application.</value>
|
||||
</data>
|
||||
<data name="UACDialogTitle" xml:space="preserve">
|
||||
<value>User Account Control</value>
|
||||
</data>
|
||||
<data name="ValueColumn.Header" xml:space="preserve">
|
||||
<value>Value</value>
|
||||
</data>
|
||||
<data name="WriteButton.Label" xml:space="preserve">
|
||||
<value>Write to Registry...</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogCloseButtonText" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogContent" xml:space="preserve">
|
||||
<value>Changes were made to the text file. Do you want to save your changes?</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogPrimaryButtonText" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogSecondaryButtonText" xml:space="preserve">
|
||||
<value>Don't save</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogTitle" xml:space="preserve">
|
||||
<value>Registry Preview</value>
|
||||
</data>
|
||||
</root>
|
BIN
src/modules/registrypreview/RegistryPreviewUI/app.ico
Normal file
After Width: | Height: | Size: 401 KiB |
21
src/modules/registrypreview/RegistryPreviewUI/app.manifest
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="RegistryPreview.app"/>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<!-- The combination of below two tags have the following effect:
|
||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
||||
2) System < Windows 10 Anniversary Update
|
||||
-->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
@ -165,6 +165,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
L"modules/PowerOCR/PowerToys.PowerOCRModuleInterface.dll",
|
||||
L"modules/PastePlain/PowerToys.PastePlainModuleInterface.dll",
|
||||
L"modules/FileLocksmith/PowerToys.FileLocksmithExt.dll",
|
||||
L"modules/RegistryPreview/PowerToys.RegistryPreviewExt.dll",
|
||||
L"modules/MeasureTool/PowerToys.MeasureToolModuleInterface.dll",
|
||||
L"modules/Hosts/PowerToys.HostsModuleInterface.dll",
|
||||
};
|
||||
|
@ -663,6 +663,8 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "VideoConference";
|
||||
case ESettingsWindowNames::Hosts:
|
||||
return "Hosts";
|
||||
case ESettingsWindowNames::RegistryPreview:
|
||||
return "RegistryPreview";
|
||||
default:
|
||||
{
|
||||
Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast<int>(value));
|
||||
@ -726,6 +728,10 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::Hosts;
|
||||
}
|
||||
else if (value == "RegistryPreview")
|
||||
{
|
||||
return ESettingsWindowNames::RegistryPreview;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value));
|
||||
|
@ -16,7 +16,8 @@ enum class ESettingsWindowNames
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
VideoConference,
|
||||
Hosts
|
||||
Hosts,
|
||||
RegistryPreview,
|
||||
};
|
||||
|
||||
std::string ESettingsWindowNames_to_string(ESettingsWindowNames value);
|
||||
|
@ -362,6 +362,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool registryPreview = true;
|
||||
|
||||
[JsonPropertyName("RegistryPreview")]
|
||||
public bool RegistryPreview
|
||||
{
|
||||
get => registryPreview;
|
||||
set
|
||||
{
|
||||
if (registryPreview != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
registryPreview = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyChange()
|
||||
{
|
||||
notifyEnabledChangedAction?.Invoke();
|
||||
|
@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class RegistryPreviewSettings : BasePTModuleSettings, ISettingsConfig
|
||||
{
|
||||
public const string ModuleName = "RegistryPreview";
|
||||
|
||||
public RegistryPreviewSettings()
|
||||
{
|
||||
Version = "1";
|
||||
Name = ModuleName;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
=> Name;
|
||||
|
||||
// This can be utilized in the future if the settings.json file is to be modified/deleted.
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
=> false;
|
||||
}
|
||||
}
|
@ -153,6 +153,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "VideoConference": StartupPage = typeof(Views.VideoConferencePage); break;
|
||||
case "MeasureTool": StartupPage = typeof(Views.MeasureToolPage); break;
|
||||
case "Hosts": StartupPage = typeof(Views.HostsPage); break;
|
||||
case "RegistryPreview": StartupPage = typeof(Views.RegistryPreviewPage); break;
|
||||
case "PastePlain": StartupPage = typeof(Views.PastePlainPage); break;
|
||||
default: Debug.Assert(false, "Unexpected SettingsWindow argument value"); break;
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 425 KiB |
BIN
src/settings-ui/Settings.UI/Assets/Modules/RegistryPreview.png
Normal file
After Width: | Height: | Size: 66 KiB |
@ -65,6 +65,13 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
|
||||
break;
|
||||
|
||||
case "RegistryPreview": // Launch Registry Preview
|
||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent()))
|
||||
{
|
||||
eventHandle.Set();
|
||||
}
|
||||
|
||||
break;
|
||||
case "MeasureTool": // Launch Screen Ruler
|
||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent()))
|
||||
{
|
||||
|
@ -138,6 +138,9 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "PowerAccent":
|
||||
needToUpdate = generalSettingsConfig.Enabled.PowerAccent != isEnabled;
|
||||
generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
|
||||
case "RegistryPreview":
|
||||
needToUpdate = generalSettingsConfig.Enabled.RegistryPreview != isEnabled;
|
||||
generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
|
||||
case "MeasureTool":
|
||||
needToUpdate = generalSettingsConfig.Enabled.MeasureTool != isEnabled;
|
||||
generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
|
||||
|
@ -26,5 +26,6 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
|
||||
Hosts,
|
||||
PastePlain,
|
||||
WhatsNew,
|
||||
RegistryPreview,
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeRegistryPreview"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:toolkitcontrols="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
mc:Ignorable="d">
|
||||
<controls:OOBEPageControl
|
||||
x:Uid="Oobe_RegistryPreview"
|
||||
HeroImage="ms-appx:///Assets/Modules/OOBE/RegistryPreview.png">
|
||||
|
||||
<controls:OOBEPageControl.PageContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
|
||||
<TextBlock
|
||||
x:Uid="Oobe_HowToUse"
|
||||
Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
|
||||
<toolkitcontrols:MarkdownTextBlock
|
||||
x:Uid="Oobe_RegistryPreview_HowToUse"
|
||||
Background="Transparent" />
|
||||
|
||||
<TextBlock
|
||||
x:Uid="Oobe_TipsAndTricks"
|
||||
Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
|
||||
<toolkitcontrols:MarkdownTextBlock
|
||||
x:Uid="Oobe_RegistryPreview_TipsAndTricks"
|
||||
Background="Transparent" />
|
||||
|
||||
<StackPanel
|
||||
Margin="0,24,0,0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="12">
|
||||
<Button
|
||||
x:Uid="Launch_RegistryPreview"
|
||||
Click="Launch_RegistryPreview_Click"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
<Button
|
||||
x:Uid="OOBE_Settings"
|
||||
Click="SettingsLaunchButton_Click" />
|
||||
<HyperlinkButton
|
||||
NavigateUri="https://aka.ms/PowerToysOverview_RegistryPreview"
|
||||
Style="{StaticResource TextButtonStyle}">
|
||||
<TextBlock
|
||||
x:Uid="LearnMore_RegistryPreview"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</controls:OOBEPageControl.PageContent>
|
||||
</controls:OOBEPageControl>
|
||||
</Page>
|
@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class OobeRegistryPreview : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeRegistryPreview()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.RegistryPreview]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void Launch_RegistryPreview_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
ShellPage.SendDefaultIPCMessage("{\"action\":{\"RegistryPreview\":{\"action_name\":\"Launch\", \"value\":\"\"}}}");
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(RegistryPreviewPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
@ -84,6 +84,10 @@
|
||||
x:Uid="Shell_QuickAccent"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsPowerAccent.png}"
|
||||
Tag="QuickAccent" />
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_RegistryPreview"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsRegistryPreview.png}"
|
||||
Tag="RegistryPreview" />
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_MeasureTool"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsScreenRuler.png}"
|
||||
|
@ -170,6 +170,12 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
ModuleName = "WhatsNew",
|
||||
IsNew = false,
|
||||
});
|
||||
|
||||
Modules.Insert((int)PowerToysModules.RegistryPreview, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = "RegistryPreview",
|
||||
IsNew = true,
|
||||
});
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
@ -240,6 +246,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
case "MouseUtils": NavigationFrame.Navigate(typeof(OobeMouseUtils)); break;
|
||||
case "MeasureTool": NavigationFrame.Navigate(typeof(OobeMeasureTool)); break;
|
||||
case "Hosts": NavigationFrame.Navigate(typeof(OobeHosts)); break;
|
||||
case "RegistryPreview": NavigationFrame.Navigate(typeof(OobeRegistryPreview)); break;
|
||||
case "PastePlain": NavigationFrame.Navigate(typeof(OobePastePlain)); break;
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,9 @@
|
||||
<Page Update="OOBE\Views\OobeOverviewAlternate.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Views\RegistryPreviewPage.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -3043,6 +3043,41 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>The maximum size, in kilobytes, for files to be displayed. This is a safety mechanism to prevent loading large files into RAM.</value>
|
||||
<comment>"RAM" refers to random access memory; "size" refers to disk space; "bytes" refer to the measurement unit</comment>
|
||||
</data>
|
||||
<data name="RegistryPreview.ModuleDescription" xml:space="preserve">
|
||||
<value>A quick little utility to visualize and edit complex Windows Registry files.</value>
|
||||
</data>
|
||||
<data name="RegistryPreview.ModuleTitle" xml:space="preserve">
|
||||
<value>Registry Preview</value>
|
||||
</data>
|
||||
<data name="Shell_RegistryPreview.Content" xml:space="preserve">
|
||||
<value>Registry Preview</value>
|
||||
<comment>Product name: Navigation view item name for Registry Preview</comment>
|
||||
</data>
|
||||
<data name="RegistryPreview_Enable_RegistryPreview.Header" xml:space="preserve">
|
||||
<value>Enable Registry Preview</value>
|
||||
<comment>Registry Preview is the name of the utility</comment>
|
||||
</data>
|
||||
<data name="Oobe_RegistryPreview_HowToUse.Text" xml:space="preserve">
|
||||
<value>In File Explorer, right-click a .REG file and select **Preview** from the context menu.</value>
|
||||
</data>
|
||||
<data name="Oobe_RegistryPreview_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>You can preview or edit Registry files in File Explorer or by opening the app from the PowerToys launcher.</value>
|
||||
</data>
|
||||
<data name="Oobe_RegistryPreview.Description" xml:space="preserve">
|
||||
<value>Registry Preview is a quick little utility to visualize and edit complex Windows Registry files.</value>
|
||||
</data>
|
||||
<data name="Oobe_RegistryPreview.Title" xml:space="preserve">
|
||||
<value>Registry Preview</value>
|
||||
<comment>Do not localize this string</comment>
|
||||
</data>
|
||||
<data name="LearnMore_RegistryPreview.Text" xml:space="preserve">
|
||||
<value>Learn more about Registry Preview</value>
|
||||
<comment>Registry Preview is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="Launch_RegistryPreview.Content" xml:space="preserve">
|
||||
<value>Launch Registry Preview</value>
|
||||
<comment>"Registry Preview" is the name of the utility</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_MouseJump.Description" xml:space="preserve">
|
||||
<value>Quickly move the mouse pointer long distances.</value>
|
||||
<comment>"Mouse Jump" is the name of the utility. Mouse is the hardware mouse.</comment>
|
||||
@ -3071,4 +3106,13 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="Hosts_Toggle_LoopbackDuplicates.Header" xml:space="preserve">
|
||||
<value>Consider loopback addresses as duplicates</value>
|
||||
</data>
|
||||
<data name="RegistryPreview_Launch_GroupSettings.Header" xml:space="preserve">
|
||||
<value>Launch</value>
|
||||
</data>
|
||||
<data name="RegistryPreview_LaunchButton_Accessible.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Launch Registry Preview</value>
|
||||
</data>
|
||||
<data name="RegistryPreview_LaunchButtonControl.Header" xml:space="preserve">
|
||||
<value>Launch Registry Preview</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -113,6 +113,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("QuickAccent/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PowerAccent, Tag = "PowerAccent", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerAccent.png", EnabledChangedCallback = EnabledChangedOnUI });
|
||||
}
|
||||
|
||||
if ((gpo = GPOWrapper.GetConfiguredRegistryPreviewEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled)
|
||||
{
|
||||
FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("RegistryPreview/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.RegistryPreview, Tag = "RegistryPreview", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsRegistryPreview.png", EnabledChangedCallback = EnabledChangedOnUI });
|
||||
}
|
||||
|
||||
if ((gpo = GPOWrapper.GetConfiguredScreenRulerEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled)
|
||||
{
|
||||
FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MeasureTool/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.MeasureTool, Tag = "MeasureTool", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsScreenRuler.png", EnabledChangedCallback = EnabledChangedOnUI });
|
||||
@ -164,6 +169,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
case "PowerRename": item.IsEnabled = generalSettingsConfig.Enabled.PowerRename; break;
|
||||
case "PowerLauncher": item.IsEnabled = generalSettingsConfig.Enabled.PowerLauncher; break;
|
||||
case "PowerAccent": item.IsEnabled = generalSettingsConfig.Enabled.PowerAccent; break;
|
||||
case "RegistryPreview": item.IsEnabled = generalSettingsConfig.Enabled.RegistryPreview; break;
|
||||
case "MeasureTool": item.IsEnabled = generalSettingsConfig.Enabled.MeasureTool; break;
|
||||
case "ShortcutGuide": item.IsEnabled = generalSettingsConfig.Enabled.ShortcutGuide; break;
|
||||
case "PowerOCR": item.IsEnabled = generalSettingsConfig.Enabled.PowerOCR; break;
|
||||
|
@ -8,6 +8,7 @@ using global::PowerToys.GPOWrapper;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
@ -93,6 +94,17 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
if (GPOWrapper.GetConfiguredRegistryPreviewEnabledValue() != GpoRuleConfigured.Disabled)
|
||||
{
|
||||
FlyoutMenuItems.Add(new FlyoutMenuItem()
|
||||
{
|
||||
Label = resourceLoader.GetString("RegistryPreview/ModuleTitle"),
|
||||
Tag = "RegistryPreview",
|
||||
Visible = generalSettingsConfig.Enabled.RegistryPreview,
|
||||
Icon = "ms-appx:///Assets/FluentIcons/FluentIconsRegistryPreview.png",
|
||||
});
|
||||
}
|
||||
|
||||
if (GPOWrapper.GetConfiguredScreenRulerEnabledValue() != GpoRuleConfigured.Disabled)
|
||||
{
|
||||
FlyoutMenuItems.Add(new FlyoutMenuItem()
|
||||
@ -147,6 +159,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
case "Hosts": item.Visible = generalSettingsConfig.Enabled.Hosts; break;
|
||||
case "PowerLauncher": item.Visible = generalSettingsConfig.Enabled.PowerLauncher; break;
|
||||
case "PowerOCR": item.Visible = generalSettingsConfig.Enabled.PowerOCR; break;
|
||||
case "RegistryPreview": item.Visible = generalSettingsConfig.Enabled.RegistryPreview; break;
|
||||
case "MeasureTool": item.Visible = generalSettingsConfig.Enabled.MeasureTool; break;
|
||||
case "ShortcutGuide": item.Visible = generalSettingsConfig.Enabled.ShortcutGuide; break;
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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;
|
||||
using global::PowerToys.GPOWrapper;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
public class RegistryPreviewViewModel : Observable
|
||||
{
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
public ButtonClickCommand LaunchEventHandler => new ButtonClickCommand(Launch);
|
||||
|
||||
public RegistryPreviewViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
// To obtain the general settings configurations of PowerToys Settings.
|
||||
if (settingsRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settingsRepository));
|
||||
}
|
||||
|
||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||
|
||||
InitializeEnabledValue();
|
||||
|
||||
// set the callback functions value to hangle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
|
||||
private void InitializeEnabledValue()
|
||||
{
|
||||
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
|
||||
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||
{
|
||||
// Get the enabled state from GPO.
|
||||
_enabledStateIsGPOConfigured = true;
|
||||
_isRegistryPreviewEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isRegistryPreviewEnabled = GeneralSettingsConfig.Enabled.RegistryPreview;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRegistryPreviewEnabled
|
||||
{
|
||||
get => _isRegistryPreviewEnabled;
|
||||
set
|
||||
{
|
||||
if (_enabledStateIsGPOConfigured)
|
||||
{
|
||||
// If it's GPO configured, shouldn't be able to change this state.
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isRegistryPreviewEnabled != value)
|
||||
{
|
||||
_isRegistryPreviewEnabled = value;
|
||||
OnPropertyChanged(nameof(IsRegistryPreviewEnabled));
|
||||
|
||||
GeneralSettingsConfig.Enabled.RegistryPreview = value;
|
||||
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabledGpoConfigured
|
||||
{
|
||||
get => _enabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public void Launch()
|
||||
{
|
||||
var actionName = "Launch";
|
||||
|
||||
SendConfigMSG("{\"action\":{\"RegistryPreview\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
|
||||
}
|
||||
|
||||
private Func<string, int> SendConfigMSG { get; }
|
||||
|
||||
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
||||
private bool _enabledStateIsGPOConfigured;
|
||||
private bool _isRegistryPreviewEnabled;
|
||||
|
||||
public void RefreshEnabledState()
|
||||
{
|
||||
InitializeEnabledValue();
|
||||
OnPropertyChanged(nameof(IsRegistryPreviewEnabled));
|
||||
}
|
||||
}
|
||||
}
|
54
src/settings-ui/Settings.UI/Views/RegistryPreviewPage.xaml
Normal file
@ -0,0 +1,54 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.RegistryPreviewPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI.UI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:SettingsPageControl
|
||||
x:Uid="RegistryPreview"
|
||||
ModuleImageSource="ms-appx:///Assets/Modules/RegistryPreview.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel Orientation="Vertical" ChildrenTransitions="{StaticResource SettingsCardsAnimations}">
|
||||
<labs:SettingsCard
|
||||
x:Uid="RegistryPreview_Enable_RegistryPreview"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsRegistryPreview.png}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabledGpoConfigured, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsRegistryPreviewEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</labs:SettingsCard>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="GPO_IsSettingForced"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabledGpoConfigured}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabledGpoConfigured}"
|
||||
Severity="Informational" />
|
||||
|
||||
<controls:SettingsGroup x:Uid="RegistryPreview_Launch_GroupSettings" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsRegistryPreviewEnabled}">
|
||||
<labs:SettingsCard
|
||||
x:Uid="RegistryPreview_LaunchButtonControl"
|
||||
ActionIcon="{ui:FontIcon FontFamily={StaticResource SymbolThemeFontFamily},
|
||||
FontSize=14,
|
||||
Glyph=}"
|
||||
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
||||
HeaderIcon="{ui:FontIcon FontFamily={StaticResource SymbolThemeFontFamily},
|
||||
Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
</controls:SettingsGroup>
|
||||
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
|
||||
<controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:PageLink
|
||||
x:Uid="LearnMore_RegistryPreview"
|
||||
Link="https://aka.ms/PowerToysOverview_RegistryPreview" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class RegistryPreviewPage : Page, IRefreshablePage
|
||||
{
|
||||
private RegistryPreviewViewModel ViewModel { get; set; }
|
||||
|
||||
public RegistryPreviewPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
ViewModel = new RegistryPreviewViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void RefreshEnabledState()
|
||||
{
|
||||
ViewModel.RefreshEnabledState();
|
||||
}
|
||||
}
|
||||
}
|
@ -119,6 +119,11 @@
|
||||
helpers:NavHelper.NavigateTo="views:PowerAccentPage"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsPowerAccent.png}" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_RegistryPreview"
|
||||
helpers:NavHelper.NavigateTo="views:RegistryPreviewPage"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsRegistryPreview.png}" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_MeasureTool"
|
||||
helpers:NavHelper.NavigateTo="views:MeasureToolPage"
|
||||
|
@ -32,5 +32,6 @@ std::vector<std::wstring> processes =
|
||||
L"PowerToys.PdfThumbnailProvider.exe",
|
||||
L"PowerToys.StlThumbnailProvider.exe",
|
||||
L"PowerToys.SvgPreviewHandler.exe",
|
||||
L"PowerToys.SvgThumbnailProvider.exe"
|
||||
L"PowerToys.SvgThumbnailProvider.exe",
|
||||
L"PowerToys.RegistryPreview.exe"
|
||||
};
|
||||
|