Browse Source

.NET 8 changes and rewrites

Ruben 2 years ago
parent
commit
66b78b3850

+ 31 - 0
src/PicView.Tools/LockScreenImage.cs

@@ -0,0 +1,31 @@
+using Microsoft.Win32;
+using System.Runtime.InteropServices;
+
+namespace PicView.Tools;
+
+public static class LockScreenHelper
+{
+    [DllImport("kernel32.dll", SetLastError = true)]
+    public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); //If on 64 bit, C# will replace "System32" with "SysWOW64". This disables that.
+
+    public static bool SetLockScreenImage(string path)
+    {
+        const string registryKey =
+            @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP";
+        var ptr = new IntPtr();
+        Wow64DisableWow64FsRedirection(ref ptr);
+
+        try
+        {
+            Registry.SetValue(registryKey, "LockScreenImageStatus", 1, RegistryValueKind.DWord);
+            Registry.SetValue(registryKey, "LockScreenImagePath", path, RegistryValueKind.String);
+            Registry.SetValue(registryKey, "LockScreenImageUrl", path, RegistryValueKind.String);
+        }
+        catch
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 13 - 0
src/PicView.Tools/PicView.Tools.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <PublishAot>true</PublishAot>
+    <InvariantGlobalization>true</InvariantGlobalization>
+    <PlatformTarget>x64</PlatformTarget>
+  </PropertyGroup>
+
+</Project>

+ 25 - 0
src/PicView.Tools/Program.cs

@@ -0,0 +1,25 @@
+using PicView.Tools;
+
+if (args.Length is 0)
+{
+    Environment.Exit(-1);
+}
+
+if (string.IsNullOrEmpty(args[0]))
+{
+    Environment.Exit(-1);
+}
+
+var arg = args[0];
+
+if (arg.StartsWith("lockscreen"))
+{
+    var path = arg[(arg.LastIndexOf(',') + 1)..];
+    path = Path.GetFullPath(path);
+    LockScreenHelper.SetLockScreenImage(path);
+
+#if DEBUG
+    Console.WriteLine(path);
+    Console.ReadKey();
+#endif
+}

+ 11 - 2
src/PicView.sln

@@ -1,9 +1,14 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29209.62
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34112.27
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView", "PicView\PicView.csproj", "{9B5425DC-4329-4A7A-A0C5-F93161F77245}"
+	ProjectSection(ProjectDependencies) = postProject
+		{47DE1EC3-CD33-43E1-857F-4820C6AD16B6} = {47DE1EC3-CD33-43E1-857F-4820C6AD16B6}
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PicView.Tools", "PicView.Tools\PicView.Tools.csproj", "{47DE1EC3-CD33-43E1-857F-4820C6AD16B6}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +20,10 @@ Global
 		{9B5425DC-4329-4A7A-A0C5-F93161F77245}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9B5425DC-4329-4A7A-A0C5-F93161F77245}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{9B5425DC-4329-4A7A-A0C5-F93161F77245}.Release|Any CPU.Build.0 = Release|Any CPU
+		{47DE1EC3-CD33-43E1-857F-4820C6AD16B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{47DE1EC3-CD33-43E1-857F-4820C6AD16B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{47DE1EC3-CD33-43E1-857F-4820C6AD16B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{47DE1EC3-CD33-43E1-857F-4820C6AD16B6}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 50 - 53
src/PicView/ChangeImage/PreLoader.cs

@@ -180,28 +180,58 @@ internal static class PreLoader
     {
         int nextStartingIndex, prevStartingIndex, deleteIndex;
         var source = new CancellationTokenSource();
+        if (Reverse)
+        {
+            nextStartingIndex = currentIndex + NegativeIterations > count ? count : currentIndex + NegativeIterations;
+            prevStartingIndex = currentIndex + 1;
+            deleteIndex = prevStartingIndex + NegativeIterations;
+        }
+        else
+        {
+            nextStartingIndex = currentIndex - NegativeIterations < 0 ? 0 : currentIndex - NegativeIterations;
+            prevStartingIndex = currentIndex - 1;
+            deleteIndex = prevStartingIndex - NegativeIterations;
+        }
+
+#if DEBUG
+        if (ShowAddRemove)
+            Trace.WriteLine($"\nPreLoading started at {nextStartingIndex}\n");
+#endif
 
-        await Task.Run(() =>
+        await Parallel.ForAsync(0, PositiveIterations + NegativeIterations, source.Token, (i, loopState) =>
         {
+            try
+            {
+                if (Pics.Count == 0 || count != Pics.Count)
+                {
+                    loopState.ThrowIfCancellationRequested();
+                }
+            }
+            catch (Exception)
+            {
+                return ValueTask.CompletedTask;
+            }
+
+            int index;
             if (Reverse)
             {
-                nextStartingIndex = currentIndex + NegativeIterations > count ? count : currentIndex + NegativeIterations;
-                prevStartingIndex = currentIndex + 1;
-                deleteIndex = prevStartingIndex + NegativeIterations;
+                index = (nextStartingIndex - i + Pics.Count) % Pics.Count;
             }
             else
             {
-                nextStartingIndex = currentIndex - NegativeIterations < 0 ? 0 : currentIndex - NegativeIterations;
-                prevStartingIndex = currentIndex - 1;
-                deleteIndex = prevStartingIndex - NegativeIterations;
+                index = (nextStartingIndex + i) % Pics.Count;
             }
 
-#if DEBUG
-            if (ShowAddRemove)
-                Trace.WriteLine($"\nPreLoading started at {nextStartingIndex}\n");
-#endif
+            _ = AddAsync(index).ConfigureAwait(false);
+            return ValueTask.CompletedTask;
+        });
+
+        var thread = Thread.CurrentThread;
+        thread.Priority = ThreadPriority.Lowest;
 
-            Parallel.For(0, PositiveIterations + NegativeIterations, (i, loopState) =>
+        if (Pics.Count > MaxCount + NegativeIterations)
+        {
+            for (var i = 0; i < NegativeIterations; i++)
             {
                 try
                 {
@@ -212,59 +242,26 @@ internal static class PreLoader
                 }
                 catch (Exception)
                 {
-                    loopState.Stop();
                     return;
                 }
 
                 int index;
                 if (Reverse)
                 {
-                    index = (nextStartingIndex - i + Pics.Count) % Pics.Count;
+                    index = (deleteIndex + i) % Pics.Count;
                 }
                 else
                 {
-                    index = (nextStartingIndex + i) % Pics.Count;
+                    index = (deleteIndex - i + Pics.Count) % Pics.Count;
                 }
 
-                _ = AddAsync(index).ConfigureAwait(false);
-            });
-
-            var thread = Thread.CurrentThread;
-            thread.Priority = ThreadPriority.Lowest;
-            if (Pics.Count > MaxCount + NegativeIterations)
-            {
-                for (var i = 0; i < NegativeIterations; i++)
-                {
-                    try
-                    {
-                        if (Pics.Count == 0 || count != Pics.Count)
-                        {
-                            throw new TaskCanceledException();
-                        }
-                    }
-                    catch (Exception)
-                    {
-                        return;
-                    }
-
-                    int index;
-                    if (Reverse)
-                    {
-                        index = (deleteIndex + i) % Pics.Count;
-                    }
-                    else
-                    {
-                        index = (deleteIndex - i + Pics.Count) % Pics.Count;
-                    }
-
-                    Remove(index);
-                }
+                Remove(index);
             }
+        }
 
-            while (PreLoadList.Count > MaxCount)
-            {
-                Remove(Reverse ? PreLoadList.Keys.Max() : PreLoadList.Keys.Min());
-            }
-        }, source.Token).ConfigureAwait(false);
+        while (PreLoadList.Count > MaxCount)
+        {
+            Remove(Reverse ? PreLoadList.Keys.Max() : PreLoadList.Keys.Min());
+        }
     }
 }

+ 16 - 16
src/PicView/ConfigureSettings/ConfigColors.cs

@@ -70,22 +70,22 @@ internal static class ConfigColors
 
         if (Settings.Default.DarkTheme)
         {
-            w.BorderBrush = isFocused ? (SolidColorBrush)Application.Current.Resources["BorderBrush"]
-                : (SolidColorBrush)Application.Current.Resources["BorderBrushAlt"];
-
-            w.LeftButtonContainer.Background =
-                w.Logo.Background =
-                    w.CloseButton.Background =
-                        w.MinButton.Background =
-                            w.FullscreenButton.Background =
-                                isFocused ? (SolidColorBrush)Application.Current.Resources["BackgroundColorBrush"]
-                                    : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
-
-            w.TitleBar.Background =
-                isFocused ? (SolidColorBrush)Application.Current.Resources["SubtleFadeBrush"]
-                    : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
-            w.LowerBar.Background = isFocused ? (SolidColorBrush)Application.Current.Resources["BackgroundColorBrushAlt"]
-                : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
+            //w.BorderBrush = isFocused ? (SolidColorBrush)Application.Current.Resources["BorderBrush"]
+            //    : (SolidColorBrush)Application.Current.Resources["BorderBrushAlt"];
+
+            //w.LeftButtonContainer.Background =
+            //    w.Logo.Background =
+            //        w.CloseButton.Background =
+            //            w.MinButton.Background =
+            //                w.FullscreenButton.Background =
+            //                    isFocused ? (SolidColorBrush)Application.Current.Resources["BackgroundColorBrush"]
+            //                        : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
+
+            //w.TitleBar.Background =
+            //    isFocused ? (SolidColorBrush)Application.Current.Resources["SubtleFadeBrush"]
+            //        : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
+            //w.LowerBar.Background = isFocused ? (SolidColorBrush)Application.Current.Resources["BackgroundColorBrushAlt"]
+            //    : (SolidColorBrush)Application.Current.Resources["BorderBrush"];
         }
         else
         {

+ 7 - 7
src/PicView/PicGallery/GalleryLoad.cs

@@ -3,7 +3,6 @@ using PicView.FileHandling;
 using PicView.ImageHandling;
 using PicView.UILogic;
 using PicView.Views.UserControls.Gallery;
-using System.Collections.Concurrent;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO;
@@ -65,12 +64,13 @@ internal static class GalleryLoad
         await Task.Run(async () =>
         {
             var priority = iterations > 3000 ? DispatcherPriority.Background : DispatcherPriority.Render;
-            for (int i = 0; i < iterations; i++)
+            await Parallel.ForAsync(0, iterations, source.Token, async (i, loopState) =>
             {
                 try
                 {
                     if (!IsLoading || Navigation.Pics?.Count < Navigation.FolderIndex || Navigation.Pics?.Count < 1)
                     {
+                        loopState.ThrowIfCancellationRequested();
                         throw new TaskCanceledException();
                     }
 
@@ -86,9 +86,8 @@ internal static class GalleryLoad
                     Trace.WriteLine(e.Message);
 #endif
                     IsLoading = false;
-                    return;
                 }
-            }
+            });
             var startPosition = 0;
             var updates = 0;
             await ConfigureWindows.GetMainWindow.Dispatcher.InvokeAsync(() =>
@@ -106,7 +105,8 @@ internal static class GalleryLoad
                 {
                     Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                 }
-                for (var x = startPosition; x < iterations; x++)
+
+                await Parallel.ForAsync(startPosition, iterations, source.Token, async (x, loopState) =>
                 {
                     updates++;
                     try
@@ -115,6 +115,7 @@ internal static class GalleryLoad
 
                         if (!IsLoading || Navigation.Pics.Count < Navigation.FolderIndex || Navigation.Pics.Count < 1 || i > Navigation.Pics.Count)
                         {
+                            loopState.ThrowIfCancellationRequested();
                             throw new TaskCanceledException();
                         }
                         var galleryThumbHolderItem = GalleryThumbHolder.GetThumbData(i);
@@ -133,9 +134,8 @@ internal static class GalleryLoad
                         Trace.WriteLine(e.Message);
 #endif
                         IsLoading = false;
-                        return;
                     }
-                }
+                });
             }, source.Token).ConfigureAwait(false);
 
             _ = Task.Run(async () =>

+ 9 - 7
src/PicView/PicView.csproj

@@ -181,19 +181,21 @@
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="Autoupdater.NET.Official" Version="1.8.4" />
-    <PackageReference Include="Magick.NET-Q16-OpenMP-x64" Version="13.2.0" />
-    <PackageReference Include="Magick.NET.SystemDrawing" Version="7.0.6">
+    <PackageReference Include="Magick.NET-Q8-OpenMP-x64" Version="13.3.0" />
+    <PackageReference Include="Magick.NET.SystemDrawing" Version="7.1.0">
       <TreatAsUsed>true</TreatAsUsed>
     </PackageReference>
-    <PackageReference Include="Magick.NET.SystemWindowsMedia" Version="7.0.6" />
+    <PackageReference Include="Magick.NET.SystemWindowsMedia" Version="7.1.0" />
     <PackageReference Include="Microsoft-WindowsAPICodePack-Core" Version="1.1.5">
       <TreatAsUsed>true</TreatAsUsed>
     </PackageReference>
     <PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
-    <PackageReference Include="SkiaSharp" Version="2.88.5">
+    <PackageReference Include="Microsoft.Win32.SystemEvents" Version="8.0.0-rc.2.23479.6" />
+    <PackageReference Include="SkiaSharp" Version="2.88.6">
       <TreatAsUsed>true</TreatAsUsed>
     </PackageReference>
-    <PackageReference Include="SkiaSharp.Views.WPF" Version="2.88.5" />
+    <PackageReference Include="SkiaSharp.Views.WPF" Version="2.88.6" />
+    <PackageReference Include="System.Drawing.Common" Version="8.0.0-rc.2.23479.14" />
     <PackageReference Include="XamlAnimatedGif" Version="2.2.0" />
   </ItemGroup>
   <ItemGroup>
@@ -334,15 +336,15 @@
     <AssemblyVersion>1.9.6</AssemblyVersion>
     <EnableNETAnalyzers>true</EnableNETAnalyzers>
     <EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
-    <TargetFramework>net7.0-windows10.0.22621.0</TargetFramework>
+    <TargetFramework>net8.0-windows</TargetFramework>
     <Nullable>enable</Nullable>
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <Description>Fast Picture Viewer with compact UI that can be hidden. </Description>
     <PackageTags>picture-viewer,desktop-app,</PackageTags>
-    <SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <ImplicitUsings>enable</ImplicitUsings>
     <ProduceReferenceAssembly>False</ProduceReferenceAssembly>
+    <PlatformTarget>x64</PlatformTarget>
   </PropertyGroup>
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>

+ 24 - 1
src/PicView/ProcessHandling/ProcessLogic.cs

@@ -1,7 +1,9 @@
-using PicView.ChangeImage;
+using System.ComponentModel;
+using PicView.ChangeImage;
 using PicView.Properties;
 using System.Diagnostics;
 using System.IO;
+using System.Security.Principal;
 using System.Windows;
 
 namespace PicView.ProcessHandling;
@@ -109,4 +111,25 @@ internal static class ProcessLogic
         };
         process.Start();
     }
+
+    internal static bool RunElevated(string fileName, string args)
+    {
+        var processInfo = new ProcessStartInfo
+        {
+            Verb = "runas",
+            UseShellExecute = true,
+            FileName = fileName,
+            Arguments = args
+        };
+        try
+        {
+            Process.Start(processInfo);
+            return true;
+        }
+        catch (Win32Exception)
+        {
+            // Do nothing. Probably the user canceled the UAC window
+        }
+        return false;
+    }
 }

+ 1 - 0
src/PicView/Shortcuts/MainKeyboardShortcuts.cs

@@ -11,6 +11,7 @@ using PicView.UILogic;
 using PicView.UILogic.Sizing;
 using System.Windows;
 using System.Windows.Input;
+using System.Windows.Media;
 using static PicView.ChangeImage.ErrorHandling;
 using static PicView.ChangeImage.Navigation;
 using static PicView.FileHandling.CopyPaste;

+ 15 - 15
src/PicView/SystemIntegration/LockScreenImage.cs

@@ -1,21 +1,28 @@
-using PicView.ChangeImage;
+using Microsoft.Win32;
+using PicView.ChangeImage;
 using PicView.ChangeTitlebar;
 using PicView.FileHandling;
 using PicView.ImageHandling;
 using PicView.UILogic;
 using System.Diagnostics;
 using System.IO;
+using System.Runtime.InteropServices;
 using System.Windows;
 using System.Windows.Input;
 using System.Windows.Media.Imaging;
-using Windows.Storage;
-using Windows.System.UserProfile;
+using PicView.ProcessHandling;
+
+//using Windows.Storage;
+//using Windows.System.UserProfile;
 using Rotation = PicView.UILogic.TransformImage.Rotation;
 
 namespace PicView.SystemIntegration;
 
 public static class LockScreenHelper
 {
+    [DllImport("kernel32.dll", SetLastError = true)]
+    public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); //If on 64 bit, C# will replace "System32" with "SysWOW64". This disables that.
+
     public static async Task<bool> SetLockScreenImageAsync(string? path = null)
     {
         var url = string.Empty;
@@ -26,7 +33,7 @@ public static class LockScreenHelper
             Application.Current.MainWindow!.Cursor = Cursors.Wait;
         });
 
-        string? folderPath, fileName;
+        string destinationPath;
         var hasEffect = ConfigureWindows.GetMainWindow.MainImage.Effect != null;
         var rotationAngle = Rotation.RotationAngle;
         var isFlipped = Rotation.IsFlipped;
@@ -59,8 +66,7 @@ public static class LockScreenHelper
         {
             // Create a temporary directory
             var tempDirectory = Path.GetTempPath();
-            var tempFileName = Path.GetRandomFileName();
-            var destinationPath = Path.Combine(tempDirectory, tempFileName);
+            destinationPath = Path.Combine(tempDirectory, Path.GetFileNameWithoutExtension(path) + ".jpg");
 
             BitmapSource? bitmapSource = null;
             string? imagePath = null;
@@ -75,24 +81,18 @@ public static class LockScreenHelper
             }
 
             await SaveImages.SaveImageAsync(rotationAngle, isFlipped, bitmapSource, imagePath, destinationPath, null, hasEffect).ConfigureAwait(false);
-
-            folderPath = Path.GetDirectoryName(destinationPath);
-            fileName = Path.GetFileName(destinationPath);
+            path = destinationPath;
         }
         else
         {
-            folderPath = Path.GetDirectoryName(Navigation.Pics[Navigation.FolderIndex]);
-            fileName = Path.GetFileName(Navigation.Pics[Navigation.FolderIndex]);
+            path = Navigation.Pics[Navigation.FolderIndex];
         }
 
         try
         {
             Tooltip.ShowTooltipMessage(Application.Current.Resources["Applying"]);
-            var storageFolder = await StorageFolder.GetFolderFromPathAsync(folderPath);
-            var imageFile = await storageFolder.GetFileAsync(fileName);
 
-            using var stream = await imageFile.OpenAsync(FileAccessMode.Read);
-            await LockScreen.SetImageStreamAsync(stream);
+            ProcessLogic.RunElevated("PicView.Tools.exe", "lockscreen," + path);
         }
         catch (Exception ex)
         {

+ 1 - 6
src/PicView/SystemIntegration/NativeMethods.cs

@@ -1,10 +1,5 @@
-using PicView.PicGallery;
-using PicView.Properties;
-using PicView.UILogic;
-using PicView.UILogic.Sizing;
-using System.Drawing;
+using System.Drawing;
 using System.Runtime.InteropServices;
-using System.Windows;
 
 namespace PicView.SystemIntegration;
 

+ 7 - 9
src/PicView/Views/Windows/EffectsWindows.xaml.cs

@@ -1,4 +1,5 @@
-using PicView.Editing.HlslEffects;
+using PicView.ConfigureSettings;
+using PicView.Editing.HlslEffects;
 using PicView.FileHandling;
 using PicView.Properties;
 using PicView.Shortcuts;
@@ -8,8 +9,6 @@ using PicView.UILogic.Sizing;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
-using PicView.ConfigureSettings;
-using WinRT;
 using static PicView.Animations.MouseOverAnimations;
 using static PicView.SystemIntegration.Wallpaper;
 
@@ -295,14 +294,13 @@ public partial class EffectsWindow : Window
         ConfigureWindows.GetMainWindow.MainImage.Effect = null;
         IntensitySlider.IsEnabled = false;
 
-        var list = EffectsContainer.Children.OfType<CheckBox>().Where(x => x.IsChecked == true);
-        var borders = EffectsContainer.Children.OfType<Border>();
-        foreach (var item in borders)
+        var list = EffectsContainer.Children.OfType<Border>();
+        foreach (var item in list)
         {
-            var checkbox = item.Child.As<CheckBox>();
-            if (checkbox is not null and { IsChecked: true })
+            var checkBox = (CheckBox)item.Child;
+            if (checkBox is not null and { IsChecked: true })
             {
-                checkbox.IsChecked = false;
+                checkBox.IsChecked = false;
                 value = true;
             }
         }

+ 2 - 1
src/PicView/Views/Windows/MainWindow.xaml

@@ -471,7 +471,8 @@
                         x:Name="MainImageBorder"
                         HorizontalAlignment="Center"
                         VerticalAlignment="Center"
-                        Focusable="False">
+                        Focusable="False"
+                        RenderOptions.BitmapScalingMode="Fant">
                         <Image
                             x:Name="MainImage"
                             AllowDrop="True"