From 8c2edd69ffe07b213d94dc97fc7e8c209654d8d6 Mon Sep 17 00:00:00 2001 From: sleevezipper Date: Thu, 31 Dec 2020 03:57:40 +0100 Subject: [PATCH] add a simple ui to configure the broker --- .../DesignTimeBuild/.dtbcache.v2 | Bin 125071 -> 152374 bytes .vs/hass-workstation-service/v16/.suo | Bin 164352 -> 230912 bytes UserInterface/.gitignore | 25 ++ UserInterface/App.axaml | 13 + UserInterface/App.axaml.cs | 29 ++ .../Assets/hass-workstation-logo.ico | Bin 0 -> 70250 bytes UserInterface/ITrayIcon.cs | 13 + UserInterface/Program.cs | 24 ++ .../PublishProfiles/FolderProfile.pubxml | 17 + .../PublishProfiles/FolderProfile.pubxml.user | 6 + UserInterface/UserInterface.csproj | 28 ++ UserInterface/UserInterface.csproj.user | 6 + UserInterface/ViewLocator.cs | 32 ++ .../ViewModels/BrokerSettingsViewModel.cs | 13 + .../ViewModels/MainWindowViewModel.cs | 11 + UserInterface/ViewModels/ViewModelBase.cs | 11 + .../Views/BrokerSettings/BrokerSettings.axaml | 17 + .../BrokerSettings/BrokerSettings.axaml.cs | 56 +++ UserInterface/Views/MainWindow.axaml | 20 + UserInterface/Views/MainWindow.axaml.cs | 22 + UserInterface/Win/Interop/BalloonFlags.cs | 61 +++ UserInterface/Win/Interop/IconDataMembers.cs | 70 +++ UserInterface/Win/Interop/IconState.cs | 22 + UserInterface/Win/Interop/MouseEvent.cs | 54 +++ UserInterface/Win/Interop/NotifyCommand.cs | 41 ++ UserInterface/Win/Interop/NotifyIconData.cs | 154 +++++++ .../Win/Interop/NotifyIconVersion.cs | 15 + UserInterface/Win/Interop/WinApi.cs | 59 +++ UserInterface/Win/Interop/WindowClass.cs | 35 ++ .../Win/Interop/WindowMessageSink.cs | 357 ++++++++++++++++ UserInterface/Win/Interop/WindowsMessages.cs | 190 +++++++++ UserInterface/Win/NotifyIcon.cs | 403 ++++++++++++++++++ UserInterface/Win/WindowsTrayIcon.cs | 62 +++ UserInterface/nuget.config | 11 + hass-workstation-service.sln | 10 + .../ServiceContractInterfaces.cs | 12 + .../Communication/MQTT/MqttPublisher.cs | 48 ++- .../Data/ConfigurationService.cs | 42 +- .../Data/ConfiguredMqttBroker.cs | 2 +- .../Data/IConfigurationService.cs | 24 ++ hass-workstation-service/Program.cs | 10 +- .../PublishProfiles/ClickOnceProfile.pubxml | 2 +- hass-workstation-service/Worker.cs | 4 +- .../hass-workstation-service.csproj | 5 +- 44 files changed, 2015 insertions(+), 21 deletions(-) create mode 100644 UserInterface/.gitignore create mode 100644 UserInterface/App.axaml create mode 100644 UserInterface/App.axaml.cs create mode 100644 UserInterface/Assets/hass-workstation-logo.ico create mode 100644 UserInterface/ITrayIcon.cs create mode 100644 UserInterface/Program.cs create mode 100644 UserInterface/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 UserInterface/Properties/PublishProfiles/FolderProfile.pubxml.user create mode 100644 UserInterface/UserInterface.csproj create mode 100644 UserInterface/UserInterface.csproj.user create mode 100644 UserInterface/ViewLocator.cs create mode 100644 UserInterface/ViewModels/BrokerSettingsViewModel.cs create mode 100644 UserInterface/ViewModels/MainWindowViewModel.cs create mode 100644 UserInterface/ViewModels/ViewModelBase.cs create mode 100644 UserInterface/Views/BrokerSettings/BrokerSettings.axaml create mode 100644 UserInterface/Views/BrokerSettings/BrokerSettings.axaml.cs create mode 100644 UserInterface/Views/MainWindow.axaml create mode 100644 UserInterface/Views/MainWindow.axaml.cs create mode 100644 UserInterface/Win/Interop/BalloonFlags.cs create mode 100644 UserInterface/Win/Interop/IconDataMembers.cs create mode 100644 UserInterface/Win/Interop/IconState.cs create mode 100644 UserInterface/Win/Interop/MouseEvent.cs create mode 100644 UserInterface/Win/Interop/NotifyCommand.cs create mode 100644 UserInterface/Win/Interop/NotifyIconData.cs create mode 100644 UserInterface/Win/Interop/NotifyIconVersion.cs create mode 100644 UserInterface/Win/Interop/WinApi.cs create mode 100644 UserInterface/Win/Interop/WindowClass.cs create mode 100644 UserInterface/Win/Interop/WindowMessageSink.cs create mode 100644 UserInterface/Win/Interop/WindowsMessages.cs create mode 100644 UserInterface/Win/NotifyIcon.cs create mode 100644 UserInterface/Win/WindowsTrayIcon.cs create mode 100644 UserInterface/nuget.config create mode 100644 hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs create mode 100644 hass-workstation-service/Data/IConfigurationService.cs diff --git a/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 b/.vs/hass-workstation-service/DesignTimeBuild/.dtbcache.v2 index bdb375a5b9a4f799bf681ef097ac67cf8ba21a6f..4e4a2cb27fa30395650ac36f5aea8606f52a57a3 100644 GIT binary patch literal 152374 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 diff --git a/.vs/hass-workstation-service/v16/.suo b/.vs/hass-workstation-service/v16/.suo index 9a5ddda1ca753f335c0af707443f75743e252154..fd6daf597272702fdd2d9f7c3c51c7b017c57955 100644 GIT binary patch literal 230912 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 + + + + + + + + + diff --git a/UserInterface/App.axaml.cs b/UserInterface/App.axaml.cs new file mode 100644 index 0000000..eaa87a9 --- /dev/null +++ b/UserInterface/App.axaml.cs @@ -0,0 +1,29 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using UserInterface.ViewModels; +using UserInterface.Views; + +namespace UserInterface +{ + public class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow + { + DataContext = new MainWindowViewModel(), + }; + } + + base.OnFrameworkInitializationCompleted(); + } + } +} diff --git a/UserInterface/Assets/hass-workstation-logo.ico b/UserInterface/Assets/hass-workstation-logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..323eb647267a5a16654f169cc1a49badc76c244b GIT binary patch literal 70250 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

oy@TWd*^E38HXeq|m`Go^}%~-s6GU70D?? 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 literal 0 HcmV?d00001 diff --git a/UserInterface/ITrayIcon.cs b/UserInterface/ITrayIcon.cs new file mode 100644 index 0000000..ff33265 --- /dev/null +++ b/UserInterface/ITrayIcon.cs @@ -0,0 +1,13 @@ +namespace MangaReader.Avalonia.Platform +{ + public interface ITrayIcon : System.IDisposable + { + System.Windows.Input.ICommand DoubleClickCommand { get; set; } + + System.Windows.Input.ICommand BalloonClickedCommand { get; set; } + + void SetIcon(); + + void ShowBalloon(string text, object state); + } +} diff --git a/UserInterface/Program.cs b/UserInterface/Program.cs new file mode 100644 index 0000000..bef6f96 --- /dev/null +++ b/UserInterface/Program.cs @@ -0,0 +1,24 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Logging.Serilog; +using Avalonia.ReactiveUI; +using System; + +namespace UserInterface +{ + class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .LogToDebug() + .UseReactiveUI(); + } +} diff --git a/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml b/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..bac3ebc --- /dev/null +++ b/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,17 @@ + + + + + Release + Any CPU + bin\Release\netcoreapp3.1\publish\ + FileSystem + netcoreapp3.1 + win-x64 + false + True + False + + \ No newline at end of file diff --git a/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml.user b/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..312c6e3 --- /dev/null +++ b/UserInterface/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/UserInterface/UserInterface.csproj b/UserInterface/UserInterface.csproj new file mode 100644 index 0000000..94e5121 --- /dev/null +++ b/UserInterface/UserInterface.csproj @@ -0,0 +1,28 @@ + + + WinExe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + + + %(Filename) + + + diff --git a/UserInterface/UserInterface.csproj.user b/UserInterface/UserInterface.csproj.user new file mode 100644 index 0000000..3d9bdf3 --- /dev/null +++ b/UserInterface/UserInterface.csproj.user @@ -0,0 +1,6 @@ + + + + <_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\UserInterface\Properties\PublishProfiles\FolderProfile.pubxml + + \ No newline at end of file diff --git a/UserInterface/ViewLocator.cs b/UserInterface/ViewLocator.cs new file mode 100644 index 0000000..4a3da86 --- /dev/null +++ b/UserInterface/ViewLocator.cs @@ -0,0 +1,32 @@ +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using System; +using UserInterface.ViewModels; + +namespace UserInterface +{ + public class ViewLocator : IDataTemplate + { + public bool SupportsRecycling => false; + + public IControl Build(object data) + { + var name = data.GetType().FullName.Replace("ViewModel", "View"); + var type = Type.GetType(name); + + if (type != null) + { + return (Control)Activator.CreateInstance(type); + } + else + { + return new TextBlock { Text = "Not Found: " + name }; + } + } + + public bool Match(object data) + { + return data is ViewModelBase; + } + } +} \ No newline at end of file diff --git a/UserInterface/ViewModels/BrokerSettingsViewModel.cs b/UserInterface/ViewModels/BrokerSettingsViewModel.cs new file mode 100644 index 0000000..f57b81a --- /dev/null +++ b/UserInterface/ViewModels/BrokerSettingsViewModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UserInterface.ViewModels +{ + public class BrokerSettingsViewModel : ViewModelBase + { + public string Host { get; set; } + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/UserInterface/ViewModels/MainWindowViewModel.cs b/UserInterface/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..667fc49 --- /dev/null +++ b/UserInterface/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UserInterface.ViewModels +{ + public class MainWindowViewModel : ViewModelBase + { + public string Greeting => "Welcome to Avalonia!"; + } +} diff --git a/UserInterface/ViewModels/ViewModelBase.cs b/UserInterface/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..987b7c8 --- /dev/null +++ b/UserInterface/ViewModels/ViewModelBase.cs @@ -0,0 +1,11 @@ +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Text; + +namespace UserInterface.ViewModels +{ + public class ViewModelBase : ReactiveObject + { + } +} diff --git a/UserInterface/Views/BrokerSettings/BrokerSettings.axaml b/UserInterface/Views/BrokerSettings/BrokerSettings.axaml new file mode 100644 index 0000000..110b651 --- /dev/null +++ b/UserInterface/Views/BrokerSettings/BrokerSettings.axaml @@ -0,0 +1,17 @@ + + + Mqtt broker + IP or hostname + + Username + + Password + + + + diff --git a/UserInterface/Views/BrokerSettings/BrokerSettings.axaml.cs b/UserInterface/Views/BrokerSettings/BrokerSettings.axaml.cs new file mode 100644 index 0000000..75ff0f3 --- /dev/null +++ b/UserInterface/Views/BrokerSettings/BrokerSettings.axaml.cs @@ -0,0 +1,56 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Microsoft.Extensions.DependencyInjection; +using hass_workstation_service.Communication.NamedPipe; +using JKang.IpcServiceFramework.Client; +using System.Threading.Tasks; +using Avalonia.Interactivity; +using System.Reactive.Linq; +using UserInterface.ViewModels; +using System.Security; + +namespace UserInterface.Views +{ + public class BrokerSettings : UserControl + { + private readonly IIpcClient client; + private string _host { get; set; } + private string _username { get; set; } + private string _password { get; set; } + public BrokerSettings() + { + DataContext = new BrokerSettingsViewModel(); + this.InitializeComponent(); + // register IPC clients + ServiceProvider serviceProvider = new ServiceCollection() + .AddNamedPipeIpcClient("client1", pipeName: "pipeinternal") + .BuildServiceProvider(); + + // resolve IPC client factory + IIpcClientFactory clientFactory = serviceProvider + .GetRequiredService>(); + + // create client + this.client = clientFactory.CreateClient("client1"); + + } + public void Ping(object sender, RoutedEventArgs args) { + var result = this.client.InvokeAsync(x => x.Ping("ping")).Result; + } + + public void Configure(object sender, RoutedEventArgs args) + { + var model = (BrokerSettingsViewModel)this.DataContext; + var result = this.client.InvokeAsync(x => x.WriteMqttBrokerSettings(model.Host, model.Username, model.Password)); + } + + + + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/UserInterface/Views/MainWindow.axaml b/UserInterface/Views/MainWindow.axaml new file mode 100644 index 0000000..f154da4 --- /dev/null +++ b/UserInterface/Views/MainWindow.axaml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/UserInterface/Views/MainWindow.axaml.cs b/UserInterface/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..55de57f --- /dev/null +++ b/UserInterface/Views/MainWindow.axaml.cs @@ -0,0 +1,22 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UserInterface.Views +{ + public class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/UserInterface/Win/Interop/BalloonFlags.cs b/UserInterface/Win/Interop/BalloonFlags.cs new file mode 100644 index 0000000..119e0fe --- /dev/null +++ b/UserInterface/Win/Interop/BalloonFlags.cs @@ -0,0 +1,61 @@ +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + ///

+ /// Flags that define the icon that is shown on a balloon + /// tooltip. + /// + public enum BalloonFlags + { + /// + /// No icon is displayed. + /// + None = 0x00, + + /// + /// An information icon is displayed. + /// + Info = 0x01, + + /// + /// A warning icon is displayed. + /// + Warning = 0x02, + + /// + /// An error icon is displayed. + /// + Error = 0x03, + + /// + /// Windows XP Service Pack 2 (SP2) and later. + /// Use a custom icon as the title icon. + /// + User = 0x04, + + /// + /// Windows XP (Shell32.dll version 6.0) and later. + /// Do not play the associated sound. Applies only to balloon ToolTips. + /// + NoSound = 0x10, + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. The large version + /// of the icon should be used as the balloon icon. This corresponds to the + /// icon with dimensions SM_CXICON x SM_CYICON. If this flag is not set, + /// the icon with dimensions XM_CXSMICON x SM_CYSMICON is used.
+ /// - This flag can be used with all stock icons.
+ /// - Applications that use older customized icons (NIIF_USER with hIcon) must + /// provide a new SM_CXICON x SM_CYICON version in the tray icon (hIcon). These + /// icons are scaled down when they are displayed in the System Tray or + /// System Control Area (SCA).
+ /// - New customized icons (NIIF_USER with hBalloonIcon) must supply an + /// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon). + ///
+ LargeIcon = 0x20, + + /// + /// Windows 7 and later. + /// + RespectQuietTime = 0x80 + } +} diff --git a/UserInterface/Win/Interop/IconDataMembers.cs b/UserInterface/Win/Interop/IconDataMembers.cs new file mode 100644 index 0000000..fb92b20 --- /dev/null +++ b/UserInterface/Win/Interop/IconDataMembers.cs @@ -0,0 +1,70 @@ +using System; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Indicates which members of a structure + /// were set, and thus contain valid data or provide additional information + /// to the ToolTip as to how it should display. + /// + [Flags] + public enum IconDataMembers + { + /// + /// The message ID is set. + /// + Message = 0x01, + + /// + /// The notification icon is set. + /// + Icon = 0x02, + + /// + /// The tooltip is set. + /// + Tip = 0x04, + + /// + /// State information () is set. This + /// applies to both and + /// . + /// + State = 0x08, + + /// + /// The balloon ToolTip is set. Accordingly, the following + /// members are set: , + /// , , + /// and . + /// + Info = 0x10, + + // Internal identifier is set. Reserved, thus commented out. + //Guid = 0x20, + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. If the ToolTip + /// cannot be displayed immediately, discard it.
+ /// Use this flag for ToolTips that represent real-time information which + /// would be meaningless or misleading if displayed at a later time. + /// For example, a message that states "Your telephone is ringing."
+ /// This modifies and must be combined with the flag. + ///
+ Realtime = 0x40, + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. + /// Use the standard ToolTip. Normally, when uVersion is set + /// to NOTIFYICON_VERSION_4, the standard ToolTip is replaced + /// by the application-drawn pop-up user interface (UI). + /// If the application wants to show the standard tooltip + /// in that case, regardless of whether the on-hover UI is showing, + /// it can specify NIF_SHOWTIP to indicate the standard tooltip + /// should still be shown.
+ /// Note that the NIF_SHOWTIP flag is effective until the next call + /// to Shell_NotifyIcon. + ///
+ UseLegacyToolTips = 0x80 + } +} diff --git a/UserInterface/Win/Interop/IconState.cs b/UserInterface/Win/Interop/IconState.cs new file mode 100644 index 0000000..7e1dc20 --- /dev/null +++ b/UserInterface/Win/Interop/IconState.cs @@ -0,0 +1,22 @@ +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// The state of the icon - can be set to + /// hide the icon. + /// + public enum IconState + { + /// + /// The icon is visible. + /// + Visible = 0x00, + + /// + /// Hide the icon. + /// + Hidden = 0x01, + + // The icon is shared - currently not supported, thus commented out. + //Shared = 0x02 + } +} diff --git a/UserInterface/Win/Interop/MouseEvent.cs b/UserInterface/Win/Interop/MouseEvent.cs new file mode 100644 index 0000000..a0e5b7a --- /dev/null +++ b/UserInterface/Win/Interop/MouseEvent.cs @@ -0,0 +1,54 @@ +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Event flags for clicked events. + /// + public enum MouseEvent + { + /// + /// The mouse was moved withing the + /// taskbar icon's area. + /// + MouseMove, + + /// + /// The right mouse button was clicked. + /// + IconRightMouseDown, + + /// + /// The left mouse button was clicked. + /// + IconLeftMouseDown, + + /// + /// The right mouse button was released. + /// + IconRightMouseUp, + + /// + /// The left mouse button was released. + /// + IconLeftMouseUp, + + /// + /// The middle mouse button was clicked. + /// + IconMiddleMouseDown, + + /// + /// The middle mouse button was released. + /// + IconMiddleMouseUp, + + /// + /// The taskbar icon was double clicked. + /// + IconDoubleClick, + + /// + /// The balloon tip was clicked. + /// + BalloonToolTipClicked + } +} diff --git a/UserInterface/Win/Interop/NotifyCommand.cs b/UserInterface/Win/Interop/NotifyCommand.cs new file mode 100644 index 0000000..b0ebe00 --- /dev/null +++ b/UserInterface/Win/Interop/NotifyCommand.cs @@ -0,0 +1,41 @@ +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Main operations performed on the + /// function. + /// + public enum NotifyCommand + { + /// + /// The taskbar icon is being created. + /// + Add = 0x00, + + /// + /// The settings of the taskbar icon are being updated. + /// + Modify = 0x01, + + /// + /// The taskbar icon is deleted. + /// + Delete = 0x02, + + /// + /// Focus is returned to the taskbar icon. Currently not in use. + /// + SetFocus = 0x03, + + /// + /// Shell32.dll version 5.0 and later only. Instructs the taskbar + /// to behave according to the version number specified in the + /// uVersion member of the structure pointed to by lpdata. + /// This message allows you to specify whether you want the version + /// 5.0 behavior found on Microsoft Windows 2000 systems, or the + /// behavior found on earlier Shell versions. The default value for + /// uVersion is zero, indicating that the original Windows 95 notify + /// icon behavior should be used. + /// + SetVersion = 0x04 + } +} diff --git a/UserInterface/Win/Interop/NotifyIconData.cs b/UserInterface/Win/Interop/NotifyIconData.cs new file mode 100644 index 0000000..37ba684 --- /dev/null +++ b/UserInterface/Win/Interop/NotifyIconData.cs @@ -0,0 +1,154 @@ +using System; +using System.Runtime.InteropServices; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// A struct that is submitted in order to configure + /// the taskbar icon. Provides various members that + /// can be configured partially, according to the + /// values of the + /// that were defined. + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct NotifyIconData + { + /// + /// Size of this structure, in bytes. + /// + public uint cbSize; + + /// + /// Handle to the window that receives notification messages associated with an icon in the + /// taskbar status area. The Shell uses hWnd and uID to identify which icon to operate on + /// when Shell_NotifyIcon is invoked. + /// + public IntPtr WindowHandle; + + /// + /// Application-defined identifier of the taskbar icon. The Shell uses hWnd and uID to identify + /// which icon to operate on when Shell_NotifyIcon is invoked. You can have multiple icons + /// associated with a single hWnd by assigning each a different uID. This feature, however + /// is currently not used. + /// + public uint TaskbarIconId; + + /// + /// Flags that indicate which of the other members contain valid data. This member can be + /// a combination of the NIF_XXX constants. + /// + public IconDataMembers ValidMembers; + + /// + /// Application-defined message identifier. The system uses this identifier to send + /// notifications to the window identified in hWnd. + /// + public uint CallbackMessageId; + + /// + /// A handle to the icon that should be displayed. Just + /// Icon.Handle. + /// + public IntPtr IconHandle; + + /// + /// String with the text for a standard ToolTip. It can have a maximum of 64 characters including + /// the terminating NULL. For Version 5.0 and later, szTip can have a maximum of + /// 128 characters, including the terminating NULL. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string ToolTipText; + + + /// + /// State of the icon. Remember to also set the . + /// + public IconState IconState; + + /// + /// A value that specifies which bits of the state member are retrieved or modified. + /// For example, setting this member to + /// causes only the item's hidden + /// state to be retrieved. + /// + public IconState StateMask; + + /// + /// String with the text for a balloon ToolTip. It can have a maximum of 255 characters. + /// To remove the ToolTip, set the NIF_INFO flag in uFlags and set szInfo to an empty string. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string BalloonText; + + /// + /// Mainly used to set the version when is invoked + /// with . However, for legacy operations, + /// the same member is also used to set timeouts for balloon ToolTips. + /// + public uint VersionOrTimeout; + + /// + /// String containing a title for a balloon ToolTip. This title appears in boldface + /// above the text. It can have a maximum of 63 characters. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string BalloonTitle; + + /// + /// Adds an icon to a balloon ToolTip, which is placed to the left of the title. If the + /// member is zero-length, the icon is not shown. + /// + public BalloonFlags BalloonFlags; + + /// + /// Windows XP (Shell32.dll version 6.0) and later.
+ /// - Windows 7 and later: A registered GUID that identifies the icon. + /// This value overrides uID and is the recommended method of identifying the icon.
+ /// - Windows XP through Windows Vista: Reserved. + ///
+ public Guid TaskbarIconGuid; + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. The handle of a customized + /// balloon icon provided by the application that should be used independently + /// of the tray icon. If this member is non-NULL and the + /// flag is set, this icon is used as the balloon icon.
+ /// If this member is NULL, the legacy behavior is carried out. + ///
+ public IntPtr CustomBalloonIconHandle; + + + /// + /// Creates a default data structure that provides + /// a hidden taskbar icon without the icon being set. + /// + /// + /// NotifyIconData + public static NotifyIconData CreateDefault(IntPtr handle) + { + var data = new NotifyIconData(); + + //use the current size + data.cbSize = (uint) Marshal.SizeOf(data); + + data.WindowHandle = handle; + data.TaskbarIconId = 0x0; + data.CallbackMessageId = WindowMessageSink.CallbackMessageId; + data.VersionOrTimeout = (uint) NotifyIconVersion.Vista; + + data.IconHandle = IntPtr.Zero; + + //hide initially + data.IconState = IconState.Hidden; + data.StateMask = IconState.Hidden; + + //set flags + data.ValidMembers = IconDataMembers.Message | IconDataMembers.Icon | IconDataMembers.Tip | IconDataMembers.UseLegacyToolTips; + + //reset strings + data.ToolTipText = data.BalloonText = data.BalloonTitle = string.Empty; + + return data; + } + } +} diff --git a/UserInterface/Win/Interop/NotifyIconVersion.cs b/UserInterface/Win/Interop/NotifyIconVersion.cs new file mode 100644 index 0000000..349ac75 --- /dev/null +++ b/UserInterface/Win/Interop/NotifyIconVersion.cs @@ -0,0 +1,15 @@ +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// The notify icon version that is used. The higher + /// the version, the more capabilities are available. + /// + public enum NotifyIconVersion + { + ///
+ Vista = 0x4 + } +} diff --git a/UserInterface/Win/Interop/WinApi.cs b/UserInterface/Win/Interop/WinApi.cs new file mode 100644 index 0000000..d0580e1 --- /dev/null +++ b/UserInterface/Win/Interop/WinApi.cs @@ -0,0 +1,59 @@ +using System; +using System.Runtime.InteropServices; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Win32 API imports. + /// + internal static class WinApi + { + private const string User32 = "user32.dll"; + + /// + /// Creates, updates or deletes the taskbar icon. + /// + [DllImport("shell32.Dll", CharSet = CharSet.Unicode)] + public static extern bool Shell_NotifyIcon(NotifyCommand cmd, [In] ref NotifyIconData data); + + + /// + /// Creates the helper window that receives messages from the taskar icon. + /// + [DllImport(User32, EntryPoint = "CreateWindowExW", SetLastError = true)] + public static extern IntPtr CreateWindowEx(int dwExStyle, [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, + [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, int dwStyle, int x, int y, + int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, + IntPtr lpParam); + + + /// + /// Processes a default windows procedure. + /// + [DllImport(User32)] + public static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wparam, IntPtr lparam); + + /// + /// Registers the helper window class. + /// + [DllImport(User32, EntryPoint = "RegisterClassW", SetLastError = true)] + public static extern short RegisterClass(ref WindowClass lpWndClass); + + /// + /// Registers a listener for a window message. + /// + /// + /// uint + [DllImport(User32, EntryPoint = "RegisterWindowMessageW")] + public static extern uint RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString); + + /// + /// Used to destroy the hidden helper window that receives messages from the + /// taskbar icon. + /// + /// + /// bool + [DllImport(User32, SetLastError = true)] + public static extern bool DestroyWindow(IntPtr hWnd); + } +} diff --git a/UserInterface/Win/Interop/WindowClass.cs b/UserInterface/Win/Interop/WindowClass.cs new file mode 100644 index 0000000..b6840a0 --- /dev/null +++ b/UserInterface/Win/Interop/WindowClass.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Callback delegate which is used by the Windows API to + /// submit window messages. + /// + public delegate IntPtr WindowProcedureHandler(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam); + + + /// + /// Win API WNDCLASS struct - represents a single window. + /// Used to receive window messages. + /// + [StructLayout(LayoutKind.Sequential)] + public struct WindowClass + { + #pragma warning disable 1591 + + public uint style; + public WindowProcedureHandler lpfnWndProc; + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszMenuName; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszClassName; + + #pragma warning restore 1591 + } +} diff --git a/UserInterface/Win/Interop/WindowMessageSink.cs b/UserInterface/Win/Interop/WindowMessageSink.cs new file mode 100644 index 0000000..f4ef6d7 --- /dev/null +++ b/UserInterface/Win/Interop/WindowMessageSink.cs @@ -0,0 +1,357 @@ +// hardcodet.net NotifyIcon for WPF +// Copyright (c) 2009 - 2013 Philipp Sumi +// Contact and Information: http://www.hardcodet.net +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Code Project Open License (CPOL); +// either version 1.0 of the License, or (at your option) any later +// version. +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE + + +using System; +using System.ComponentModel; +using System.Diagnostics; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// Receives messages from the taskbar icon through + /// window messages of an underlying helper window. + /// + public class WindowMessageSink : IDisposable + { + #region members + + /// + /// The ID of messages that are received from the the + /// taskbar icon. + /// + public const int CallbackMessageId = 0x400; + + /// + /// The ID of the message that is being received if the + /// taskbar is (re)started. + /// + private uint taskbarRestartMessageId; + + /// + /// Used to track whether a mouse-up event is just + /// the aftermath of a double-click and therefore needs + /// to be suppressed. + /// + private bool isDoubleClick; + + /// + /// A delegate that processes messages of the hidden + /// native window that receives window messages. Storing + /// this reference makes sure we don't loose our reference + /// to the message window. + /// + private WindowProcedureHandler messageHandler; + + /// + /// Window class ID. + /// + internal string WindowId { get; private set; } + + /// + /// Handle for the message window. + /// + internal IntPtr MessageWindowHandle { get; private set; } + + /// + /// The version of the underlying icon. Defines how + /// incoming messages are interpreted. + /// + public NotifyIconVersion Version { get; set; } + + #endregion + + #region events + + /// + /// The custom tooltip should be closed or hidden. + /// + public event Action ChangeToolTipStateRequest; + + /// + /// Fired in case the user clicked or moved within + /// the taskbar icon area. + /// + public event Action MouseEventReceived; + + /// + /// Fired if a balloon ToolTip was either displayed + /// or closed (indicated by the boolean flag). + /// + public event Action BalloonToolTipChanged; + + /// + /// Fired if the taskbar was created or restarted. Requires the taskbar + /// icon to be reset. + /// + public event Action TaskbarCreated; + + #endregion + + #region construction + + /// + /// Creates a new message sink that receives message from + /// a given taskbar icon. + /// + /// + public WindowMessageSink(NotifyIconVersion version) + { + Version = version; + CreateMessageWindow(); + } + + #endregion + + #region CreateMessageWindow + + /// + /// Creates the helper message window that is used + /// to receive messages from the taskbar icon. + /// + private void CreateMessageWindow() + { + //generate a unique ID for the window + WindowId = "WPFTaskbarIcon_" + Guid.NewGuid(); + + //register window message handler + messageHandler = OnWindowMessageReceived; + + // Create a simple window class which is reference through + //the messageHandler delegate + WindowClass wc; + + wc.style = 0; + wc.lpfnWndProc = messageHandler; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = IntPtr.Zero; + wc.hIcon = IntPtr.Zero; + wc.hCursor = IntPtr.Zero; + wc.hbrBackground = IntPtr.Zero; + wc.lpszMenuName = string.Empty; + wc.lpszClassName = WindowId; + + // Register the window class + WinApi.RegisterClass(ref wc); + + // Get the message used to indicate the taskbar has been restarted + // This is used to re-add icons when the taskbar restarts + taskbarRestartMessageId = WinApi.RegisterWindowMessage("TaskbarCreated"); + + // Create the message window + MessageWindowHandle = WinApi.CreateWindowEx(0, WindowId, "", 0, 0, 0, 1, 1, IntPtr.Zero, IntPtr.Zero, + IntPtr.Zero, IntPtr.Zero); + + if (MessageWindowHandle == IntPtr.Zero) + { + throw new Win32Exception("Message window handle was not a valid pointer"); + } + } + + #endregion + + #region Handle Window Messages + + /// + /// Callback method that receives messages from the taskbar area. + /// + private IntPtr OnWindowMessageReceived(IntPtr hWnd, uint messageId, IntPtr wParam, IntPtr lParam) + { + if (messageId == taskbarRestartMessageId) + { + //recreate the icon if the taskbar was restarted (e.g. due to Win Explorer shutdown) + var listener = TaskbarCreated; + listener?.Invoke(); + } + + //forward message + ProcessWindowMessage(messageId, wParam, lParam); + + // Pass the message to the default window procedure + return WinApi.DefWindowProc(hWnd, messageId, wParam, lParam); + } + + + /// + /// Processes incoming system messages. + /// + /// Callback ID. + /// If the version is + /// or higher, this parameter can be used to resolve mouse coordinates. + /// Currently not in use. + /// Provides information about the event. + private void ProcessWindowMessage(uint msg, IntPtr wParam, IntPtr lParam) + { + if (msg != CallbackMessageId) return; + + var message = (WindowsMessages) lParam.ToInt32(); + switch (message) + { + case WindowsMessages.WM_CONTEXTMENU: + // TODO: Handle WM_CONTEXTMENU, see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw + Debug.WriteLine("Unhandled WM_CONTEXTMENU"); + break; + + case WindowsMessages.WM_MOUSEMOVE: + MouseEventReceived?.Invoke(MouseEvent.MouseMove); + break; + + case WindowsMessages.WM_LBUTTONDOWN: + MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseDown); + break; + + case WindowsMessages.WM_LBUTTONUP: + if (!isDoubleClick) + { + MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseUp); + } + isDoubleClick = false; + break; + + case WindowsMessages.WM_LBUTTONDBLCLK: + isDoubleClick = true; + MouseEventReceived?.Invoke(MouseEvent.IconDoubleClick); + break; + + case WindowsMessages.WM_RBUTTONDOWN: + MouseEventReceived?.Invoke(MouseEvent.IconRightMouseDown); + break; + + case WindowsMessages.WM_RBUTTONUP: + MouseEventReceived?.Invoke(MouseEvent.IconRightMouseUp); + break; + + case WindowsMessages.WM_RBUTTONDBLCLK: + //double click with right mouse button - do not trigger event + break; + + case WindowsMessages.WM_MBUTTONDOWN: + MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseDown); + break; + + case WindowsMessages.WM_MBUTTONUP: + MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseUp); + break; + + case WindowsMessages.WM_MBUTTONDBLCLK: + //double click with middle mouse button - do not trigger event + break; + + case WindowsMessages.NIN_BALLOONSHOW: + BalloonToolTipChanged?.Invoke(true); + break; + + case WindowsMessages.NIN_BALLOONHIDE: + case WindowsMessages.NIN_BALLOONTIMEOUT: + BalloonToolTipChanged?.Invoke(false); + break; + + case WindowsMessages.NIN_BALLOONUSERCLICK: + MouseEventReceived?.Invoke(MouseEvent.BalloonToolTipClicked); + break; + + case WindowsMessages.NIN_POPUPOPEN: + ChangeToolTipStateRequest?.Invoke(true); + break; + + case WindowsMessages.NIN_POPUPCLOSE: + ChangeToolTipStateRequest?.Invoke(false); + break; + + case WindowsMessages.NIN_SELECT: + // TODO: Handle NIN_SELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw + Debug.WriteLine("Unhandled NIN_SELECT"); + break; + + case WindowsMessages.NIN_KEYSELECT: + // TODO: Handle NIN_KEYSELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw + Debug.WriteLine("Unhandled NIN_KEYSELECT"); + break; + + default: + Debug.WriteLine("Unhandled NotifyIcon message ID: " + lParam); + break; + } + } + + #endregion + + #region Dispose + + /// + /// Set to true as soon as Dispose has been invoked. + /// + public bool IsDisposed { get; private set; } + + + /// + /// Disposes the object. + /// + /// This method is not virtual by design. Derived classes + /// should override . + /// + public void Dispose() + { + Dispose(true); + + // This object will be cleaned up by the Dispose method. + // Therefore, you should call GC.SuppressFinalize to + // take this object off the finalization queue + // and prevent finalization code for this object + // from executing a second time. + GC.SuppressFinalize(this); + } + + /// + /// This destructor will run only if the + /// method does not get called. This gives this base class the + /// opportunity to finalize. + /// + /// Important: Do not provide destructor in types derived from + /// this class. + /// + /// + ~WindowMessageSink() + { + Dispose(false); + } + + /// + /// Removes the windows hook that receives window + /// messages and closes the underlying helper window. + /// + private void Dispose(bool disposing) + { + //don't do anything if the component is already disposed + if (IsDisposed) return; + IsDisposed = true; + + //always destroy the unmanaged handle (even if called from the GC) + WinApi.DestroyWindow(MessageWindowHandle); + messageHandler = null; + } + + #endregion + } +} diff --git a/UserInterface/Win/Interop/WindowsMessages.cs b/UserInterface/Win/Interop/WindowsMessages.cs new file mode 100644 index 0000000..80bdc71 --- /dev/null +++ b/UserInterface/Win/Interop/WindowsMessages.cs @@ -0,0 +1,190 @@ +// hardcodet.net NotifyIcon for WPF +// Copyright (c) 2009 - 2013 Philipp Sumi +// Contact and Information: http://www.hardcodet.net +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Code Project Open License (CPOL); +// either version 1.0 of the License, or (at your option) any later +// version. +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE + +// ReSharper disable InconsistentNaming + +using System.Diagnostics.CodeAnalysis; + +namespace MangaReader.Avalonia.Platform.Win.Interop +{ + /// + /// This enum defines the windows messages we respond to. + /// See more on Windows messages here + /// + [SuppressMessage("ReSharper", "IdentifierTypo")] + public enum WindowsMessages : uint + { + /// + /// Notifies a window that the user clicked the right mouse button (right-clicked) in the window. + /// See WM_CONTEXTMENU message + /// + /// In case of a notify icon: + /// If a user selects a notify icon's shortcut menu with the keyboard, the Shell now sends the associated application a WM_CONTEXTMENU message. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. + /// See Shell_NotifyIcon function + /// + WM_CONTEXTMENU = 0x007b, + + /// + /// Posted to a window when the cursor moves. + /// If the mouse is not captured, the message is posted to the window that contains the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_MOUSEMOVE message + /// + WM_MOUSEMOVE = 0x0200, + + /// + /// Posted when the user presses the left mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_LBUTTONDOWN message + /// + WM_LBUTTONDOWN = 0x0201, + + /// + /// Posted when the user releases the left mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_LBUTTONUP message + /// + WM_LBUTTONUP = 0x0202, + + /// + /// Posted when the user double-clicks the left mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_LBUTTONDBLCLK message + /// + WM_LBUTTONDBLCLK = 0x0203, + + /// + /// Posted when the user presses the right mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_RBUTTONDOWN message + /// + WM_RBUTTONDOWN = 0x0204, + + /// + /// Posted when the user releases the right mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_RBUTTONUP message + /// + WM_RBUTTONUP = 0x0205, + + /// + /// Posted when the user double-clicks the right mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_RBUTTONDBLCLK message + /// + WM_RBUTTONDBLCLK = 0x0206, + + /// + /// Posted when the user presses the middle mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_MBUTTONDOWN message + /// + WM_MBUTTONDOWN = 0x0207, + + /// + /// Posted when the user releases the middle mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_MBUTTONUP message + /// + WM_MBUTTONUP = 0x0208, + + /// + /// Posted when the user double-clicks the middle mouse button while the cursor is in the client area of a window. + /// If the mouse is not captured, the message is posted to the window beneath the cursor. + /// Otherwise, the message is posted to the window that has captured the mouse. + /// + /// See WM_MBUTTONDBLCLK message + /// + WM_MBUTTONDBLCLK = 0x0209, + + /// + /// Used to define private messages for use by private window classes, usually of the form WM_USER+x, where x is an integer value. + /// + WM_USER = 0x0400, + + /// + /// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification. + /// Send when a notify icon is activated with mouse or ENTER key. + /// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. + /// + NIN_SELECT = WM_USER, + + /// + /// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification. + /// Send when a notify icon is activated with SPACEBAR or ENTER key. + /// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. + /// + NIN_KEYSELECT = WM_USER + 1, + + /// + /// Sent when the balloon is shown (balloons are queued). + /// + NIN_BALLOONSHOW = WM_USER + 2, + + /// + /// Sent when the balloon disappears. For example, when the icon is deleted. + /// This message is not sent if the balloon is dismissed because of a timeout or if the user clicks the mouse. + /// + /// As of Windows 7, NIN_BALLOONHIDE is also sent when a notification with the NIIF_RESPECT_QUIET_TIME flag set attempts to display during quiet time (a user's first hour on a new computer). + /// In that case, the balloon is never displayed at all. + /// + NIN_BALLOONHIDE = WM_USER + 3, + + /// + /// Sent when the balloon is dismissed because of a timeout. + /// + NIN_BALLOONTIMEOUT = WM_USER + 4, + + /// + /// Sent when the balloon is dismissed because the user clicked the mouse. + /// + NIN_BALLOONUSERCLICK = WM_USER + 5, + + /// + /// Sent when the user hovers the cursor over an icon to indicate that the richer pop-up UI should be used in place of a standard textual tooltip. + /// + NIN_POPUPOPEN = WM_USER + 6, + + /// + /// Sent when a cursor no longer hovers over an icon to indicate that the rich pop-up UI should be closed. + /// + NIN_POPUPCLOSE = WM_USER + 7 + } +} diff --git a/UserInterface/Win/NotifyIcon.cs b/UserInterface/Win/NotifyIcon.cs new file mode 100644 index 0000000..c0c2cbd --- /dev/null +++ b/UserInterface/Win/NotifyIcon.cs @@ -0,0 +1,403 @@ +// hardcodet.net NotifyIcon for WPF +// Copyright (c) 2009 - 2013 Philipp Sumi +// Contact and Information: http://www.hardcodet.net +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the Code Project Open License (CPOL); +// either version 1.0 of the License, or (at your option) any later +// version. +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE + + +using System; +using System.Drawing; +using System.Linq; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using MangaReader.Avalonia.Platform.Win.Interop; + +namespace MangaReader.Avalonia.Platform.Win +{ + /// + /// A WPF proxy to for a taskbar icon (NotifyIcon) that sits in the system's + /// taskbar notification area ("system tray"). + /// + public class TaskBarIcon : IDisposable + { + private readonly object lockObject = new object(); + + #region Members + + /// + /// Represents the current icon data. + /// + private NotifyIconData iconData; + + /// + /// Receives messages from the taskbar icon. + /// + private readonly WindowMessageSink messageSink; + + /// + /// Indicates whether the taskbar icon has been created or not. + /// + public bool IsTaskbarIconCreated { get; private set; } + + public Icon Icon { get; } + + public event EventHandler MouseEventHandler; + + #endregion + + #region Construction + + /// + /// Initializes the taskbar icon and registers a message listener + /// in order to receive events from the taskbar area. + /// + public TaskBarIcon(Icon icon) + { + Icon = icon; + + // using dummy sink in design mode + messageSink = new WindowMessageSink(NotifyIconVersion.Vista); + + // init icon data structure + iconData = NotifyIconData.CreateDefault(messageSink.MessageWindowHandle); + iconData.IconHandle = Icon?.Handle ?? IntPtr.Zero; + iconData.ToolTipText = nameof(MangaReader); + + // create the taskbar icon + CreateTaskbarIcon(); + + // register event listeners + messageSink.MouseEventReceived += OnMouseEvent; + messageSink.TaskbarCreated += OnTaskbarCreated; + + // register listener in order to get notified when the application closes + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) + { + lifetime.Exit += OnExit; + } + } + + #endregion + + #region Process Incoming Mouse Events + + /// + /// Processes mouse events, which are bubbled + /// through the class' routed events, trigger + /// certain actions (e.g. show a popup), or + /// both. + /// + /// Event flag. + private void OnMouseEvent(MouseEvent me) + { + if (IsDisposed) + return; + + switch (me) + { + case MouseEvent.MouseMove: + // immediately return - there's nothing left to evaluate + return; + case MouseEvent.IconRightMouseDown: + case MouseEvent.IconLeftMouseDown: + case MouseEvent.IconRightMouseUp: + case MouseEvent.IconLeftMouseUp: + case MouseEvent.IconMiddleMouseDown: + case MouseEvent.IconMiddleMouseUp: + case MouseEvent.BalloonToolTipClicked: + case MouseEvent.IconDoubleClick: + MouseEventHandler?.Invoke(this, me); + break; + default: + throw new ArgumentOutOfRangeException(nameof(me), "Missing handler for mouse event flag: " + me); + } + } + + #endregion + + #region Balloon Tips + + /// + /// Displays a balloon tip with the specified title, + /// text, and icon in the taskbar for the specified time period. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + /// A symbol that indicates the severity. + public void ShowBalloonTip(string title, string message, BalloonFlags symbol) + { + lock (lockObject) + { + ShowBalloonTip(title, message, symbol, IntPtr.Zero); + } + } + + + /// + /// Invokes in order to display + /// a given balloon ToolTip. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + /// Indicates what icon to use. + /// A handle to a custom icon, if any, or + /// . + private void ShowBalloonTip(string title, string message, BalloonFlags flags, IntPtr balloonIconHandle) + { + EnsureNotDisposed(); + + iconData.BalloonText = message ?? string.Empty; + iconData.BalloonTitle = title ?? string.Empty; + + iconData.BalloonFlags = flags; + iconData.CustomBalloonIconHandle = balloonIconHandle; + WriteIconData(ref iconData, NotifyCommand.Modify, IconDataMembers.Info | IconDataMembers.Icon); + } + + + /// + /// Hides a balloon ToolTip, if any is displayed. + /// + public void HideBalloonTip() + { + EnsureNotDisposed(); + + // reset balloon by just setting the info to an empty string + iconData.BalloonText = iconData.BalloonTitle = string.Empty; + WriteIconData(ref iconData, NotifyCommand.Modify, IconDataMembers.Info); + } + + #endregion + + #region Create / Remove Taskbar Icon + + /// + /// Recreates the taskbar icon if the whole taskbar was + /// recreated (e.g. because Explorer was shut down). + /// + private void OnTaskbarCreated() + { + IsTaskbarIconCreated = false; + CreateTaskbarIcon(); + } + + + /// + /// Creates the taskbar icon. This message is invoked during initialization, + /// if the taskbar is restarted, and whenever the icon is displayed. + /// + private void CreateTaskbarIcon() + { + lock (lockObject) + { + if (IsTaskbarIconCreated) + { + return; + } + + const IconDataMembers members = IconDataMembers.Message | IconDataMembers.Icon | IconDataMembers.Tip; + + //write initial configuration + var status = WriteIconData(ref iconData, NotifyCommand.Add, members); + if (!status) + { + // couldn't create the icon - we can assume this is because explorer is not running (yet!) + // -> try a bit later again rather than throwing an exception. Typically, if the windows + // shell is being loaded later, this method is being re-invoked from OnTaskbarCreated + // (we could also retry after a delay, but that's currently YAGNI) + return; + } + + messageSink.Version = (NotifyIconVersion)iconData.VersionOrTimeout; + + IsTaskbarIconCreated = true; + } + } + + /// + /// Closes the taskbar icon if required. + /// + private void RemoveTaskbarIcon() + { + lock (lockObject) + { + // make sure we didn't schedule a creation + + if (!IsTaskbarIconCreated) + { + return; + } + + WriteIconData(ref iconData, NotifyCommand.Delete, IconDataMembers.Message); + IsTaskbarIconCreated = false; + } + } + + #endregion + + #region Dispose / Exit + + /// + /// Set to true as soon as Dispose has been invoked. + /// + public bool IsDisposed { get; private set; } + + + /// + /// Checks if the object has been disposed and + /// raises a in case + /// the flag is true. + /// + private void EnsureNotDisposed() + { + if (IsDisposed) + throw new ObjectDisposedException(GetType().FullName); + } + + + /// + /// Disposes the class if the application exits. + /// + private void OnExit(object sender, EventArgs e) + { + Dispose(); + } + + + /// + /// This destructor will run only if the + /// method does not get called. This gives this base class the + /// opportunity to finalize. + /// + /// Important: Do not provide destructor in types derived from this class. + /// + /// + ~TaskBarIcon() + { + Dispose(false); + } + + + /// + /// Disposes the object. + /// + /// This method is not virtual by design. Derived classes + /// should override . + /// + public void Dispose() + { + Dispose(true); + + // This object will be cleaned up by the Dispose method. + // Therefore, you should call GC.SuppressFinalize to + // take this object off the finalization queue + // and prevent finalization code for this object + // from executing a second time. + GC.SuppressFinalize(this); + } + + + /// + /// Closes the tray and releases all resources. + /// + /// + /// Dispose(bool disposing) executes in two distinct scenarios. + /// If disposing equals true, the method has been called directly + /// or indirectly by a user's code. Managed and unmanaged resources + /// can be disposed. + /// + /// If disposing equals false, the method + /// has been called by the runtime from inside the finalizer and you + /// should not reference other objects. Only unmanaged resources can + /// be disposed. + /// Check the property to determine whether + /// the method has already been called. + private void Dispose(bool disposing) + { + // don't do anything if the component is already disposed + if (IsDisposed || !disposing) + return; + + lock (lockObject) + { + IsDisposed = true; + + // de-register application event listener + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) + { + lifetime.Exit -= OnExit; + } + + // dispose message sink + messageSink.Dispose(); + + // remove icon + RemoveTaskbarIcon(); + } + } + + #endregion + + #region WriteIconData + + /// + /// Updates the taskbar icons with data provided by a given + /// instance. + /// + /// Configuration settings for the NotifyIcon. + /// Operation on the icon (e.g. delete the icon). + /// Defines which members of the + /// structure are set. + /// True if the data was successfully written. + /// See Shell_NotifyIcon documentation on MSDN for details. + private bool WriteIconData(ref NotifyIconData data, NotifyCommand command, IconDataMembers flags) + { + data.ValidMembers |= flags; + lock (lockObject) + { + return WinApi.Shell_NotifyIcon(command, ref data); + } + } + + #endregion + + /// + /// Reads a given image resource into a WinForms icon. + /// + /// Image source pointing to + /// an icon file (*.ico). + /// An icon object that can be used with the + /// taskbar area. + public static Icon ToIcon(string imageSource) + { + if (imageSource == null) + return null; + + var executingAssembly = System.Reflection.Assembly.GetExecutingAssembly(); + if (executingAssembly.GetManifestResourceNames().Contains(imageSource)) + { + var stream = executingAssembly.GetManifestResourceStream(imageSource); + return new Icon(stream); + } + + return null; + } + } +} diff --git a/UserInterface/Win/WindowsTrayIcon.cs b/UserInterface/Win/WindowsTrayIcon.cs new file mode 100644 index 0000000..532ce8b --- /dev/null +++ b/UserInterface/Win/WindowsTrayIcon.cs @@ -0,0 +1,62 @@ +using System.Runtime.InteropServices; +using System.Windows.Input; +using MangaReader.Avalonia.Platform.Win.Interop; + +namespace MangaReader.Avalonia.Platform.Win +{ + public class WindowsTrayIcon : ITrayIcon + { + public ICommand DoubleClickCommand { get; set; } + + public ICommand BalloonClickedCommand { get; set; } + + private TaskBarIcon taskBarIcon; + + private object lastBalloonState; + + public void SetIcon() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var iconSource = "MangaReader.Avalonia.Assets.main.ico"; + var icon = TaskBarIcon.ToIcon(iconSource); + taskBarIcon = new TaskBarIcon(icon); + taskBarIcon.MouseEventHandler += TaskBarIconOnMouseEventHandler; + } + } + + public void ShowBalloon(string text, object state) + { + this.lastBalloonState = state; + taskBarIcon?.ShowBalloonTip(nameof(MangaReader), text, BalloonFlags.Info); + } + + private void TaskBarIconOnMouseEventHandler(object sender, MouseEvent e) + { + if (e == MouseEvent.IconDoubleClick) + { + var command = this.DoubleClickCommand; + if (command != null && command.CanExecute(null)) + { + command.Execute(null); + } + } + + if (e == MouseEvent.BalloonToolTipClicked) + { + var command = this.BalloonClickedCommand; + if (command != null && command.CanExecute(lastBalloonState)) + { + command.Execute(lastBalloonState); + } + } + } + + public void Dispose() + { + if (taskBarIcon != null) + taskBarIcon.MouseEventHandler -= TaskBarIconOnMouseEventHandler; + taskBarIcon?.Dispose(); + } + } +} diff --git a/UserInterface/nuget.config b/UserInterface/nuget.config new file mode 100644 index 0000000..6c273ab --- /dev/null +++ b/UserInterface/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/hass-workstation-service.sln b/hass-workstation-service.sln index 18edd60..8815dcc 100644 --- a/hass-workstation-service.sln +++ b/hass-workstation-service.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.30804.86 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hass-workstation-service", "hass-workstation-service\hass-workstation-service.csproj", "{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserInterface", "UserInterface\UserInterface.csproj", "{8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,14 @@ Global {78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|Any CPU.Build.0 = Release|Any CPU {78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|x86.ActiveCfg = Release|Any CPU {78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|x86.Build.0 = Release|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Debug|x86.ActiveCfg = Debug|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Debug|x86.Build.0 = Debug|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Release|Any CPU.Build.0 = Release|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Release|x86.ActiveCfg = Release|Any CPU + {8ECB6FEE-1AD2-40E3-897D-E75EDB637BB5}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs new file mode 100644 index 0000000..8750f31 --- /dev/null +++ b/hass-workstation-service/Communication/InterProcesCommunication/ServiceContractInterfaces.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace hass_workstation_service.Communication.NamedPipe +{ + public interface ServiceContractInterfaces + { + public string Ping(string str); + void WriteMqttBrokerSettings(string host, string username, string password); + } +} diff --git a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs index 95d4894..2b1dd92 100644 --- a/hass-workstation-service/Communication/MQTT/MqttPublisher.cs +++ b/hass-workstation-service/Communication/MQTT/MqttPublisher.cs @@ -17,7 +17,7 @@ namespace hass_workstation_service.Communication { private readonly IMqttClient _mqttClient; private readonly ILogger _logger; - private readonly ConfigurationService _configurationService; + private readonly IConfigurationService _configurationService; public DateTime LastConfigAnnounce { get; private set; } public DeviceConfigModel DeviceConfigModel { get; private set; } public bool IsConnected @@ -38,7 +38,7 @@ namespace hass_workstation_service.Communication public MqttPublisher( ILogger logger, DeviceConfigModel deviceConfigModel, - ConfigurationService configurationService) + IConfigurationService configurationService) { this._logger = logger; @@ -46,6 +46,7 @@ namespace hass_workstation_service.Communication this._configurationService = configurationService; var options = _configurationService.ReadMqttSettings().Result; + _configurationService.MqqtConfigChangedHandler = this.ReplaceMqttClient; var factory = new MqttFactory(); this._mqttClient = factory.CreateMqttClient(); @@ -54,17 +55,21 @@ namespace hass_workstation_service.Communication // configure what happens on disconnect this._mqttClient.UseDisconnectedHandler(async e => { - _logger.LogWarning("Disconnected from server"); - await Task.Delay(TimeSpan.FromSeconds(5)); - - try - { - await this._mqttClient.ConnectAsync(options, CancellationToken.None); - } - catch (Exception ex) + if (e.ReasonCode != MQTTnet.Client.Disconnecting.MqttClientDisconnectReason.NormalDisconnection) { - _logger.LogError(ex, "Reconnecting failed"); + _logger.LogWarning("Disconnected from server"); + await Task.Delay(TimeSpan.FromSeconds(5)); + + try + { + await this._mqttClient.ConnectAsync(options, CancellationToken.None); + } + catch (Exception ex) + { + _logger.LogError(ex, "Reconnecting failed"); + } } + }); } @@ -76,7 +81,7 @@ namespace hass_workstation_service.Communication } else { - this._logger.LogInformation($"message dropped because mqtt not connected: {message}"); + this._logger.LogInformation($"Message dropped because mqtt not connected: {message}"); } } @@ -99,5 +104,24 @@ namespace hass_workstation_service.Communication LastConfigAnnounce = DateTime.UtcNow; } } + + public async void ReplaceMqttClient(IMqttClientOptions options) + { + this._logger.LogInformation($"Replacing Mqtt client with new config"); + await _mqttClient.DisconnectAsync(); + try + { + await _mqttClient.ConnectAsync(options); + } + catch (Exception ex) + { + Log.Logger.Error("Could not connect to broker: " + ex.Message); + } + finally + { + Log.Logger.Information("Connected to new broker"); + } + + } } } diff --git a/hass-workstation-service/Data/ConfigurationService.cs b/hass-workstation-service/Data/ConfigurationService.cs index 834f032..dcb4f0b 100644 --- a/hass-workstation-service/Data/ConfigurationService.cs +++ b/hass-workstation-service/Data/ConfigurationService.cs @@ -2,9 +2,11 @@ using System; using System.Collections.Generic; using System.IO; using System.IO.IsolatedStorage; +using System.Security; using System.Text.Json; using System.Threading.Tasks; using hass_workstation_service.Communication; +using hass_workstation_service.Communication.NamedPipe; using hass_workstation_service.Domain.Sensors; using Microsoft.Extensions.Configuration; using MQTTnet; @@ -14,9 +16,11 @@ using Serilog; namespace hass_workstation_service.Data { - public class ConfigurationService + public class ConfigurationService : ServiceContractInterfaces, IConfigurationService { public ICollection ConfiguredSensors { get; private set; } + public Action MqqtConfigChangedHandler { get; set; } + private readonly IsolatedStorageFile _fileStorage; public ConfigurationService() @@ -64,8 +68,9 @@ namespace hass_workstation_service.Data configuredBroker = await JsonSerializer.DeserializeAsync(stream); } stream.Close(); - if (configuredBroker != null) + if (configuredBroker != null && configuredBroker.Host != null) { + var mqttClientOptions = new MqttClientOptionsBuilder() .WithTcpServer(configuredBroker.Host) // .WithTls() @@ -110,5 +115,38 @@ namespace hass_workstation_service.Data sensors.ForEach((sensor) => this.ConfiguredSensors.Add(sensor)); WriteSettings(); } + + public async void WriteMqttBrokerSettings(string host, string username, string password) + { + IsolatedStorageFileStream stream = this._fileStorage.OpenFile("mqttbroker.json", FileMode.OpenOrCreate); + Log.Logger.Information($"writing configured mqttbroker to: {stream.Name}"); + ConfiguredMqttBroker configuredBroker = new ConfiguredMqttBroker() + { + Host = host, + Username = username, + Password = password + }; + + await JsonSerializer.SerializeAsync(stream, configuredBroker); + stream.Close(); + + this.MqqtConfigChangedHandler.Invoke(await this.ReadMqttSettings()); + } + + + + /// + /// You can use this to check if the application responds. + /// + /// + /// + public string Ping(string str) + { + if (str == "ping") + { + return "pong"; + } + return "what?"; + } } } \ No newline at end of file diff --git a/hass-workstation-service/Data/ConfiguredMqttBroker.cs b/hass-workstation-service/Data/ConfiguredMqttBroker.cs index 77afbc2..a86e249 100644 --- a/hass-workstation-service/Data/ConfiguredMqttBroker.cs +++ b/hass-workstation-service/Data/ConfiguredMqttBroker.cs @@ -7,6 +7,6 @@ namespace hass_workstation_service.Data { public string Host { get; set; } public string Username { get; set; } - public SecureString Password { get; set; } + public string Password { get; set; } } } \ No newline at end of file diff --git a/hass-workstation-service/Data/IConfigurationService.cs b/hass-workstation-service/Data/IConfigurationService.cs new file mode 100644 index 0000000..7dac53c --- /dev/null +++ b/hass-workstation-service/Data/IConfigurationService.cs @@ -0,0 +1,24 @@ +using hass_workstation_service.Communication; +using hass_workstation_service.Domain.Sensors; +using MQTTnet.Client.Options; +using System; +using System.Collections.Generic; +using System.Security; +using System.Threading.Tasks; + +namespace hass_workstation_service.Data +{ + public interface IConfigurationService + { + ICollection ConfiguredSensors { get; } + Action MqqtConfigChangedHandler { get; set; } + + void AddConfiguredSensor(AbstractSensor sensor); + void AddConfiguredSensors(List sensors); + string Ping(string str); + Task ReadMqttSettings(); + void ReadSensorSettings(MqttPublisher publisher); + void WriteMqttBrokerSettings(string host, string username, string password); + void WriteSettings(); + } +} \ No newline at end of file diff --git a/hass-workstation-service/Program.cs b/hass-workstation-service/Program.cs index 7b3eac7..b5223bc 100644 --- a/hass-workstation-service/Program.cs +++ b/hass-workstation-service/Program.cs @@ -16,6 +16,8 @@ using System.IO.IsolatedStorage; using System.Reflection; using System.IO; using Microsoft.Win32; +using JKang.IpcServiceFramework.Hosting; +using hass_workstation_service.Communication.NamedPipe; namespace hass_workstation_service { @@ -86,9 +88,15 @@ namespace hass_workstation_service Sw_version = GetVersion() }; services.AddSingleton(deviceConfig); - services.AddSingleton(); + ConfigurationService configurationService = new ConfigurationService(); + services.AddSingleton(configurationService); + services.AddSingleton(configurationService); services.AddSingleton(); services.AddHostedService(); + }).ConfigureIpcHost(builder => + { + // configure IPC endpoints + builder.AddNamedPipeEndpoint(pipeName: "pipeinternal"); }); static internal string GetVersion() { diff --git a/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml b/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml index e801e01..9a49144 100644 --- a/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml +++ b/hass-workstation-service/Properties/PublishProfiles/ClickOnceProfile.pubxml @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - 33 + 34 1.0.0.* True Release diff --git a/hass-workstation-service/Worker.cs b/hass-workstation-service/Worker.cs index 8e09eeb..f054334 100644 --- a/hass-workstation-service/Worker.cs +++ b/hass-workstation-service/Worker.cs @@ -15,11 +15,11 @@ namespace hass_workstation_service public class Worker : BackgroundService { private readonly ILogger _logger; - private readonly ConfigurationService _configurationService; + private readonly IConfigurationService _configurationService; private readonly MqttPublisher _mqttPublisher; public Worker(ILogger logger, - ConfigurationService configuredSensorsService, + IConfigurationService configuredSensorsService, MqttPublisher mqttPublisher) { _logger = logger; diff --git a/hass-workstation-service/hass-workstation-service.csproj b/hass-workstation-service/hass-workstation-service.csproj index ee48ed1..f61dee6 100644 --- a/hass-workstation-service/hass-workstation-service.csproj +++ b/hass-workstation-service/hass-workstation-service.csproj @@ -4,7 +4,7 @@ netcoreapp3.1 dotnet-hass_workstation_service-C65C2EBE-1977-4C24-AC6B-6921877E1390 hass_workstation_service - WinExe + Exe Sleevezipper https://github.com/sleevezipper/hass-workstation-service false @@ -30,7 +30,8 @@ - + +
+ /// Extended tooltip support, which is available for Vista and later. + /// Detailed information about what the different versions do, can be found here + ///