diff --git a/dotnet/DesktopAgent/About.cs b/dotnet/DesktopAgent/About.cs index 7adc2d493..7f5d03bc1 100644 --- a/dotnet/DesktopAgent/About.cs +++ b/dotnet/DesktopAgent/About.cs @@ -11,32 +11,35 @@ internal class About : Form { public About() { - this.Text = Resources.lblAbout; - this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.StartPosition = FormStartPosition.CenterScreen; - this.MaximizeBox = this.MinimizeBox = false; - this.Icon = Resources.AppIcon; - this.ShowInTaskbar = false; - this.AutoSize = true; - this.AutoSizeMode = AutoSizeMode.GrowAndShrink; - this.MinimumSize = new Size(260, 100); - - using MemoryStream ms = new MemoryStream(Resources.devolutions_agent_icon_shadow); - - PictureBox pbLogo = new PictureBox() + Text = Resources.lblAbout; + FormBorderStyle = FormBorderStyle.FixedDialog; + StartPosition = FormStartPosition.CenterScreen; + MaximizeBox = MinimizeBox = false; + Icon = ImageResources.AppIcon; + ShowInTaskbar = false; + + AutoScaleMode = AutoScaleMode.Dpi; + AutoSize = true; + AutoSizeMode = AutoSizeMode.GrowAndShrink; + + MinimumSize = new Size(320, 180); + Padding = new Padding(12); + + DpiAwareImageBox pbLogo = new DpiAwareImageBox { - Image = Image.FromStream(ms), - SizeMode = PictureBoxSizeMode.Zoom, - Dock = DockStyle.Top, + Image = ImageResources.devolutions_agent_icon_shadow, + Dock = DockStyle.Fill, + MinimumSize = new Size(0, 96), }; - Label lblName = new Label() + Label lblName = new Label { - Text = Resources.lblProductName, - Dock = DockStyle.Top, - Height = 40, + Text = StaticResources.DevolutionsAgent, + AutoSize = true, TextAlign = ContentAlignment.MiddleCenter, - Font = new Font(Font.FontFamily, 12, FontStyle.Bold), + Dock = DockStyle.Fill, + Margin = new Padding(0, 0, 0, 6), + Font = new Font(Font.FontFamily, 12f, FontStyle.Bold), }; Version version = Assembly.GetExecutingAssembly().GetName().Version; @@ -44,34 +47,183 @@ public About() Label lblVersion = new Label { Text = $@"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}", - Dock = DockStyle.Top, - Height = 30, + AutoSize = true, TextAlign = ContentAlignment.MiddleCenter, + Dock = DockStyle.Fill, + Margin = new Padding(0, 0, 0, 6), }; Label lblVendor = new Label { - Text = Resources.lblVendor, - Dock = DockStyle.Top, + Text = StaticResources.DevolutionsInc, + AutoSize = true, TextAlign = ContentAlignment.MiddleCenter, - Font = new Font(Font.FontFamily, 7, FontStyle.Regular), + Dock = DockStyle.Fill, + Margin = new Padding(0, 0, 0, 2), + Font = new Font(Font.FontFamily, 8f, FontStyle.Regular), }; Label lblCopyright = new Label { Text = $@"{Resources.lblCopyright} © 2006 - {DateTime.Now.Year}", - Dock = DockStyle.Top, + AutoSize = true, TextAlign = ContentAlignment.MiddleCenter, - Font = new Font(Font.FontFamily, 7, FontStyle.Regular), + Dock = DockStyle.Fill, + Margin = new Padding(0, 0, 0, 0), + Font = new Font(Font.FontFamily, 8f, FontStyle.Regular), }; - this.Controls.Add(lblCopyright); - this.Controls.Add(lblVendor); - this.Controls.Add(lblVersion); - this.Controls.Add(lblName); - this.Controls.Add(pbLogo); + TableLayoutPanel layout = new TableLayoutPanel + { + Dock = DockStyle.Fill, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + ColumnCount = 1, + RowCount = 5, + Padding = new Padding(0), + Margin = new Padding(0), + }; + + layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); + + layout.Controls.Add(pbLogo, 0, 0); + layout.Controls.Add(lblName, 0, 1); + layout.Controls.Add(lblVersion, 0, 2); + layout.Controls.Add(lblVendor, 0, 3); + layout.Controls.Add(lblCopyright, 0, 4); + + Controls.Add(layout); + + FormClosed += (_, _) => DialogResult = DialogResult.OK; + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + + if (Utils.Theme() == Utils.ThemeMode.Dark) + { + Utils.UseImmersiveDarkMode(Handle, true); + DarkTheme.Apply(this); + } + } + } + + internal static class DarkTheme + { + public static readonly Color WindowBack = Color.FromArgb(32, 32, 32); + + public static readonly Color PanelBack = Color.FromArgb(32, 32, 32); + + public static readonly Color Text = Color.FromArgb(240, 240, 240); + + public static void Apply(Control root) + { + root.BackColor = WindowBack; + root.ForeColor = Text; + + ApplyToChildren(root); + } + + private static void ApplyToChildren(Control parent) + { + foreach (Control c in parent.Controls) + { + switch (c) + { + case LinkLabel link: + link.LinkColor = Text; + link.ActiveLinkColor = Text; + link.VisitedLinkColor = Text; + link.BackColor = Color.Transparent; + break; + + case Label lbl: + lbl.BackColor = Color.Transparent; + break; + + case TableLayoutPanel tlp: + tlp.BackColor = PanelBack; + break; + + case Panel p: + p.BackColor = PanelBack; + break; + + case Button btn: + btn.FlatStyle = FlatStyle.Flat; + btn.BackColor = Color.FromArgb(45, 45, 45); + btn.ForeColor = Text; + btn.FlatAppearance.BorderColor = Color.FromArgb(80, 80, 80); + btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(55, 55, 55); + btn.FlatAppearance.MouseDownBackColor = Color.FromArgb(65, 65, 65); + break; + + default: + c.BackColor = parent.BackColor; + c.ForeColor = parent.ForeColor; + break; + } + + if (c.HasChildren) + { + ApplyToChildren(c); + } + } + } + } + + internal sealed class DpiAwareImageBox : Control + { + private Image image; + + public Image Image + { + get => image; + set + { + image = value; + Invalidate(); + } + } + + public DpiAwareImageBox() + { + DoubleBuffered = true; + SetStyle(ControlStyles.ResizeRedraw, true); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (image == null) + return; + + e.Graphics.InterpolationMode = + System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + e.Graphics.SmoothingMode = + System.Drawing.Drawing2D.SmoothingMode.HighQuality; + e.Graphics.PixelOffsetMode = + System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; + + Rectangle dest = GetScaledRect(ClientRectangle, image.Size); + e.Graphics.DrawImage(image, dest); + } + + private static Rectangle GetScaledRect(Rectangle bounds, Size imageSize) + { + float ratio = Math.Min( + (float)bounds.Width / imageSize.Width, + (float)bounds.Height / imageSize.Height); + + int w = (int)(imageSize.Width * ratio); + int h = (int)(imageSize.Height * ratio); + + int x = bounds.X + (bounds.Width - w) / 2; + int y = bounds.Y + (bounds.Height - h) / 2; - this.FormClosed += (_, _) => this.DialogResult = DialogResult.OK; + return new Rectangle(x, y, w, h); } } } diff --git a/dotnet/DesktopAgent/App.config b/dotnet/DesktopAgent/App.config index 193aecc67..237403132 100644 --- a/dotnet/DesktopAgent/App.config +++ b/dotnet/DesktopAgent/App.config @@ -3,4 +3,8 @@ + + + + \ No newline at end of file diff --git a/dotnet/DesktopAgent/DesktopAgent.csproj b/dotnet/DesktopAgent/DesktopAgent.csproj index e0a84f3ad..d3fb89cb2 100644 --- a/dotnet/DesktopAgent/DesktopAgent.csproj +++ b/dotnet/DesktopAgent/DesktopAgent.csproj @@ -17,11 +17,13 @@ Resources\AppIcon.ico AnyCPU + app.manifest + @@ -37,16 +39,34 @@ + + True + True + ImageResources.resx + True True Resources.resx + + True + True + StaticResources.resx + + + ResXFileCodeGenerator + ImageResources.Designer.cs + ResXFileCodeGenerator Resources.Designer.cs + + ResXFileCodeGenerator + StaticResources.Designer.cs + \ No newline at end of file diff --git a/dotnet/DesktopAgent/Program.cs b/dotnet/DesktopAgent/Program.cs index a3b8f1c9c..406e32bf5 100644 --- a/dotnet/DesktopAgent/Program.cs +++ b/dotnet/DesktopAgent/Program.cs @@ -106,6 +106,8 @@ private static void Application_OnIdle(object sender, EventArgs e) public class AppContext : ApplicationContext { + private readonly RootConfig config; + private readonly ContextMenu contextMenu; private readonly SynchronizationContext synchronizationContext; @@ -114,6 +116,8 @@ public class AppContext : ApplicationContext public AppContext() { + config = Utils.LoadConfig(); + Version version = Assembly.GetExecutingAssembly().GetName().Version; this.synchronizationContext = new WindowsFormsSynchronizationContext(); @@ -121,15 +125,17 @@ public AppContext() this.contextMenu.Popup += ContextMenuOnPopup; this.trayIcon = new NotifyIcon() { - Icon = Resources.AppIcon, + Icon = ImageResources.AppIcon, ContextMenu = contextMenu, - Text = $"{Resources.lblProductName} v{version.Major}.{version.Minor}.{version.Build}", + Text = $"{StaticResources.DevolutionsAgent} v{version.Major}.{version.Minor}.{version.Build}", Visible = true, }; } private void ContextMenuOnPopup(object sender, EventArgs e) { + bool ctrl = (Control.ModifierKeys & Keys.Control) == Keys.Control; + this.contextMenu.MenuItems.Clear(); this.contextMenu.MenuItems.Add(Resources.mnuAbout, (_, _) => @@ -139,57 +145,71 @@ private void ContextMenuOnPopup(object sender, EventArgs e) }); this.contextMenu.MenuItems.Add(new MenuItem("-")); + this.contextMenu.MenuItems.Add(new MenuItem(Utils.IsServiceRunning("DevolutionsAgent") ? Resources.mnuServiceAvailable : Resources.mnuServiceUnavailable) { Enabled = false }); - if (Client.Available) + if (ctrl) { - List<(long, string)> profiles = new List<(long, string)>(); - profiles.Add((0, Resources.mnuProfileNone)); - - MenuItem mnuProfiles = new MenuItem(Resources.mnuProfiles); + this.contextMenu.MenuItems.Add(new MenuItem("-")); + this.contextMenu.MenuItems.Add(new MenuItem("Updater") { Enabled = false, Checked = config?.Updater?.Enabled ?? false }); + this.contextMenu.MenuItems.Add(new MenuItem("Session") { Enabled = false, Checked = config?.Session?.Enabled ?? false }); + this.contextMenu.MenuItems.Add(new MenuItem("PEDM") { Enabled = false, Checked = config?.Pedm?.Enabled ?? false }); + } - GetProfilesMeResponse currentProfiles = null; + if (config?.Pedm?.Enabled ?? false) + { + this.contextMenu.MenuItems.Add(new MenuItem("-")); - try + if (Client.Available) { - currentProfiles = Client.CurrentProfiles(); - profiles.AddRange(currentProfiles.Available.Select(z => (z, Client.GetProfile(z).Name))); - } - catch (Exception exception) - { - Program.Log.Error(exception.ToString()); - } + List<(long, string)> profiles = new List<(long, string)>(); + profiles.Add((0, Resources.mnuProfileNone)); - foreach (var profile in profiles) - { - MenuItem mnuProfile = new MenuItem(profile.Item2); - mnuProfile.Tag = profile.Item1; + MenuItem mnuProfiles = new MenuItem(Resources.mnuProfiles); - if (profile.Item1 == currentProfiles?.Active) + GetProfilesMeResponse currentProfiles = null; + + try + { + currentProfiles = Client.CurrentProfiles(); + profiles.AddRange(currentProfiles.Available.Select(z => (z, Client.GetProfile(z).Name))); + } + catch (Exception exception) { - mnuProfile.Checked = true; + Program.Log.Error(exception.ToString()); } - mnuProfile.Click += (o, _) => + foreach (var profile in profiles) { - try + MenuItem mnuProfile = new MenuItem(profile.Item2); + mnuProfile.Tag = profile.Item1; + + if (profile.Item1 == currentProfiles?.Active) { - long profileId = (long)((MenuItem) o).Tag; - Client.SetCurrentProfile(profileId); + mnuProfile.Checked = true; } - catch (Exception exception) + + mnuProfile.Click += (o, _) => { - Program.Log.Error(exception.ToString()); - } - }; + try + { + long profileId = (long)((MenuItem)o).Tag; + Client.SetCurrentProfile(profileId); + } + catch (Exception exception) + { + Program.Log.Error(exception.ToString()); + } + }; - mnuProfiles.MenuItems.Add(mnuProfile); - } + mnuProfiles.MenuItems.Add(mnuProfile); + } - this.contextMenu.MenuItems.Add(mnuProfiles); - } - else - { - this.contextMenu.MenuItems.Add(new MenuItem(Resources.mnuServiceUnavailable) { Enabled = false }); + this.contextMenu.MenuItems.Add(mnuProfiles); + } + else + { + this.contextMenu.MenuItems.Add(new MenuItem(Resources.mnuPEDMUnavailable) { Enabled = false }); + } } this.contextMenu.MenuItems.Add(new MenuItem("-")); diff --git a/dotnet/DesktopAgent/Properties/ImageResources.Designer.cs b/dotnet/DesktopAgent/Properties/ImageResources.Designer.cs new file mode 100644 index 000000000..a42dc35ff --- /dev/null +++ b/dotnet/DesktopAgent/Properties/ImageResources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Devolutions.Agent.Desktop.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ImageResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ImageResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Devolutions.Agent.Desktop.Properties.ImageResources", typeof(ImageResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon AppIcon { + get { + object obj = ResourceManager.GetObject("AppIcon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap devolutions_agent_icon_shadow { + get { + object obj = ResourceManager.GetObject("devolutions-agent-icon-shadow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/dotnet/DesktopAgent/Properties/ImageResources.resx b/dotnet/DesktopAgent/Properties/ImageResources.resx new file mode 100644 index 000000000..4e7dd8aae --- /dev/null +++ b/dotnet/DesktopAgent/Properties/ImageResources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\AppIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\devolutions-agent-icon-shadow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/dotnet/DesktopAgent/Properties/Resources.Designer.cs b/dotnet/DesktopAgent/Properties/Resources.Designer.cs index bb8061213..d3d93d83d 100644 --- a/dotnet/DesktopAgent/Properties/Resources.Designer.cs +++ b/dotnet/DesktopAgent/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Devolutions.Agent.Desktop.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,26 +60,6 @@ internal Resources() { } } - /// - /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). - /// - internal static System.Drawing.Icon AppIcon { - get { - object obj = ResourceManager.GetObject("AppIcon", resourceCulture); - return ((System.Drawing.Icon)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] devolutions_agent_icon_shadow { - get { - object obj = ResourceManager.GetObject("devolutions-agent-icon-shadow", resourceCulture); - return ((byte[])(obj)); - } - } - /// /// Looks up a localized string similar to About. /// @@ -98,24 +78,6 @@ internal static string lblCopyright { } } - /// - /// Looks up a localized string similar to Devolutions Agent. - /// - internal static string lblProductName { - get { - return ResourceManager.GetString("lblProductName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Devolutions Inc.. - /// - internal static string lblVendor { - get { - return ResourceManager.GetString("lblVendor", resourceCulture); - } - } - /// /// Looks up a localized string similar to About. /// @@ -134,6 +96,15 @@ internal static string mnuExit { } } + /// + /// Looks up a localized string similar to PEDM unavailable. + /// + internal static string mnuPEDMUnavailable { + get { + return ResourceManager.GetString("mnuPEDMUnavailable", resourceCulture); + } + } + /// /// Looks up a localized string similar to None. /// @@ -152,6 +123,15 @@ internal static string mnuProfiles { } } + /// + /// Looks up a localized string similar to Service running. + /// + internal static string mnuServiceAvailable { + get { + return ResourceManager.GetString("mnuServiceAvailable", resourceCulture); + } + } + /// /// Looks up a localized string similar to Service unavailable. /// diff --git a/dotnet/DesktopAgent/Properties/Resources.fr.resx b/dotnet/DesktopAgent/Properties/Resources.fr.resx new file mode 100644 index 000000000..b30905c19 --- /dev/null +++ b/dotnet/DesktopAgent/Properties/Resources.fr.resx @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + À propos + + + Tous droits réservés + + + À propos + + + Quitter + + + Aucun + + + Profils + + + Service indisponible + + + Élévation bloquée + + + Élévation bloquée par le profil actuellement sélectionné + + + Échec de l’élévation + + + Erreur inattendue + + + Une erreur inattendue s’est produite + + + PEDM indisponible + + + Service en cours d’exécution + + \ No newline at end of file diff --git a/dotnet/DesktopAgent/Properties/Resources.resx b/dotnet/DesktopAgent/Properties/Resources.resx index 158883a40..84a75d0b2 100644 --- a/dotnet/DesktopAgent/Properties/Resources.resx +++ b/dotnet/DesktopAgent/Properties/Resources.resx @@ -117,25 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\AppIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\devolutions-agent-icon-shadow.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - About Copyright - - Devolutions Agent - - - Devolutions Inc. - About @@ -166,4 +153,10 @@ An unexpected error occurred + + PEDM unavailable + + + Service running + \ No newline at end of file diff --git a/dotnet/DesktopAgent/Properties/StaticResources.Designer.cs b/dotnet/DesktopAgent/Properties/StaticResources.Designer.cs new file mode 100644 index 000000000..2dfe0619a --- /dev/null +++ b/dotnet/DesktopAgent/Properties/StaticResources.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Devolutions.Agent.Desktop.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class StaticResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal StaticResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Devolutions.Agent.Desktop.Properties.StaticResources", typeof(StaticResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Devolutions Agent. + /// + internal static string DevolutionsAgent { + get { + return ResourceManager.GetString("DevolutionsAgent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Devolutions Inc.. + /// + internal static string DevolutionsInc { + get { + return ResourceManager.GetString("DevolutionsInc", resourceCulture); + } + } + } +} diff --git a/dotnet/DesktopAgent/Properties/StaticResources.resx b/dotnet/DesktopAgent/Properties/StaticResources.resx new file mode 100644 index 000000000..d26a1f889 --- /dev/null +++ b/dotnet/DesktopAgent/Properties/StaticResources.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Devolutions Agent + + + Devolutions Inc. + + \ No newline at end of file diff --git a/dotnet/DesktopAgent/Utils/Config.cs b/dotnet/DesktopAgent/Utils/Config.cs new file mode 100644 index 000000000..53bb0af82 --- /dev/null +++ b/dotnet/DesktopAgent/Utils/Config.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Text; + +namespace Devolutions.Agent.Desktop +{ + internal partial class Utils + { + internal static RootConfig LoadConfig() + { + try + { + string programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + string path = Path.Combine(programData, "Devolutions", "Agent", "agent.json"); + string json = File.ReadAllText(path); + + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(RootConfig)); + + using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) + { + return (RootConfig)serializer.ReadObject(ms); + } + } + catch + { + return null; + } + } + } + + [DataContract] + internal class RootConfig + { + [DataMember] + public Feature Updater { get; set; } + + [DataMember] + public Feature Session { get; set; } + + [DataMember] + public Feature Pedm { get; set; } + } + + [DataContract] + internal class Feature + { + [DataMember] + public bool Enabled { get; set; } + } +} diff --git a/dotnet/DesktopAgent/Utils/Service.cs b/dotnet/DesktopAgent/Utils/Service.cs new file mode 100644 index 000000000..8e4b2663b --- /dev/null +++ b/dotnet/DesktopAgent/Utils/Service.cs @@ -0,0 +1,22 @@ +using System.ServiceProcess; + +namespace Devolutions.Agent.Desktop +{ + internal partial class Utils + { + public static bool IsServiceRunning(string serviceName) + { + using (ServiceController sc = new ServiceController(serviceName)) + { + try + { + return sc.Status == ServiceControllerStatus.Running; + } + catch + { + return false; + } + } + } + } +} diff --git a/dotnet/DesktopAgent/Utils/UI.cs b/dotnet/DesktopAgent/Utils/UI.cs new file mode 100644 index 000000000..bff0ae99d --- /dev/null +++ b/dotnet/DesktopAgent/Utils/UI.cs @@ -0,0 +1,64 @@ +using Microsoft.Win32; +using System; +using System.Runtime.InteropServices; + +namespace Devolutions.Agent.Desktop +{ + internal partial class Utils + { + internal enum ThemeMode + { + Dark = 0, + Light = 1, + Unknown, + } + + [DllImport("dwmapi.dll")] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); + + private const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19; + + private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; + + internal static bool UseImmersiveDarkMode(IntPtr handle, bool enabled) + { + if (Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 17763) + { + int attribute = Environment.OSVersion.Version.Build >= 18985 ? DWMWA_USE_IMMERSIVE_DARK_MODE : DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1; + int useImmersiveDarkMode = enabled ? 1 : 0; + + try + { + return DwmSetWindowAttribute(handle, attribute, ref useImmersiveDarkMode, sizeof(int)) == 0; + } + catch + { + return false; + } + } + + return false; + } + + public static ThemeMode Theme() + { + string keyName = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"; + + try + { + int raw = (int)Registry.GetValue(keyName, "AppsUseLightTheme", -1); + + return raw switch + { + 0 => ThemeMode.Dark, + 1 => ThemeMode.Light, + _ => ThemeMode.Unknown + }; + } + catch + { + return ThemeMode.Unknown; + } + } + } +} diff --git a/dotnet/DesktopAgent/app.manifest b/dotnet/DesktopAgent/app.manifest new file mode 100644 index 000000000..9d466577e --- /dev/null +++ b/dotnet/DesktopAgent/app.manifest @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + PerMonitorV2 + + + + + + + + diff --git a/package/AgentWindowsManaged/Program.cs b/package/AgentWindowsManaged/Program.cs index bfb457806..f6fc3e15e 100644 --- a/package/AgentWindowsManaged/Program.cs +++ b/package/AgentWindowsManaged/Program.cs @@ -287,7 +287,7 @@ static void Main() }, Dirs = new[] { - new Dir(Features.PEDM_FEATURE, "desktop", new Files(Features.PEDM_FEATURE, $"{DevolutionsDesktopAgentPath}\\*.*")), + new Dir(Features.AGENT_FEATURE, "desktop", new Files(Features.AGENT_FEATURE, $"{DevolutionsDesktopAgentPath}\\*.*")), new Dir(Features.PEDM_FEATURE, "ShellExt", new File(Features.PEDM_FEATURE, DevolutionsPedmShellExtDll), new File(Features.PEDM_FEATURE, DevolutionsPedmShellExtMsix)), @@ -314,7 +314,7 @@ static void Main() { Win64 = project.Platform == Platform.x64, RegistryKeyAction = RegistryKeyAction.create, - Feature = Features.PEDM_FEATURE, + Feature = Features.AGENT_FEATURE, } };