Neuerstellung

This commit is contained in:
maier_S
2022-03-11 14:59:36 +01:00
parent 072072202a
commit cc720e6421
128 changed files with 16224 additions and 0 deletions

10
.gitremotes Normal file
View File

@@ -0,0 +1,10 @@
FSI.Lib http://desiaugetc7-088:3000/FSI/FSI.Lib.git (fetch)
FSI.Lib http://desiaugetc7-088:3000/FSI/FSI.Lib.git (push)
NHotkey http://desiaugetc7-088:3000/FSI/NHotkey.git (fetch)
NHotkey http://desiaugetc7-088:3000/FSI/NHotkey.git (push)
NotifyIconWpf http://desiaugetc7-088:3000/FSI/NotifyIconWpf.git (fetch)
NotifyIconWpf http://desiaugetc7-088:3000/FSI/NotifyIconWpf.git (push)
RadialMenu http://desiaugetc7-088:3000/FSI/RadialMenu.git (fetch)
RadialMenu http://desiaugetc7-088:3000/FSI/RadialMenu.git (push)
origin http://desiaugetc7-088:3000/FSI/FSI.Tools.git (fetch)
origin http://desiaugetc7-088:3000/FSI/FSI.Tools.git (push)

49
FSI.BT.Tools.sln Normal file
View File

@@ -0,0 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.BT.Tools", "FSI.BT.Tools\FSI.BT.Tools.csproj", "{21041032-87C5-4842-B540-9EB3ACD8A16D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.Lib", "FSI.Lib\FSI.Lib\FSI.Lib.csproj", "{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIconWpf", "NotifyIconWpf\NotifyIconWpf\NotifyIconWpf.csproj", "{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.Wpf", "NHotkey\NHotkey.Wpf\NHotkey.Wpf.csproj", "{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RadialMenu", "RadialMenu\RadialMenu.csproj", "{9DF116EE-45B1-4297-BE75-0F6B78B33689}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Release|Any CPU.Build.0 = Release|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Release|Any CPU.Build.0 = Release|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Release|Any CPU.Build.0 = Release|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Release|Any CPU.Build.0 = Release|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E7CCC9AB-E9BE-4414-B73F-8387EDFEEB2D}
EndGlobalSection
EndGlobal

35
FSI.BT.Tools/Admin.cs Normal file
View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using FSI.Lib.Helpers;
namespace FSI.BT.Tools
{
internal class Admin
{
public static bool CheckAdminRight()
{
string adminsSettings = Lib.Settings.Setting<string>("AdminUsers", Lib.Settings.Mode.ExeSetttings);
string[] adminsCrypt = adminsSettings.Split(";;");
List<string> admins = new List<string>();
foreach (string admin in adminsCrypt)
{
try
{
admins.Add(Lib.DeEncryptString.DeEncrypt.DecryptString(Lib.DeEncryptString.DeEncrypt.DecryptString(admin, Lib.Settings.Setting<string>("DeEnCryptPasswort", Lib.Settings.Mode.ExeSetttings)), Lib.Settings.Setting<string>("DeEnCryptPasswort", Lib.Settings.Mode.ExeSetttings)));
}
catch { }
}
System.Security.Principal.WindowsIdentity windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
foreach (string admin in admins)
{
if (string.Equals(admin, windowsIdentity.ShortName(), StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
}
}

80
FSI.BT.Tools/App.config Normal file
View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DeEnCryptPasswort"
value="Fondium Singen GmbH"/>
<add key="Users"
value="x27xm8kujBnjlCVaIcoTTg=="/>
<add key="AdminUsers"
value="hU4oePJDurXlIZUL4WLIRTt7LoEhVS//rfdZH3O2QVsUPPJL62dqKOCbXZMDdCRih884NktbdDHgRSzsN7wjkQ=="/>
<add key="TimeStamp.Format"
value="_yyyyMMdd_HHmmss"/>
<add key="SIE.Simatic.Manager.Exe"
value="C:\Program Files (x86)\Siemens\Step7\S7BIN\S7tgtopx.exe"/>
<add key="SIE.TIA.V13.Exe"
value="C:\Program Files (x86)\Siemens\Automation\Portal V13\Bin\Siemens.Automation.Portal.exe"/>
<add key="SIE.TIA.V14.Exe"
value="C:\Program Files\Siemens\Automation\Portal V14\Bin\Siemens.Automation.Portal.exe"/>
<add key="SIE.TIA.V15.Exe"
value="C:\Program Files\Siemens\Automation\Portal V15\Bin\Siemens.Automation.Portal.exe;
C:\Program Files\Siemens\Automation\Portal V15_1\Bin\Siemens.Automation.Portal.exe"/>
<add key="SIE.TIA.V16.Exe"
value="C:\Program Files\Siemens\Automation\Portal V16\Bin\Siemens.Automation.Portal.exe"/>
<add key="SIE.TIA.V17.Exe"
value="C:\Program Files\Siemens\Automation\Portal V17\Bin\Siemens.Automation.Portal.exe"/>
<add key="SIE.Starter.Exe"
value="C:\Program Files (x86)\Siemens\Step7\S7BIN\u7wdrfax.exe"/>
<add key="Epl.Exe"
value="C:\Program Files\EPLAN\Platform\2.9.4\Bin\EPLAN.exe;
C:\Program Files\EPLAN\Platform\2022.0.3\Bin\Eplan.exe"/>
<add key="Npp.Exe"
value="C:\Windows\system32\notepad.exe;
C:\Program Files\Notepad++\notepad++.exe"/>
<add key="TeXstudio.Exe"
value="C:\Program Files\texstudio\texstudio.exe"/>
<add key="TeXstudio.Path"
value="C:\Program Files\texstudio\dictionaries"/>
<add key="TotalCmd.Exe"
value="C:\Program Files\totalcmd\TOTALCMD.EXE;
C:\Program Files\totalcmd\TOTALCMD64.EXE;
C:\totalcmd\TOTALCMD64.EXE;
C:\totalcmd\TOTALCMD.EXE"/>
<add key="VS.Exe"
value="C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe"/>
<add key="VS.Code.Exe"
value="%USERPROFILE%\AppData\Local\Programs\Microsoft VS Code\Code.exe"/>
<add key="Rdp.Exe"
value="%windir%\system32\mstsc.exe"/>
<add key="ZentralWeb.Url"
value="http://desiaugetwf/web/?AspxAutoDetectCookieSupport=1"/>
<add key="Schichtbuch.Url"
value="http://10.10.1.42/SKSchichtbuchWeb/de-DE/Plugin/ShiftBook/ShiftBook/IR"/>
<add key="SPS.Url"
value="http://10.10.1.42/SKChangeTrackerWeb/de-DE/Plugin/ChangeTracker"/>
<add key="PL1.PLS.Url"
value="http://10.10.200.2/SKPL1Web/index.aspx"/>
<add key="PL2.PLS.Url"
value="http://10.10.213.4/SKPL2Web/index.aspx"/>
<add key="PL2.ALS.Url"
value="http://10.10.213.234:84/emb_1/index.html"/>
<add key="PL3.PLS.Url"
value="http://10.10.202.10/SKPL3Web/index.aspx"/>
<add key="FSI.Gitea.Url"
value="http://desiaugetc7-088:3000/"/>
<add key="FSI.Wiki.Url"
value="http://desiaugetc7-088:3001/en/home"/>
<add key="Erp.Url"
value="https://mingle-portal.eu1.inforcloudsuite.com/FONDIUM_prd"/>
</appSettings>
</configuration>

17
FSI.BT.Tools/App.xaml Normal file
View File

@@ -0,0 +1,17 @@
<Application x:Class="FSI.BT.Tools.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
Startup="InitApplication">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NotifyIconResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

51
FSI.BT.Tools/App.xaml.cs Normal file
View File

@@ -0,0 +1,51 @@
using Hardcodet.Wpf.TaskbarNotification;
using NHotkey;
using NHotkey.Wpf;
using System.Windows;
using System.Windows.Input;
using FSI.Lib.Wpf.ExtensionMethods;
using System.IO;
using System.Diagnostics;
using System;
namespace FSI.BT.Tools
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application
{
private static readonly KeyGesture RadialMenu = new(Key.OemBackslash, ModifierKeys.Control);
private static readonly KeyGesture TimeStamp = new(Key.C, ModifierKeys.Control | ModifierKeys.Alt);
public void InitApplication(object sender, StartupEventArgs e)
{
Global.TaskbarIcon = (TaskbarIcon)FindResource("FSINotifyIcon");
Global.AdminRights = Admin.CheckAdminRight();
HotkeyManager.Current.AddOrReplace("RadialMenu", RadialMenu, ShowRadialMenu);
HotkeyManager.Current.AddOrReplace("TimeStampToClipboard", TimeStamp, TimeStampToClipboard);
Global.FrmRadialMenu = new();
}
private void ShowRadialMenu(object sender, HotkeyEventArgs e)
{
var cmd = new Commands.RadialMenuCommand();
cmd.Execute(null);
e.Handled = true;
}
private void TimeStampToClipboard(object sender, HotkeyEventArgs e)
{
var cmd = new Commands.TimeStampToClipboardCommand();
cmd.Execute(null);
e.Handled = true;
}
}
}

View File

@@ -0,0 +1,153 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using Hardcodet.Wpf.TaskbarNotification;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Basic implementation of the <see cref="ICommand"/>
/// interface, which is also accessible as a markup
/// extension.
/// </summary>
public abstract class CommandBase<T> : MarkupExtension, ICommand
where T : class, ICommand, new()
{
/// <summary>
/// A singleton instance.
/// </summary>
private static T? command;
/// <summary>
/// Gets a shared command instance.
/// </summary>
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (command == null) command = new T();
return command;
}
/// <summary>
/// Fires when changes occur that affect whether
/// or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command.
/// If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
public abstract void Execute(object parameter);
/// <summary>
/// Defines the method that determines whether the command
/// can execute in its current state.
/// </summary>
/// <returns>
/// This default implementation always returns true.
/// </returns>
/// <param name="parameter">Data used by the command.
/// If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
public virtual bool CanExecute(object parameter)
{
return !IsDesignMode;
}
public static bool IsDesignMode
{
get
{
return (bool)
DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty,
typeof(FrameworkElement))
.Metadata.DefaultValue;
}
}
/// <summary>
/// Resolves the window that owns the TaskbarIcon class.
/// </summary>
/// <param name="commandParameter"></param>
/// <returns>Window</returns>
protected Window? GetTaskbarWindow(object commandParameter)
{
if (IsDesignMode)
return null;
// get the showcase window off the taskbar icon
var tb = commandParameter as TaskbarIcon;
return tb == null ? null : TryFindParent<Window>(tb);
}
#region TryFindParent helper
/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="TParent">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static TParent? TryFindParent<TParent>(DependencyObject child) where TParent : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
if (parentObject is TParent parent)
{
return parent;
}
//use recursion to proceed with next level
return TryFindParent<TParent>(parentObject);
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetParent"/> method, which also
/// supports content elements. Keep in mind that for content element,
/// this method falls back to the logical tree of the element!
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject? GetParentObject(DependencyObject child)
{
if (child == null) return null;
if (child is ContentElement contentElement)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement? fce = contentElement as FrameworkContentElement;
return fce?.Parent;
}
//if it's not a ContentElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
#endregion
}
}

View File

@@ -0,0 +1,20 @@
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class ExitCommand : CommandBase<ExitCommand>
{
public override void Execute(object parameter)
{
Application.Current.Shutdown();
}
public override bool CanExecute(object parameter)
{
return true;
}
}
}

View File

@@ -0,0 +1,29 @@
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class LoginCommand : CommandBase<LoginCommand>
{
public override void Execute(object parameter)
{
Lib.Guis.AutoPw.FrmMain frmMain = new()
{
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
frmMain.ShowDialog();
Global.UserRights =
Global.AdminRights = frmMain.PwOk;
}
public override bool CanExecute(object parameter)
{
return true;
}
}
}

View File

@@ -0,0 +1,313 @@
using FSI.Lib;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class OpenAppCommand : CommandBase<OpenAppCommand>
{
public override void Execute(object parameter)
{
string[] files = new string[] { };
string[] pathes = new string[] { };
string arguments = string.Empty;
switch ((string)parameter)
{
case "SimaticManager":
files = Global.Settings.Apps.SieSimaticManagerExe.Split(";");
break;
case "TIAv13":
files = Global.Settings.Apps.SieTiaV13Exe.Split(";");
break;
case "TIAv14":
files = Global.Settings.Apps.SieTiaV14Exe.Split(";");
break;
case "TIAv15":
files = Global.Settings.Apps.SieTiaV15Exe.Split(";");
break;
case "TIAv16":
files = Global.Settings.Apps.SieTiaV16Exe.Split(";");
break;
case "TIAv17":
files = Global.Settings.Apps.SieTiaV17Exe.Split(";");
break;
case "Starter":
files = Global.Settings.Apps.SieTiaVStarterExe.Split(";");
break;
case "Epl":
files = Global.Settings.Apps.Epl.Exe.Split(";");
arguments = Global.Settings.Apps.Epl.Arguments;
break;
case "EplPrj":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPrj = new()
{
ShowPdf = false,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
frmMainEplPrj.Show();
return;
case "EplPdf":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPdf = new()
{
ShowPdf = true,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
frmMainEplPdf.Show();
return;
case "EplPdfMgt":
Lib.Guis.Pdf.Mgt.FrmMain frmMainEplPdfMgt = new()
{
CloseAtLostFocus = true
};
frmMainEplPdfMgt.Show();
return;
case "Npp":
files = Global.Settings.Apps.NppExe.Split(";");
break;
case "TotalCmd":
files = Global.Settings.Apps.TotalCmdExe.Split(";");
break;
case "TeXstudio":
files = Global.Settings.Apps.TeXstudioExe.Split(";");
pathes = Global.Settings.Apps.TeXstudioPath.Split(";");
break;
case "VS":
files = Global.Settings.Apps.VsExe.Split(";");
break;
case "VS.Code":
files = Global.Settings.Apps.VsCodeExe.Split(";");
break;
case "Rdp":
files = Global.Settings.Apps.RdpExe.Split(";"); ;
break;
case "DeEncrypt":
Lib.Guis.DeEncryptMessage.FrmMain frmMainDeEnCrypt = new()
{
Password = Global.Settings.General.DeEnCryptPasswort,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
frmMainDeEnCrypt.Show();
return;
case "StarterCsvExporter":
Lib.Guis.SieStarterCsvExporter.FrmMain frmMain = new();
frmMain.Show();
return;
}
string fileName = string.Empty;
string path = string.Empty;
for (int i = 0; i <= files.Length - 1; i++)
{
if (File.Exists(Environment.ExpandEnvironmentVariables(files[i].Trim())))
{
fileName = Environment.ExpandEnvironmentVariables(files[i].Trim());
}
if (pathes.Length == 0)
{
path = Path.GetDirectoryName(fileName);
}
else
{
path = Environment.ExpandEnvironmentVariables(pathes[i].Trim());
}
}
if (ProgramIsRunning(fileName))
{
ProgramToFront(fileName);
}
else
{
Process process = new();
process.StartInfo.FileName = fileName;
process.StartInfo.WorkingDirectory = path;
process.StartInfo.Arguments = arguments;
try
{
process.Start();
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 740)
{
try
{
process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas";
process.Start();
}
catch { }
}
}
}
public override bool CanExecute(object parameter)
{
string[] files = new string[] { };
switch ((string)parameter)
{
case "SimaticManager":
files = Global.Settings.Apps.SieSimaticManagerExe.Split(";");
break;
case "TIAv13":
files = Global.Settings.Apps.SieTiaV13Exe.Split(";");
break;
case "TIAv14":
files = Global.Settings.Apps.SieTiaV14Exe.Split(";");
break;
case "TIAv15":
files = Global.Settings.Apps.SieTiaV15Exe.Split(";");
break;
case "TIAv16":
files = Global.Settings.Apps.SieTiaV16Exe.Split(";");
break;
case "TIAv17":
files = Global.Settings.Apps.SieTiaV17Exe.Split(";");
break;
case "Starter":
files = Global.Settings.Apps.SieTiaVStarterExe.Split(";");
break;
case "Epl":
files = Global.Settings.Apps.Epl.Exe.Split(";");
break;
case "EplPrj":
return true;
case "EplPdf":
return true;
case "EplPdfMgt":
return Global.AdminRights;
case "Npp":
files = Global.Settings.Apps.NppExe.Split(";");
break;
case "TotalCmd":
files = Global.Settings.Apps.TotalCmdExe.Split(";");
break;
case "TeXstudio":
files = Global.Settings.Apps.TeXstudioExe.Split(";");
break;
case "VS":
files = Global.Settings.Apps.VsExe.Split(";");
break;
case "VS.Code":
files = Global.Settings.Apps.VsCodeExe.Split(";");
break;
case "Rdp":
files = Global.Settings.Apps.RdpExe.Split(";"); ;
break;
case "DeEncrypt":
return Global.AdminRights;
case "StarterCsvExporter":
return Global.AdminRights;
default: return false;
}
foreach (string file in files)
{
if (File.Exists(Environment.ExpandEnvironmentVariables(file.Trim())))
{
return true;
}
}
return false;
}
private bool ProgramIsRunning(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
bool isRunning = false;
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
isRunning = true;
break;
}
}
return isRunning;
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
private void ProgramToFront(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
IntPtr handle = p.MainWindowHandle;
if (IsIconic(handle))
{
ShowWindow(handle, 9);
}
SetForegroundWindow(handle);
break;
}
}
}
}
}

View File

@@ -0,0 +1,79 @@
using FSI.Lib;
using System;
using System.Diagnostics;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class OpenLinkCommand : CommandBase<OpenLinkCommand>
{
public override void Execute(object parameter)
{
string url = String.Empty;
switch ((string)parameter)
{
case "ZentralWeb":
url = Global.Settings.Urls.ZentralWeb;
break;
case "Schichtbuch":
url = Global.Settings.Urls.Schichtbuch;
break;
case "SPS":
url = Global.Settings.Urls.SPS;
break;
case "PL1.Pls":
url = Global.Settings.Urls.Pl1Pls;
break;
case "PL2.Pls":
url = Global.Settings.Urls.Pl2Pls;
break;
case "PL2.Als":
url = Global.Settings.Urls.Pl2Als;
break;
case "PL3.Pls":
url = Global.Settings.Urls.Pl3Pls;
break;
case "FSI.Gitea":
url = Global.Settings.Urls.Gitea;
break;
case "FSI.Wiki":
url = Global.Settings.Urls.Wiki;
break;
case "Erp":
url = Global.Settings.Urls.Erp;
break;
}
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
public override bool CanExecute(object parameter)
{
string url = String.Empty;
switch ((string)parameter)
{
case "FSI.Gitea":
return Global.AdminRights;
case "FSI.Wiki":
return Global.AdminRights;
default:
return true;
}
}
}
}

View File

@@ -0,0 +1,37 @@
using FSI.Lib.Wpf.ExtensionMethods;
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class RadialMenuCommand : CommandBase<RadialMenuCommand>
{
public override void Execute(object parameter)
{
if (Global.FrmRadialMenu.Visibility == Visibility.Collapsed)
{
Global.FrmRadialMenu.ShowCenteredToMouse();
Global.FrmRadialMenu.ActivateCenteredToMouse();
return;
}
if (Global.FrmRadialMenu.Visibility == Visibility.Hidden)
{
Global.FrmRadialMenu.Visibility = Visibility.Visible;
}
else
{
Global.FrmRadialMenu.Visibility = Visibility.Hidden;
}
Global.FrmRadialMenu.ActivateCenteredToMouse();
}
public override bool CanExecute(object parameter)
{
return Global.AdminRights || Global.UserRights;
}
}
}

View File

@@ -0,0 +1,26 @@
using System.Windows.Controls.Primitives;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class TimeStampToClipboardCommand : CommandBase<TimeStampToClipboardCommand>
{
public override void Execute(object parameter)
{
System.Windows.Forms.Clipboard.SetDataObject(Global.Settings.General.TimeStampFormat);
var balloon = new ToolTip()
{
BalloonText = "Zeitstempel",
BalloonDesc = "Der aktuelle Zeitstempel wurde in die Zwischenablage kopiert."
};
Global.TaskbarIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, 2000);
}
public override bool CanExecute(object parameter)
{
return true;
}
}
}

View File

@@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0-windows</TargetFrameworks>
<OutputType>WinExe</OutputType>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<ApplicationIcon>Icons\FondiumU.ico</ApplicationIcon>
<AssemblyVersion>0.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Icons\Erp.png" />
<None Remove="Icons\Plc.jpg" />
<None Remove="Icons\Rdp.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FSI.Lib\FSI.Lib\FSI.Lib.csproj" />
<ProjectReference Include="..\NHotkey\NHotkey.Wpf\NHotkey.Wpf.csproj" />
<ProjectReference Include="..\NotifyIconWpf\NotifyIconWpf\NotifyIconWpf.csproj" />
<ProjectReference Include="..\RadialMenu\RadialMenu.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\1087815.png" />
<Resource Include="Icons\Circuit.png" />
<Resource Include="Icons\Close.png" />
<Resource Include="Icons\Crypt.jpg" />
<Resource Include="Icons\EplP8.png" />
<Resource Include="Icons\Erp.png" />
<Resource Include="Icons\FondiumU.ico" />
<Resource Include="Icons\FU.png" />
<Resource Include="Icons\Gitea.png" />
<Resource Include="Icons\Info.png" />
<Resource Include="Icons\Links.png" />
<Resource Include="Icons\NPP.png" />
<Resource Include="Icons\Pdf.png" />
<Resource Include="Icons\Plc.jpg" />
<Resource Include="Icons\Rdp.png" />
<Resource Include="Icons\SIE.png" />
<Resource Include="Icons\STEP7.png" />
<Resource Include="Icons\TIAv13.jpg" />
<Resource Include="Icons\TIAv14.jpg" />
<Resource Include="Icons\TIAv15.jpg" />
<Resource Include="Icons\TIAv16.jpg" />
<Resource Include="Icons\TIAv17.jpg" />
<Resource Include="Icons\Tools.png" />
<Resource Include="Icons\TotalCmd.jfif" />
<Resource Include="Icons\Vs.png" />
<Resource Include="Icons\VsCode.png" />
<Resource Include="Icons\TeXstudio.png" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,724 @@
<Window x:Class="FSI.BT.Tools.FrmRadialMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:RadialMenu="clr-namespace:RadialMenu.Controls;assembly=RadialMenu"
xmlns:commands="clr-namespace:FSI.BT.Tools.Commands"
SizeToContent="WidthAndHeight"
WindowStyle="None"
ShowInTaskbar="False"
AllowsTransparency="True"
Background="Transparent"
Deactivated="Window_Deactivated">
<Window.Resources>
<ResourceDictionary Source="Utils/Icons.xaml" />
</Window.Resources>
<Canvas Name="cnvMain"
Height="300"
Width="300">
<!-- Draws a circle with a blue interior. -->
<Ellipse Width="{Binding ElementName=cnvMain,
Path=ActualWidth}"
Height="300"
Fill="WhiteSmoke"
Canvas.Left="0"
Canvas.Top="0">
</Ellipse>
<Grid>
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock x:Name="tbversion"
Margin="0 38 0 0"
FontSize="10" />
</StackPanel>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenHome}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding CloseRadialMenuHome}" >
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenRadialMenuEpl}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="40"
Height="40">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/EplP8.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Eplan
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenRadialMenuTools}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="40"
Height="40">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Tools.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Tools
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenRadialMenuSie}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="40"
Height="40">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/SIE.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Siemens
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TotalCmd"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TotalCmd.jfif" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Total CMD
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="Npp"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/NPP.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Notepad++
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenRadialMenuLinks}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Links
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenEpl}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding OpenRadialMenuHome}">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="Epl"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/EplP8.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Eplan
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="EplPrj"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/1087815.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Projekt-Auswahl
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="EplPdf"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Circuit.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PDF-Auswahl
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenEplPdfMgt}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="35"
Height="35">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Pdf.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PDF-Mgt.
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenTools}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding OpenRadialMenuHome}"
Click="RadialMenuItem_Click">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="DeEncrypt"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="40"
Height="40">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Crypt.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Ver-/<LineBreak />Entschlüsseln
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="Rdp"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Rdp.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Remote<LineBreak />Desktop
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="VS"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Vs.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Visual Studio
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="VS.Code"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/VsCode.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Visual Studio<LineBreak />Code
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TeXstudio"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TeXstudio.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TeXstudio
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="StarterCsvExporter"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="40"
Height="40">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FU.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Starter<LineBreak />CSV-Exporter
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenSie}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding OpenRadialMenuHome}">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="SimaticManager"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/STEP7.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Step 7<LineBreak />Classic
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TIAv13"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TIAv13.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TIA V13
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TIAv14"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TIAv14.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TIA V14
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TIAv15"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TIAv15.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TIA V15
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TIAv16"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TIAv16.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TIA V16
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="TIAv17"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/TIAv17.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
TIA V17
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenAppCommand}"
CommandParameter="Starter"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="50"
Height="50">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FU.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Starter
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenLinks}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding OpenRadialMenuHome}"
Click="RadialMenuItem_Click">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{Binding OpenRadialMenuPlantLinks}"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Anlagen<LineBreak />Links
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="Erp"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Erp.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Infor
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="ZentralWeb"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Zentraler<LineBreak />Webserver
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="Schichtbuch"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Schichtbuch
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="SPS"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Plc.jpg" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
SPS<LineBreak />Änderungen
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="FSI.Gitea"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Gitea.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
FSI<LineBreak />Gitea
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="FSI.Wiki"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
FSI<LineBreak />Wikipedia
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
<RadialMenu:RadialMenu IsOpen="{Binding IsOpenPlantLinks}">
<RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuCentralItem Command="{Binding OpenRadialMenuLinks}">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/FondiumU.ico" />
</Rectangle.Fill>
</Rectangle>
</RadialMenu:RadialMenuCentralItem>
</RadialMenu:RadialMenu.CentralItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="ZentralWeb"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
Zentraler<LineBreak />Webserver
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="PL1.PLS"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PL1 PLS
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="PL2.PLS"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PL2 PLS
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="PL2.Als"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PL2 ALS
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
<RadialMenu:RadialMenuItem Command="{commands:OpenLinkCommand}"
CommandParameter="PL3.Pls"
Click="RadialMenuItem_Click">
<WrapPanel Orientation="Vertical">
<Rectangle Width="30"
Height="30">
<Rectangle.Fill>
<ImageBrush ImageSource="../../Icons/Links.png" />
</Rectangle.Fill>
</Rectangle>
<TextBlock FontSize="14"
TextAlignment="Center">
PL3 PLS
</TextBlock>
</WrapPanel>
</RadialMenu:RadialMenuItem>
</RadialMenu:RadialMenu>
</Grid>
</Canvas>
</Window>

View File

@@ -0,0 +1,266 @@
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
namespace FSI.BT.Tools
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class FrmRadialMenu : Window, INotifyPropertyChanged
{
public FrmRadialMenu()
{
InitializeComponent();
DataContext = this;
_isOpenHome = true;
tbversion.Text = "v" + Assembly.GetExecutingAssembly().GetName().Version.Major + "." + Assembly.GetExecutingAssembly().GetName().Version.Minor;
}
#region Home
private bool _isOpenHome = true;
public bool IsOpenHome
{
get
{
return _isOpenHome;
}
set
{
_isOpenHome = value;
RaisePropertyChanged();
}
}
public ICommand CloseRadialMenuHome
{
get
{
return new RelayCommand(() => Visibility = Visibility.Hidden);
}
}
public ICommand OpenRadialMenuHome
{
get
{
return new RelayCommand(() =>
{
IsOpenHome = true;
IsOpenEpl =
IsOpenTools =
IsOpenSie =
IsOpenLinks = false;
});
}
}
#endregion
#region Epl
private bool _isOpenEpl = false;
public bool IsOpenEpl
{
get
{
return _isOpenEpl;
}
set
{
_isOpenEpl = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuEpl
{
get
{
return new RelayCommand(() =>
{
IsOpenEpl = true;
IsOpenHome = false;
});
}
}
#endregion
#region Tools
private bool _isOpenTools = false;
public bool IsOpenTools
{
get
{
return _isOpenTools;
}
set
{
_isOpenTools = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuTools
{
get
{
return new RelayCommand(() =>
{
IsOpenTools = true;
IsOpenHome = false;
});
}
}
#endregion
#region Siemens
private bool _isOpenSie = false;
public bool IsOpenSie
{
get
{
return _isOpenSie;
}
set
{
_isOpenSie = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuSie
{
get
{
return new RelayCommand(() =>
{
IsOpenSie = true;
IsOpenHome = false;
});
}
}
#endregion
#region Links
private bool _isOpenLinks = false;
public bool IsOpenLinks
{
get
{
return _isOpenLinks;
}
set
{
_isOpenLinks = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuLinks
{
get
{
return new RelayCommand(() =>
{
IsOpenLinks = true;
IsOpenPlantLinks =
IsOpenHome = false;
});
}
}
#endregion
#region Anlagen Links
private bool _isOpenPlantLinks = false;
public bool IsOpenPlantLinks
{
get
{
return _isOpenPlantLinks;
}
set
{
_isOpenPlantLinks = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuPlantLinks
{
get
{
return new RelayCommand(() =>
{
IsOpenPlantLinks = true;
IsOpenLinks = false;
});
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void Window_Deactivated(object sender, EventArgs e)
{
Visibility = Visibility.Hidden;
IsOpenHome = true;
IsOpenEpl =
IsOpenTools =
IsOpenSie =
IsOpenLinks =
IsOpenPlantLinks = false;
}
private void RadialMenuItem_Click(object sender, RoutedEventArgs e)
{
int left = Convert.ToInt32(GetActualLeft() + this.ActualWidth / 2);
int top = Convert.ToInt32(GetActuaTop() + this.ActualHeight / 2);
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(left, top);
}
private double GetActualLeft()
{
if (this.WindowState == WindowState.Maximized)
{
var leftField = typeof(Window).GetField("_actualLeft", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
return (double)leftField.GetValue(this);
}
else
return this.Left;
}
private double GetActuaTop()
{
if (this.WindowState == WindowState.Maximized)
{
var topField = typeof(Window).GetField("_actualTop", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
return (double)topField.GetValue(this);
}
else
return this.Top;
}
}
}

179
FSI.BT.Tools/Global.cs Normal file
View File

@@ -0,0 +1,179 @@
using Hardcodet.Wpf.TaskbarNotification;
namespace FSI.BT.Tools
{
internal static class Global
{
public static FrmRadialMenu? FrmRadialMenu { get; set; }
public static TaskbarIcon? TaskbarIcon { get; set; }
public static bool UserRights { get; set; }
public static bool AdminRights { get; set; }
public static class Settings
{
public static class General
{
public static string DeEnCryptPasswort
{
get
{
return FSI.Lib.Settings.Setting<string>("DeEnCryptPasswort", Lib.Settings.Mode.ExeSetttings);
}
}
public static string TimeStampFormat
{
get
{
return FSI.Lib.Settings.Setting<string>("TimeStamp.Format", Lib.Settings.Mode.ExeSetttings);
}
}
}
public static class Apps
{
public static string SieSimaticManagerExe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.Simatic.Manager.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaV13Exe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.TIA.V13.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaV14Exe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.TIA.V14.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaV15Exe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.TIA.V15.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaV16Exe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.TIA.V16.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaV17Exe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.TIA.V17.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SieTiaVStarterExe
{
get { return FSI.Lib.Settings.Setting<string>("SIE.Starter.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static class Epl
{
public static string Exe
{
get { return FSI.Lib.Settings.Setting<string>("Epl.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Arguments
{
get { return "/Variant:\"Electric P8\""; }
}
}
public static string NppExe
{
get { return FSI.Lib.Settings.Setting<string>("Npp.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string TotalCmdExe
{
get { return FSI.Lib.Settings.Setting<string>("TotalCmd.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string TeXstudioExe
{
get { return FSI.Lib.Settings.Setting<string>("TeXstudio.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string TeXstudioPath
{
get { return FSI.Lib.Settings.Setting<string>("TeXstudio.Path", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string VsExe
{
get { return FSI.Lib.Settings.Setting<string>("VS.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string VsCodeExe
{
get { return FSI.Lib.Settings.Setting<string>("VS.Code.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string RdpExe
{
get { return FSI.Lib.Settings.Setting<string>("Rdp.Exe", FSI.Lib.Settings.Mode.ExeSetttings); }
}
}
public static class Urls
{
public static string ZentralWeb
{
get { return FSI.Lib.Settings.Setting<string>("ZentralWeb.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Schichtbuch
{
get { return FSI.Lib.Settings.Setting<string>("Schichtbuch.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string SPS
{
get { return FSI.Lib.Settings.Setting<string>("SPS.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Pl1Pls
{
get { return FSI.Lib.Settings.Setting<string>("PL1.Pls.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Pl2Pls
{
get { return FSI.Lib.Settings.Setting<string>("PL2.Pls.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Pl2Als
{
get { return FSI.Lib.Settings.Setting<string>("PL2.Als.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Pl3Pls
{
get { return FSI.Lib.Settings.Setting<string>("PL3.Pls.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Gitea
{
get { return FSI.Lib.Settings.Setting<string>("FSI.Gitea.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Wiki
{
get { return FSI.Lib.Settings.Setting<string>("FSI.Gitea.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
public static string Erp
{
get { return FSI.Lib.Settings.Setting<string>("Erp.Url", FSI.Lib.Settings.Mode.ExeSetttings); }
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
FSI.BT.Tools/Icons/Erp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
FSI.BT.Tools/Icons/FU.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
FSI.BT.Tools/Icons/Info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
FSI.BT.Tools/Icons/NPP.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
FSI.BT.Tools/Icons/Pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
FSI.BT.Tools/Icons/Plc.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
FSI.BT.Tools/Icons/Rdp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
FSI.BT.Tools/Icons/SIE.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
FSI.BT.Tools/Icons/Vs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -0,0 +1,31 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:commands="clr-namespace:FSI.BT.Tools.Commands">
<LinearGradientBrush x:Key="MenuBackground"
EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="#FFFFD892"
Offset="1" />
<GradientStop Color="#FFFFF3DD"
Offset="0.259" />
</LinearGradientBrush>
<tb:TaskbarIcon x:Key="FSINotifyIcon"
Visibility="Visible"
ToolTipText="FSI Tools"
IconSource="/Icons/FondiumU.ico"
MenuActivation="RightClick"
DoubleClickCommand="{commands:LoginCommand}"
LeftClickCommand="{commands:TimeStampToClipboardCommand}">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Beenden"
Command="{commands:ExitCommand}"/>
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
</ResourceDictionary>

View File

@@ -0,0 +1,46 @@
using System;
using System.Windows.Input;
namespace FSI.BT.Tools
{
public class RelayCommand : ICommand
{
private Action action;
private Func<bool> condition;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action action)
{
this.action = action;
condition = () => true;
}
public RelayCommand(Action action, bool condition)
{
this.action = action;
this.condition = () => condition;
}
public RelayCommand(Action action, Func<bool> condition)
{
this.action = action;
this.condition = condition;
}
public bool CanExecute(object parameter)
{
return condition.Invoke();
}
void ICommand.Execute(object parameter)
{
action.Invoke();
}
}
}

158
FSI.BT.Tools/ToolTip.xaml Normal file
View File

@@ -0,0 +1,158 @@
<UserControl x:Class="FSI.BT.Tools.ToolTip"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
x:Name="me"
Height="120"
Width="240">
<UserControl.Resources>
<Storyboard x:Key="FadeIn">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="0.95" />
<SplineDoubleKeyFrame KeyTime="00:00:03"
Value="0.95" />
<!-- <SplineDoubleKeyFrame KeyTime="00:00:05" Value="0"/>-->
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="HighlightCloseButton">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="imgClose"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0.4" />
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000"
Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="FadeCloseButton">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="imgClose"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="1" />
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000"
Value="0.4" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="FadeBack">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="1" />
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000"
Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="FadeOut"
Completed="OnFadeOutCompleted">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="grid"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="1" />
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000"
Value="0.2" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="tb:TaskbarIcon.BalloonShowing">
<BeginStoryboard Storyboard="{StaticResource FadeIn}"
x:Name="FadeIn_BeginStoryboard" />
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter"
SourceName="imgClose">
<BeginStoryboard Storyboard="{StaticResource HighlightCloseButton}"
x:Name="HighlightCloseButton_BeginStoryboard" />
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave"
SourceName="imgClose">
<BeginStoryboard Storyboard="{StaticResource FadeCloseButton}"
x:Name="FadeCloseButton_BeginStoryboard" />
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<StopStoryboard BeginStoryboardName="FadeIn_BeginStoryboard" />
<BeginStoryboard x:Name="FadeBack_BeginStoryboard1"
Storyboard="{StaticResource FadeBack}" />
</EventTrigger>
<EventTrigger RoutedEvent="tb:TaskbarIcon.BalloonClosing">
<BeginStoryboard Storyboard="{StaticResource FadeOut}"
x:Name="FadeOut_BeginStoryboard" />
</EventTrigger>
</UserControl.Triggers>
<Grid x:Name="grid"
MouseEnter="grid_MouseEnter">
<Border HorizontalAlignment="Stretch"
Margin="5,5,5,5"
BorderThickness="1,1,1,1"
BorderBrush="#FF997137">
<Border.Effect>
<DropShadowEffect Color="#FF747474" />
</Border.Effect>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="#FF4B4B4B"
Offset="0" />
<GradientStop Color="#FF8F8F8F"
Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Image HorizontalAlignment="Left"
Margin="0,10,0,0"
Width="72"
Source="/Icons/Info.png"
Stretch="Fill"
Height="72"
VerticalAlignment="Top" />
<TextBlock Margin="72,49.2,10,0"
VerticalAlignment="Top"
Foreground="#FFECAD25"
TextWrapping="Wrap">
<Run Text="{Binding Path=BalloonDesc, ElementName=me, Mode=Default}" />
</TextBlock>
<Path Fill="#FFFFFFFF"
Stretch="Fill"
Margin="72,38.2,34,0"
VerticalAlignment="Top"
Height="1"
Data="M26,107 L220.04123,107"
SnapsToDevicePixels="True">
<Path.Stroke>
<LinearGradientBrush EndPoint="0.973,0.5"
StartPoint="0.005,0.5">
<GradientStop Color="#00ECAD25"
Offset="1" />
<GradientStop Color="#87ECAD25"
Offset="0" />
</LinearGradientBrush>
</Path.Stroke>
</Path>
<TextBlock Margin="72,10,10,0"
VerticalAlignment="Top"
Height="23.2"
Text="{Binding Path=BalloonText, ElementName=me, Mode=Default}"
TextWrapping="Wrap"
Foreground="#FFECAD25"
FontWeight="Bold" />
<Image HorizontalAlignment="Right"
Margin="0,10,10,0"
VerticalAlignment="Top"
Width="16"
Height="16"
Source="/Icons/Close.png"
Stretch="Fill"
Opacity="0.4"
ToolTip="Close Balloon"
x:Name="imgClose"
MouseDown="imgClose_MouseDown" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,116 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using Hardcodet.Wpf.TaskbarNotification;
namespace FSI.BT.Tools
{
/// <summary>
/// Interaktionslogik für ToolTip.xaml
/// </summary>
public partial class ToolTip : UserControl
{
private bool isClosing = false;
#region BalloonText dependency property
/// <summary>
/// Description
/// </summary>
public static readonly DependencyProperty BalloonTextProperty =
DependencyProperty.Register(nameof(BalloonText),
typeof(string),
typeof(ToolTip),
new FrameworkPropertyMetadata(string.Empty));
/// <summary>
/// A property wrapper for the <see cref="BalloonTextProperty"/>
/// dependency property:<br/>
/// Description
/// </summary>
public string BalloonText
{
get { return (string)GetValue(BalloonTextProperty); }
set { SetValue(BalloonTextProperty, value); }
}
/// <summary>
/// Description
/// </summary>
public static readonly DependencyProperty BalloonDescProperty =
DependencyProperty.Register(nameof(BalloonDesc),
typeof(string),
typeof(ToolTip),
new FrameworkPropertyMetadata(string.Empty));
/// <summary>
/// A property wrapper for the <see cref="BalloonDescProperty"/>
/// dependency property:<br/>
/// Description
/// </summary>
public string BalloonDesc
{
get { return (string)GetValue(BalloonDescProperty); }
set { SetValue(BalloonDescProperty, value); }
}
#endregion
public ToolTip()
{
InitializeComponent();
TaskbarIcon.AddBalloonClosingHandler(this, OnBalloonClosing);
}
/// <summary>
/// By subscribing to the <see cref="TaskbarIcon.BalloonClosingEvent"/>
/// and setting the "Handled" property to true, we suppress the popup
/// from being closed in order to display the custom fade-out animation.
/// </summary>
private void OnBalloonClosing(object sender, RoutedEventArgs e)
{
e.Handled = true; //suppresses the popup from being closed immediately
isClosing = true;
}
/// <summary>
/// Resolves the <see cref="TaskbarIcon"/> that displayed
/// the balloon and requests a close action.
/// </summary>
private void imgClose_MouseDown(object sender, MouseButtonEventArgs e)
{
//the tray icon assigned this attached property to simplify access
TaskbarIcon taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this);
taskbarIcon.CloseBalloon();
}
/// <summary>
/// If the users hovers over the balloon, we don't close it.
/// </summary>
private void grid_MouseEnter(object sender, MouseEventArgs e)
{
//if we're already running the fade-out animation, do not interrupt anymore
//(makes things too complicated for the sample)
if (isClosing) return;
//the tray icon assigned this attached property to simplify access
TaskbarIcon taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this);
taskbarIcon.ResetBalloonCloseTimer();
}
/// <summary>
/// Closes the popup once the fade-out animation completed.
/// The animation was triggered in XAML through the attached
/// BalloonClosing event.
/// </summary>
private void OnFadeOutCompleted(object sender, EventArgs e)
{
Popup pp = (Popup)Parent;
pp.IsOpen = false;
}
}
}

File diff suppressed because one or more lines are too long

400
NHotkey/.gitignore vendored Normal file
View File

@@ -0,0 +1,400 @@
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

View File

@@ -0,0 +1,22 @@
<Project>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)NHotkey.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Authors>Thomas Levesque</Authors>
<PackageProjectUrl>https://github.com/thomaslevesque/NHotkey</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageTags>global;hotkey;windows</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="2.3.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
// Enables extension methods in assembly that targets .NET 2.0
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Method)]
internal sealed class ExtensionAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,12 @@
using System.Windows.Forms;
namespace NHotkey.WindowsForms
{
static class Extensions
{
public static bool HasFlag(this Keys keys, Keys flag)
{
return (keys & flag) == flag;
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Windows.Forms;
namespace NHotkey.WindowsForms
{
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Design",
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
Justification = "This is a singleton; disposing it would break it")]
public class HotkeyManager : HotkeyManagerBase
{
#region Singleton implementation
public static HotkeyManager Current { get { return LazyInitializer.Instance; } }
private static class LazyInitializer
{
static LazyInitializer() { }
public static readonly HotkeyManager Instance = new HotkeyManager();
}
#endregion
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly MessageWindow _messageWindow;
private HotkeyManager()
{
_messageWindow = new MessageWindow(this);
SetHwnd(_messageWindow.Handle);
}
public void AddOrReplace(string name, Keys keys, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
{
var flags = GetFlags(keys, noRepeat);
var vk = unchecked((uint)(keys & ~Keys.Modifiers));
AddOrReplace(name, vk, flags, handler);
}
public void AddOrReplace(string name, Keys keys, EventHandler<HotkeyEventArgs> handler)
{
AddOrReplace(name, keys, false, handler);
}
private static HotkeyFlags GetFlags(Keys hotkey, bool noRepeat)
{
var noMod = hotkey & ~Keys.Modifiers;
var flags = HotkeyFlags.None;
if (hotkey.HasFlag(Keys.Alt))
flags |= HotkeyFlags.Alt;
if (hotkey.HasFlag(Keys.Control))
flags |= HotkeyFlags.Control;
if (hotkey.HasFlag(Keys.Shift))
flags |= HotkeyFlags.Shift;
if (noMod == Keys.LWin || noMod == Keys.RWin)
flags |= HotkeyFlags.Windows;
if (noRepeat)
flags |= HotkeyFlags.NoRepeat;
return flags;
}
class MessageWindow : ContainerControl
{
private readonly HotkeyManager _hotkeyManager;
public MessageWindow(HotkeyManager hotkeyManager)
{
_hotkeyManager = hotkeyManager;
}
protected override CreateParams CreateParams
{
get
{
var parameters = base.CreateParams;
parameters.Parent = HwndMessage;
return parameters;
}
}
protected override void WndProc(ref Message m)
{
bool handled = false;
Hotkey hotkey;
m.Result = _hotkeyManager.HandleHotkeyMessage(Handle, m.Msg, m.WParam, m.LParam, ref handled, out hotkey);
if (!handled)
base.WndProc(ref m);
}
}
}
}

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net40;net45;netcoreapp3.0</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Description>A managed library to handle global hotkeys in Windows Forms applications. This package contains the concrete HotkeyManager implementation for Windows Forms.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,17 @@
using System.Windows.Input;
namespace NHotkey.Wpf
{
static class Extensions
{
public static bool HasFlag(this ModifierKeys modifiers, ModifierKeys flag)
{
return (modifiers & flag) == flag;
}
public static bool HasFlag(this HotkeyFlags flags, HotkeyFlags flag)
{
return (flags & flag) == flag;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace NHotkey.Wpf
{
public class HotkeyAlreadyRegisteredEventArgs : EventArgs
{
private readonly string _name;
public HotkeyAlreadyRegisteredEventArgs(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
}

View File

@@ -0,0 +1,249 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace NHotkey.Wpf
{
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Design",
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
Justification = "This is a singleton; disposing it would break it")]
public class HotkeyManager : HotkeyManagerBase
{
#region Singleton implementation
public static HotkeyManager Current { get { return LazyInitializer.Instance; } }
private static class LazyInitializer
{
static LazyInitializer() { }
public static readonly HotkeyManager Instance = new HotkeyManager();
}
public void AddOrReplace(string v, object incrementKeys, object onIncrement)
{
throw new NotImplementedException();
}
#endregion
#region Attached property for KeyBindings
[AttachedPropertyBrowsableForType(typeof(KeyBinding))]
public static bool GetRegisterGlobalHotkey(KeyBinding binding)
{
return (bool)binding.GetValue(RegisterGlobalHotkeyProperty);
}
public static void SetRegisterGlobalHotkey(KeyBinding binding, bool value)
{
binding.SetValue(RegisterGlobalHotkeyProperty, value);
}
public static readonly DependencyProperty RegisterGlobalHotkeyProperty =
DependencyProperty.RegisterAttached(
"RegisterGlobalHotkey",
typeof(bool),
typeof(HotkeyManager),
new PropertyMetadata(
false,
RegisterGlobalHotkeyPropertyChanged));
private static void RegisterGlobalHotkeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var keyBinding = d as KeyBinding;
if (keyBinding == null)
return;
bool oldValue = (bool) e.OldValue;
bool newValue = (bool) e.NewValue;
if (DesignerProperties.GetIsInDesignMode(d))
return;
if (oldValue && !newValue)
{
Current.RemoveKeyBinding(keyBinding);
}
else if (newValue && !oldValue)
{
Current.AddKeyBinding(keyBinding);
}
}
#endregion
#region HotkeyAlreadyRegistered event
public static event EventHandler<HotkeyAlreadyRegisteredEventArgs> HotkeyAlreadyRegistered;
private static void OnHotkeyAlreadyRegistered(string name)
{
var handler = HotkeyAlreadyRegistered;
if (handler != null)
handler(null, new HotkeyAlreadyRegisteredEventArgs(name));
}
#endregion
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly HwndSource _source;
private readonly WeakReferenceCollection<KeyBinding> _keyBindings;
private HotkeyManager()
{
_keyBindings = new WeakReferenceCollection<KeyBinding>();
var parameters = new HwndSourceParameters("Hotkey sink")
{
HwndSourceHook = HandleMessage,
ParentWindow = HwndMessage
};
_source = new HwndSource(parameters);
SetHwnd(_source.Handle);
}
public void AddOrReplace(string name, KeyGesture gesture, EventHandler<HotkeyEventArgs> handler)
{
AddOrReplace(name, gesture, false, handler);
}
public void AddOrReplace(string name, KeyGesture gesture, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
{
AddOrReplace(name, gesture.Key, gesture.Modifiers, noRepeat, handler);
}
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, EventHandler<HotkeyEventArgs> handler)
{
AddOrReplace(name, key, modifiers, false, handler);
}
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
{
var flags = GetFlags(modifiers, noRepeat);
var vk = (uint)KeyInterop.VirtualKeyFromKey(key);
AddOrReplace(name, vk, flags, handler);
}
private static HotkeyFlags GetFlags(ModifierKeys modifiers, bool noRepeat)
{
var flags = HotkeyFlags.None;
if (modifiers.HasFlag(ModifierKeys.Shift))
flags |= HotkeyFlags.Shift;
if (modifiers.HasFlag(ModifierKeys.Control))
flags |= HotkeyFlags.Control;
if (modifiers.HasFlag(ModifierKeys.Alt))
flags |= HotkeyFlags.Alt;
if (modifiers.HasFlag(ModifierKeys.Windows))
flags |= HotkeyFlags.Windows;
if (noRepeat)
flags |= HotkeyFlags.NoRepeat;
return flags;
}
private static ModifierKeys GetModifiers(HotkeyFlags flags)
{
var modifiers = ModifierKeys.None;
if (flags.HasFlag(HotkeyFlags.Shift))
modifiers |= ModifierKeys.Shift;
if (flags.HasFlag(HotkeyFlags.Control))
modifiers |= ModifierKeys.Control;
if (flags.HasFlag(HotkeyFlags.Alt))
modifiers |= ModifierKeys.Alt;
if (flags.HasFlag(HotkeyFlags.Windows))
modifiers |= ModifierKeys.Windows;
return modifiers;
}
private void AddKeyBinding(KeyBinding keyBinding)
{
var gesture = (KeyGesture)keyBinding.Gesture;
string name = GetNameForKeyBinding(gesture);
try
{
AddOrReplace(name, gesture.Key, gesture.Modifiers, null);
_keyBindings.Add(keyBinding);
}
catch (HotkeyAlreadyRegisteredException)
{
OnHotkeyAlreadyRegistered(name);
}
}
private void RemoveKeyBinding(KeyBinding keyBinding)
{
var gesture = (KeyGesture)keyBinding.Gesture;
string name = GetNameForKeyBinding(gesture);
Remove(name);
_keyBindings.Remove(keyBinding);
}
private readonly KeyGestureConverter _gestureConverter = new KeyGestureConverter();
private string GetNameForKeyBinding(KeyGesture gesture)
{
string name = gesture.DisplayString;
if (string.IsNullOrEmpty(name))
name = _gestureConverter.ConvertToString(gesture);
return name;
}
private IntPtr HandleMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
Hotkey hotkey;
var result = HandleHotkeyMessage(hwnd, msg, wparam, lparam, ref handled, out hotkey);
if (handled)
return result;
if (hotkey != null)
handled = ExecuteBoundCommand(hotkey);
return result;
}
private bool ExecuteBoundCommand(Hotkey hotkey)
{
var key = KeyInterop.KeyFromVirtualKey((int)hotkey.VirtualKey);
var modifiers = GetModifiers(hotkey.Flags);
bool handled = false;
foreach (var binding in _keyBindings)
{
if (binding.Key == key && binding.Modifiers == modifiers)
{
handled |= ExecuteCommand(binding);
}
}
return handled;
}
private static bool ExecuteCommand(InputBinding binding)
{
var command = binding.Command;
var parameter = binding.CommandParameter;
var target = binding.CommandTarget;
if (command == null)
return false;
var routedCommand = command as RoutedCommand;
if (routedCommand != null)
{
if (routedCommand.CanExecute(parameter, target))
{
routedCommand.Execute(parameter, target);
return true;
}
}
else
{
if (command.CanExecute(parameter))
{
command.Execute(parameter);
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net40;net45;netcoreapp3.0;net6.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Description>A managed library to handle global hotkeys in WPF applications. This package contains the concrete HotkeyManager implementation for WPF.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
using System.Windows.Markup;
// Mapping a custom namespace to the standard WPF namespace is usually something to avoid,
// however in this case we're only importing one type (HotkeyManager), and it's unlikely to
// collide with another type in a future version of WPF. So in this case, we do it for the
// sake of simplicity, so that the user doesn't need to map the namespace manually.
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "NHotkey.Wpf")]

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace NHotkey.Wpf
{
class WeakReferenceCollection<T> : IEnumerable<T>
where T : class
{
private readonly List<WeakReference> _references = new List<WeakReference>();
public IEnumerator<T> GetEnumerator()
{
var references = _references.ToList();
foreach (var reference in references)
{
var target = reference.Target;
if (target != null)
yield return (T) target;
}
Trim();
}
public void Add(T item)
{
_references.Add(new WeakReference(item));
}
public void Remove(T item)
{
_references.RemoveAll(r => (r.Target ?? item) == item);
}
public void Trim()
{
_references.RemoveAll(r => !r.IsAlive);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

37
NHotkey/NHotkey.sln Normal file
View File

@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey", "NHotkey\NHotkey.csproj", "{6CAB99C4-6F21-4508-9160-CE4DBF540840}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.WindowsForms", "NHotkey.WindowsForms\NHotkey.WindowsForms.csproj", "{F0D5CDB4-B74A-419B-9AD6-2A438A268837}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.Wpf", "NHotkey.Wpf\NHotkey.Wpf.csproj", "{FC92233F-6F08-45B7-B3EE-7C557582236B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.Build.0 = Release|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.Build.0 = Release|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {67220BE9-A1D5-41B9-9D16-177606E9D4D5}
EndGlobalSection
EndGlobal

BIN
NHotkey/NHotkey.snk Normal file

Binary file not shown.

Binary file not shown.

71
NHotkey/NHotkey/Hotkey.cs Normal file
View File

@@ -0,0 +1,71 @@
using System;
using System.Runtime.InteropServices;
namespace NHotkey
{
internal class Hotkey
{
private static int _nextId;
private readonly int _id;
private readonly uint _virtualKey;
private readonly HotkeyFlags _flags;
private readonly EventHandler<HotkeyEventArgs> _handler;
public Hotkey(uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
{
_id = ++_nextId;
_virtualKey = virtualKey;
_flags = flags;
_handler = handler;
}
public int Id
{
get { return _id; }
}
public uint VirtualKey
{
get { return _virtualKey; }
}
public HotkeyFlags Flags
{
get { return _flags; }
}
public EventHandler<HotkeyEventArgs> Handler
{
get { return _handler; }
}
private IntPtr _hwnd;
public void Register(IntPtr hwnd, string name)
{
if (!NativeMethods.RegisterHotKey(hwnd, _id, _flags, _virtualKey))
{
var hr = Marshal.GetHRForLastWin32Error();
var ex = Marshal.GetExceptionForHR(hr);
if ((uint) hr == 0x80070581)
throw new HotkeyAlreadyRegisteredException(name, ex);
throw ex;
}
_hwnd = hwnd;
}
public void Unregister()
{
if (_hwnd != IntPtr.Zero)
{
if (!NativeMethods.UnregisterHotKey(_hwnd, _id))
{
var hr = Marshal.GetHRForLastWin32Error();
throw Marshal.GetExceptionForHR(hr);
}
_hwnd = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace NHotkey
{
[Serializable]
public class HotkeyAlreadyRegisteredException : Exception
{
private readonly string _name;
public HotkeyAlreadyRegisteredException(string name, Exception inner) : base(inner.Message, inner)
{
_name = name;
HResult = Marshal.GetHRForException(inner);
}
protected HotkeyAlreadyRegisteredException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
_name = (string) info.GetValue("_name", typeof (string));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("_name", _name);
}
public string Name
{
get { return _name; }
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace NHotkey
{
public class HotkeyEventArgs : EventArgs
{
private readonly string _name;
internal HotkeyEventArgs(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
public bool Handled { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NHotkey
{
[Flags]
internal enum HotkeyFlags : uint
{
None = 0x0000,
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Windows = 0x0008,
NoRepeat = 0x4000
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
namespace NHotkey
{
public abstract class HotkeyManagerBase
{
private readonly Dictionary<int, string> _hotkeyNames = new Dictionary<int, string>();
private readonly Dictionary<string, Hotkey> _hotkeys = new Dictionary<string, Hotkey>();
private IntPtr _hwnd;
internal static readonly IntPtr HwndMessage = (IntPtr)(-3);
internal HotkeyManagerBase()
{
}
internal void AddOrReplace(string name, uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
{
var hotkey = new Hotkey(virtualKey, flags, handler);
lock (_hotkeys)
{
Remove(name);
_hotkeys.Add(name, hotkey);
_hotkeyNames.Add(hotkey.Id, name);
if (_hwnd != IntPtr.Zero)
hotkey.Register(_hwnd, name);
}
}
public void Remove(string name)
{
lock (_hotkeys)
{
Hotkey hotkey;
if (_hotkeys.TryGetValue(name, out hotkey))
{
_hotkeys.Remove(name);
_hotkeyNames.Remove(hotkey.Id);
if (_hwnd != IntPtr.Zero)
hotkey.Unregister();
}
}
}
public bool IsEnabled { get; set; } = true;
internal void SetHwnd(IntPtr hwnd)
{
_hwnd = hwnd;
}
private const int WmHotkey = 0x0312;
internal IntPtr HandleHotkeyMessage(
IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam,
ref bool handled,
out Hotkey hotkey)
{
hotkey = null;
if (IsEnabled && msg == WmHotkey)
{
int id = wParam.ToInt32();
string name;
if (_hotkeyNames.TryGetValue(id, out name))
{
hotkey = _hotkeys[name];
var handler = hotkey.Handler;
if (handler != null)
{
var e = new HotkeyEventArgs(name);
handler(this, e);
handled = e.Handled;
}
}
}
return IntPtr.Zero;
}
}
}

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40;net45;netcoreapp3.0;net6.0-windows</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Description>A managed library to handle global hotkeys in Windows Forms and WPF applications. NOTE: this package doesn't contain a concrete HotkeyManager implementation; you should add either the NHotkey.Wpf or NHotkey.WindowsForms package to get one.</Description>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,14 @@
using System;
using System.Runtime.InteropServices;
namespace NHotkey
{
static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyFlags fsModifiers, uint vk);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
}

View File

@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("NHotkey.WindowsForms, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]
[assembly: InternalsVisibleTo("NHotkey.Wpf, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]

2
NHotkey/README.md Normal file
View File

@@ -0,0 +1,2 @@
# NHotkey.Wpf

400
NotifyIconWpf/.gitignore vendored Normal file
View File

@@ -0,0 +1,400 @@
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

View File

@@ -0,0 +1,81 @@
<Project>
<PropertyGroup>
<TargetFrameworks>net45;net462;net472;netcoreapp3.1;net5.0-windows</TargetFrameworks>
<LangVersion>latest</LangVersion>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<IsSampleProject>$(MSBuildProjectName.Contains('Sample'))</IsSampleProject>
<DebugSymbols>True</DebugSymbols>
<DebugType>embedded</DebugType>
<Copyright>Copyright (c) 2009-2021 Philipp Sumi</Copyright>
<Company>hardcodet.net</Company>
<Authors>Philipp Sumi, Robin Krom, Jan Karger</Authors>
<PackageIcon>icon.png</PackageIcon>
<RepositoryUrl>https://github.com/hardcodet/wpf-notifyicon</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://github.com/hardcodet/wpf-notifyicon</PackageProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<Description>This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform. It does not just rely on the Windows Forms NotifyIcon component, but is a purely independent control which leverages several features of the WPF framework in order to display rich tooltips, popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file.
Source code and extensive sample application available at http://www.hardcodet.net/projects/wpf-notifyicon</Description>
<Summary>NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform.</Summary>
<tags>NotifyIcon WPF Tray Notify ToolTip Popup Balloon Toast</tags>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<Choose>
<When Condition=" '$(IsSampleProject)' != 'true' ">
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\NotifyIconWpf.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<None Include="$(SolutionDir)\icon.png" Pack="true" PackagePath="\"/>
</ItemGroup>
<!-- SourceLink -->
<PropertyGroup>
<!-- Optional: Declare that the Repository URL can be published to NuSpec -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- Optional: Embed source files that are not tracked by the source control manager to the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- https://github.com/dotnet/sourcelink/blob/master/docs/README.md#embedallsources -->
<EmbedAllSources>true</EmbedAllSources>
</PropertyGroup>
</When>
</Choose>
<ItemGroup>
<None Remove="**\*.png;**\*.jpg;**\*.ico" />
<Resource Include="**\*.png;**\*.jpg;**\*.ico" />
<None Include="..\..\LICENSE" Pack="true" PackagePath="" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIconWpf", "NotifyIconWpf\NotifyIconWpf.csproj", "{78E6F5E5-11F1-4840-BA37-87522806DEDF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DE07A147-0D17-4667-A1F7-7076FDFF4AEA}
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@@ -0,0 +1,52 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 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
namespace Hardcodet.Wpf.TaskbarNotification
{
///<summary>
/// Supported icons for the tray's balloon messages.
///</summary>
public enum BalloonIcon
{
/// <summary>
/// The balloon message is displayed without an icon.
/// </summary>
None,
/// <summary>
/// An information is displayed.
/// </summary>
Info,
/// <summary>
/// A warning is displayed.
/// </summary>
Warning,
/// <summary>
/// An error is displayed.
/// </summary>
Error
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Hardcodet.Wpf.TaskbarNotification.TaskbarIcon">
<Position X="1.75" Y="0.5" Width="3.5" />
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
<Compartment Name="Methods" Collapsed="true" />
</Compartments>
<TypeIdentifier>
<HashCode>N6qdVIeUdLmQtSUbiJhEGdYRjvJYXlhbEVBDKuPRO5s=</HashCode>
<FileName>TaskbarIcon.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Enum Name="Hardcodet.Wpf.TaskbarNotification.PopupActivationMode">
<Position X="6.75" Y="0.5" Width="2" />
<TypeIdentifier>
<HashCode>ABAEAAAAAAAAAAABAAAAAAAAAAAAAAAAAIAKAIAAAAA=</HashCode>
<FileName>PopupActivationMode.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Hardcodet.Wpf.TaskbarNotification.BalloonIcon">
<Position X="9.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAQAAAAAAABAAAAAAAAAAAAAAAEEAAAA=</HashCode>
<FileName>BalloonIcon.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,133 @@
// Some interop code taken from Mike Marshall's AnyForm
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This contains the logic to access the location of the app bar and communicate with it.
/// </summary>
public class AppBarInfo
{
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("shell32.dll")]
private static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA data);
[DllImport("user32.dll")]
private static extern int SystemParametersInfo(uint uiAction, uint uiParam,
IntPtr pvParam, uint fWinIni);
private const int ABM_GETTASKBARPOS = 0x00000005;
private APPBARDATA m_data;
/// <summary>
/// Get on which edge the app bar is located
/// </summary>
public ScreenEdge Edge
{
get { return (ScreenEdge) m_data.uEdge; }
}
/// <summary>
/// Get the working area
/// </summary>
public Rectangle WorkArea
{
get { return GetRectangle(m_data.rc); }
}
private Rectangle GetRectangle(RECT rc)
{
return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
}
/// <summary>
/// Update the location of the appbar with the specified classname and window name.
/// </summary>
/// <param name="strClassName">string</param>
/// <param name="strWindowName">string</param>
private void GetPosition(string strClassName, string strWindowName)
{
m_data = new APPBARDATA();
m_data.cbSize = (uint) Marshal.SizeOf(m_data.GetType());
IntPtr hWnd = FindWindow(strClassName, strWindowName);
if (hWnd != IntPtr.Zero)
{
uint uResult = SHAppBarMessage(ABM_GETTASKBARPOS, ref m_data);
if (uResult != 1)
{
throw new Exception("Failed to communicate with the given AppBar");
}
}
else
{
throw new Exception("Failed to find an AppBar that matched the given criteria");
}
}
/// <summary>
/// Updates the system taskbar position
/// </summary>
public void GetSystemTaskBarPosition()
{
GetPosition("Shell_TrayWnd", null);
}
/// <summary>
/// A value that specifies an edge of the screen.
/// </summary>
public enum ScreenEdge
{
/// <summary>
/// Undefined
/// </summary>
Undefined = -1,
/// <summary>
/// Left edge.
/// </summary>
Left = 0,
/// <summary>
/// Top edge.
/// </summary>
Top = 1,
/// <summary>
/// Right edge.
/// </summary>
Right = 2,
/// <summary>
/// Bottom edge.
/// </summary>
Bottom = 3
}
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public uint cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public uint uEdge;
public RECT rc;
public int lParam;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Flags that define the icon that is shown on a balloon
/// tooltip.
/// </summary>
public enum BalloonFlags
{
/// <summary>
/// No icon is displayed.
/// </summary>
None = 0x00,
/// <summary>
/// An information icon is displayed.
/// </summary>
Info = 0x01,
/// <summary>
/// A warning icon is displayed.
/// </summary>
Warning = 0x02,
/// <summary>
/// An error icon is displayed.
/// </summary>
Error = 0x03,
/// <summary>
/// Windows XP Service Pack 2 (SP2) and later.
/// Use a custom icon as the title icon.
/// </summary>
User = 0x04,
/// <summary>
/// Windows XP (Shell32.dll version 6.0) and later.
/// Do not play the associated sound. Applies only to balloon ToolTips.
/// </summary>
NoSound = 0x10,
/// <summary>
/// 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.<br/>
/// - This flag can be used with all stock icons.<br/>
/// - 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).<br/>
/// - New customized icons (NIIF_USER with hBalloonIcon) must supply an
/// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon).
/// </summary>
LargeIcon = 0x20,
/// <summary>
/// Windows 7 and later.
/// </summary>
RespectQuietTime = 0x80
}
}

View File

@@ -0,0 +1,70 @@
using System;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Indicates which members of a <see cref="NotifyIconData"/> structure
/// were set, and thus contain valid data or provide additional information
/// to the ToolTip as to how it should display.
/// </summary>
[Flags]
public enum IconDataMembers
{
/// <summary>
/// The message ID is set.
/// </summary>
Message = 0x01,
/// <summary>
/// The notification icon is set.
/// </summary>
Icon = 0x02,
/// <summary>
/// The tooltip is set.
/// </summary>
Tip = 0x04,
/// <summary>
/// State information (<see cref="IconState"/>) is set. This
/// applies to both <see cref="NotifyIconData.IconState"/> and
/// <see cref="NotifyIconData.StateMask"/>.
/// </summary>
State = 0x08,
/// <summary>
/// The balloon ToolTip is set. Accordingly, the following
/// members are set: <see cref="NotifyIconData.BalloonText"/>,
/// <see cref="NotifyIconData.BalloonTitle"/>, <see cref="NotifyIconData.BalloonFlags"/>,
/// and <see cref="NotifyIconData.VersionOrTimeout"/>.
/// </summary>
Info = 0x10,
// Internal identifier is set. Reserved, thus commented out.
//Guid = 0x20,
/// <summary>
/// Windows Vista (Shell32.dll version 6.0.6) and later. If the ToolTip
/// cannot be displayed immediately, discard it.<br/>
/// 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."<br/>
/// This modifies and must be combined with the <see cref="Info"/> flag.
/// </summary>
Realtime = 0x40,
/// <summary>
/// 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.<br/>
/// Note that the NIF_SHOWTIP flag is effective until the next call
/// to Shell_NotifyIcon.
/// </summary>
UseLegacyToolTips = 0x80
}
}

View File

@@ -0,0 +1,22 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// The state of the icon - can be set to
/// hide the icon.
/// </summary>
public enum IconState
{
/// <summary>
/// The icon is visible.
/// </summary>
Visible = 0x00,
/// <summary>
/// Hide the icon.
/// </summary>
Hidden = 0x01,
// The icon is shared - currently not supported, thus commented out.
//Shared = 0x02
}
}

View File

@@ -0,0 +1,54 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Event flags for clicked events.
/// </summary>
public enum MouseEvent
{
/// <summary>
/// The mouse was moved withing the
/// taskbar icon's area.
/// </summary>
MouseMove,
/// <summary>
/// The right mouse button was clicked.
/// </summary>
IconRightMouseDown,
/// <summary>
/// The left mouse button was clicked.
/// </summary>
IconLeftMouseDown,
/// <summary>
/// The right mouse button was released.
/// </summary>
IconRightMouseUp,
/// <summary>
/// The left mouse button was released.
/// </summary>
IconLeftMouseUp,
/// <summary>
/// The middle mouse button was clicked.
/// </summary>
IconMiddleMouseDown,
/// <summary>
/// The middle mouse button was released.
/// </summary>
IconMiddleMouseUp,
/// <summary>
/// The taskbar icon was double clicked.
/// </summary>
IconDoubleClick,
/// <summary>
/// The balloon tip was clicked.
/// </summary>
BalloonToolTipClicked
}
}

View File

@@ -0,0 +1,41 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Main operations performed on the
/// <see cref="WinApi.Shell_NotifyIcon"/> function.
/// </summary>
public enum NotifyCommand
{
/// <summary>
/// The taskbar icon is being created.
/// </summary>
Add = 0x00,
/// <summary>
/// The settings of the taskbar icon are being updated.
/// </summary>
Modify = 0x01,
/// <summary>
/// The taskbar icon is deleted.
/// </summary>
Delete = 0x02,
/// <summary>
/// Focus is returned to the taskbar icon. Currently not in use.
/// </summary>
SetFocus = 0x03,
/// <summary>
/// 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.
/// </summary>
SetVersion = 0x04
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// 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 <see cref="IconDataMembers"/>
/// that were defined.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct NotifyIconData
{
/// <summary>
/// Size of this structure, in bytes.
/// </summary>
public uint cbSize;
/// <summary>
/// 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.
/// </summary>
public IntPtr WindowHandle;
/// <summary>
/// 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.
/// </summary>
public uint TaskbarIconId;
/// <summary>
/// Flags that indicate which of the other members contain valid data. This member can be
/// a combination of the NIF_XXX constants.
/// </summary>
public IconDataMembers ValidMembers;
/// <summary>
/// Application-defined message identifier. The system uses this identifier to send
/// notifications to the window identified in hWnd.
/// </summary>
public uint CallbackMessageId;
/// <summary>
/// A handle to the icon that should be displayed. Just
/// <c>Icon.Handle</c>.
/// </summary>
public IntPtr IconHandle;
/// <summary>
/// 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.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string ToolTipText;
/// <summary>
/// State of the icon. Remember to also set the <see cref="StateMask"/>.
/// </summary>
public IconState IconState;
/// <summary>
/// A value that specifies which bits of the state member are retrieved or modified.
/// For example, setting this member to <see cref="TaskbarNotification.Interop.IconState.Hidden"/>
/// causes only the item's hidden
/// state to be retrieved.
/// </summary>
public IconState StateMask;
/// <summary>
/// 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.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string BalloonText;
/// <summary>
/// Mainly used to set the version when <see cref="WinApi.Shell_NotifyIcon"/> is invoked
/// with <see cref="NotifyCommand.SetVersion"/>. However, for legacy operations,
/// the same member is also used to set timeouts for balloon ToolTips.
/// </summary>
public uint VersionOrTimeout;
/// <summary>
/// String containing a title for a balloon ToolTip. This title appears in boldface
/// above the text. It can have a maximum of 63 characters.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string BalloonTitle;
/// <summary>
/// Adds an icon to a balloon ToolTip, which is placed to the left of the title. If the
/// <see cref="BalloonTitle"/> member is zero-length, the icon is not shown.
/// </summary>
public BalloonFlags BalloonFlags;
/// <summary>
/// Windows XP (Shell32.dll version 6.0) and later.<br/>
/// - Windows 7 and later: A registered GUID that identifies the icon.
/// This value overrides uID and is the recommended method of identifying the icon.<br/>
/// - Windows XP through Windows Vista: Reserved.
/// </summary>
public Guid TaskbarIconGuid;
/// <summary>
/// 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 <see cref="TaskbarNotification.Interop.BalloonFlags.User"/>
/// flag is set, this icon is used as the balloon icon.<br/>
/// If this member is NULL, the legacy behavior is carried out.
/// </summary>
public IntPtr CustomBalloonIconHandle;
/// <summary>
/// Creates a default data structure that provides
/// a hidden taskbar icon without the icon being set.
/// </summary>
/// <param name="handle"></param>
/// <returns>NotifyIconData</returns>
public static NotifyIconData CreateDefault(IntPtr handle)
{
var data = new NotifyIconData();
if (Environment.OSVersion.Version.Major >= 6)
{
//use the current size
data.cbSize = (uint) Marshal.SizeOf(data);
}
else
{
//we need to set another size on xp/2003- otherwise certain
//features (e.g. balloon tooltips) don't work.
data.cbSize = 952; // NOTIFYICONDATAW_V3_SIZE
//set to fixed timeout
data.VersionOrTimeout = 10;
}
data.WindowHandle = handle;
data.TaskbarIconId = 0x0;
data.CallbackMessageId = WindowMessageSink.CallbackMessageId;
data.VersionOrTimeout = (uint) NotifyIconVersion.Win95;
data.IconHandle = IntPtr.Zero;
//hide initially
data.IconState = IconState.Hidden;
data.StateMask = IconState.Hidden;
//set flags
data.ValidMembers = IconDataMembers.Message
| IconDataMembers.Icon
| IconDataMembers.Tip;
//reset strings
data.ToolTipText = data.BalloonText = data.BalloonTitle = string.Empty;
return data;
}
}
}

View File

@@ -0,0 +1,27 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// The notify icon version that is used. The higher
/// the version, the more capabilities are available.
/// </summary>
public enum NotifyIconVersion
{
/// <summary>
/// Default behavior (legacy Win95). Expects
/// a <see cref="NotifyIconData"/> size of 488.
/// </summary>
Win95 = 0x0,
/// <summary>
/// Behavior representing Win2000 an higher. Expects
/// a <see cref="NotifyIconData"/> size of 504.
/// </summary>
Win2000 = 0x3,
/// <summary>
/// Extended tooltip support, which is available for Vista and later.
/// Detailed information about what the different versions do, can be found <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyicona">here</a>
/// </summary>
Vista = 0x4
}
}

View File

@@ -0,0 +1,20 @@
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Win API struct providing coordinates for a single point.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
/// <summary>
/// X coordinate.
/// </summary>
public int X;
/// <summary>
/// Y coordinate.
/// </summary>
public int Y;
}
}

View File

@@ -0,0 +1,85 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 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.Diagnostics.Contracts;
using System.Windows.Interop;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This class is a helper for system information, currently to get the DPI factors
/// </summary>
public static class SystemInfo
{
/// <summary>
/// Make sure the initial value is calculated at the first access
/// </summary>
static SystemInfo()
{
UpdateDpiFactors();
}
/// <summary>
/// This calculates the current DPI values and sets this into the DpiFactorX/DpiFactorY values
/// </summary>
internal static void UpdateDpiFactors()
{
using (var source = new HwndSource(new HwndSourceParameters()))
{
if (source.CompositionTarget?.TransformToDevice != null)
{
DpiFactorX = source.CompositionTarget.TransformToDevice.M11;
DpiFactorY = source.CompositionTarget.TransformToDevice.M22;
return;
}
}
DpiFactorX = DpiFactorY = 1;
}
/// <summary>
/// Returns the DPI X Factor
/// </summary>
public static double DpiFactorX { get; private set; } = 1;
/// <summary>
/// Returns the DPI Y Factor
/// </summary>
public static double DpiFactorY { get; private set; } = 1;
/// <summary>
/// Scale the supplied point to the current DPI settings
/// </summary>
/// <param name="point"></param>
/// <returns>Point</returns>
[Pure]
public static Point ScaleWithDpi(this Point point)
{
return new Point
{
X = (int)(point.X / DpiFactorX),
Y = (int)(point.Y / DpiFactorY)
};
}
}
}

View File

@@ -0,0 +1,56 @@
// Some interop code taken from Mike Marshall's AnyForm
using System.Drawing;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Resolves the current tray position.
/// </summary>
public static class TrayInfo
{
/// <summary>
/// Gets the position of the system tray.
/// </summary>
/// <returns>Tray coordinates.</returns>
public static Point GetTrayLocation()
{
int space = 2;
var info = new AppBarInfo();
info.GetSystemTaskBarPosition();
Rectangle rcWorkArea = info.WorkArea;
int x = 0, y = 0;
switch (info.Edge)
{
case AppBarInfo.ScreenEdge.Left:
x = rcWorkArea.Right + space;
y = rcWorkArea.Bottom;
break;
case AppBarInfo.ScreenEdge.Bottom:
x = rcWorkArea.Right;
y = rcWorkArea.Bottom - rcWorkArea.Height - space;
break;
case AppBarInfo.ScreenEdge.Top:
x = rcWorkArea.Right;
y = rcWorkArea.Top + rcWorkArea.Height + space;
break;
case AppBarInfo.ScreenEdge.Right:
x = rcWorkArea.Right - rcWorkArea.Width - space;
y = rcWorkArea.Bottom;
break;
}
return GetDeviceCoordinates(new Point {X = x, Y = y});
}
/// <summary>
/// Recalculates OS coordinates in order to support WPFs coordinate
/// system if OS scaling (DPIs) is not 100%.
/// </summary>
/// <param name="point">Point</param>
/// <returns>Point</returns>
public static Point GetDeviceCoordinates(Point point) => point.ScaleWithDpi();
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Win32 API imports.
/// </summary>
internal static class WinApi
{
private const string User32 = "user32.dll";
/// <summary>
/// Creates, updates or deletes the taskbar icon.
/// </summary>
[DllImport("shell32.Dll", CharSet = CharSet.Unicode)]
public static extern bool Shell_NotifyIcon(NotifyCommand cmd, [In] ref NotifyIconData data);
/// <summary>
/// Creates the helper window that receives messages from the taskar icon.
/// </summary>
[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);
/// <summary>
/// Processes a default windows procedure.
/// </summary>
[DllImport(User32)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wparam, IntPtr lparam);
/// <summary>
/// Registers the helper window class.
/// </summary>
[DllImport(User32, EntryPoint = "RegisterClassW", SetLastError = true)]
public static extern short RegisterClass(ref WindowClass lpWndClass);
/// <summary>
/// Registers a listener for a window message.
/// </summary>
/// <param name="lpString"></param>
/// <returns>uint</returns>
[DllImport(User32, EntryPoint = "RegisterWindowMessageW")]
public static extern uint RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString);
/// <summary>
/// Used to destroy the hidden helper window that receives messages from the
/// taskbar icon.
/// </summary>
/// <param name="hWnd"></param>
/// <returns>bool</returns>
[DllImport(User32, SetLastError = true)]
public static extern bool DestroyWindow(IntPtr hWnd);
/// <summary>
/// Gives focus to a given window.
/// </summary>
/// <param name="hWnd"></param>
/// <returns>bool</returns>
[DllImport(User32)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// Gets the maximum number of milliseconds that can elapse between a
/// first click and a second click for the OS to consider the
/// mouse action a double-click.
/// </summary>
/// <returns>The maximum amount of time, in milliseconds, that can
/// elapse between a first click and a second click for the OS to
/// consider the mouse action a double-click.</returns>
[DllImport(User32, CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int GetDoubleClickTime();
/// <summary>
/// Gets the screen coordinates of the current mouse position.
/// </summary>
[DllImport(User32, SetLastError = true)]
public static extern bool GetPhysicalCursorPos(ref Point lpPoint);
[DllImport(User32, SetLastError = true)]
public static extern bool GetCursorPos(ref Point lpPoint);
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Callback delegate which is used by the Windows API to
/// submit window messages.
/// </summary>
public delegate IntPtr WindowProcedureHandler(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
/// <summary>
/// Win API WNDCLASS struct - represents a single window.
/// Used to receive window messages.
/// </summary>
[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
}
}

View File

@@ -0,0 +1,390 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 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 Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Receives messages from the taskbar icon through
/// window messages of an underlying helper window.
/// </summary>
public class WindowMessageSink : IDisposable
{
#region members
/// <summary>
/// The ID of messages that are received from the the
/// taskbar icon.
/// </summary>
public const int CallbackMessageId = 0x400;
/// <summary>
/// The ID of the message that is being received if the
/// taskbar is (re)started.
/// </summary>
private uint taskbarRestartMessageId;
/// <summary>
/// Used to track whether a mouse-up event is just
/// the aftermath of a double-click and therefore needs
/// to be suppressed.
/// </summary>
private bool isDoubleClick;
/// <summary>
/// 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.
/// </summary>
private WindowProcedureHandler messageHandler;
/// <summary>
/// Window class ID.
/// </summary>
internal string WindowId { get; private set; }
/// <summary>
/// Handle for the message window.
/// </summary>
internal IntPtr MessageWindowHandle { get; private set; }
/// <summary>
/// The version of the underlying icon. Defines how
/// incoming messages are interpreted.
/// </summary>
public NotifyIconVersion Version { get; set; }
#endregion
#region events
/// <summary>
/// The custom tooltip should be closed or hidden.
/// </summary>
public event Action<bool> ChangeToolTipStateRequest;
/// <summary>
/// Fired in case the user clicked or moved within
/// the taskbar icon area.
/// </summary>
public event Action<MouseEvent> MouseEventReceived;
/// <summary>
/// Fired if a balloon ToolTip was either displayed
/// or closed (indicated by the boolean flag).
/// </summary>
public event Action<bool> BalloonToolTipChanged;
/// <summary>
/// Fired if the taskbar was created or restarted. Requires the taskbar
/// icon to be reset.
/// </summary>
public event Action TaskbarCreated;
#endregion
#region construction
/// <summary>
/// Creates a new message sink that receives message from
/// a given taskbar icon.
/// </summary>
/// <param name="version"></param>
public WindowMessageSink(NotifyIconVersion version)
{
Version = version;
CreateMessageWindow();
}
private WindowMessageSink()
{
}
/// <summary>
/// Creates a dummy instance that provides an empty
/// pointer rather than a real window handler.<br/>
/// Used at design time.
/// </summary>
/// <returns>WindowMessageSink</returns>
internal static WindowMessageSink CreateEmpty()
{
return new WindowMessageSink
{
MessageWindowHandle = IntPtr.Zero,
Version = NotifyIconVersion.Vista
};
}
#endregion
#region CreateMessageWindow
/// <summary>
/// Creates the helper message window that is used
/// to receive messages from the taskbar icon.
/// </summary>
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
/// <summary>
/// Callback method that receives messages from the taskbar area.
/// </summary>
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);
}
/// <summary>
/// Processes incoming system messages.
/// </summary>
/// <param name="msg">Callback ID.</param>
/// <param name="wParam">If the version is <see cref="NotifyIconVersion.Vista"/>
/// or higher, this parameter can be used to resolve mouse coordinates.
/// Currently not in use.</param>
/// <param name="lParam">Provides information about the event.</param>
private void ProcessWindowMessage(uint msg, IntPtr wParam, IntPtr lParam)
{
// Check if it was a callback message
if (msg != CallbackMessageId)
{
// It was not a callback message, but make sure it's not something else we need to process
switch ((WindowsMessages) msg)
{
case WindowsMessages.WM_DPICHANGED:
Debug.WriteLine("DPI Change");
SystemInfo.UpdateDpiFactors();
break;
}
return;
}
var message = (WindowsMessages)lParam.ToInt32();
Debug.WriteLine("Got message " + message);
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
/// <summary>
/// Set to true as soon as <c>Dispose</c> has been invoked.
/// </summary>
public bool IsDisposed { get; private set; }
/// <summary>
/// Disposes the object.
/// </summary>
/// <remarks>This method is not virtual by design. Derived classes
/// should override <see cref="Dispose(bool)"/>.
/// </remarks>
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);
}
/// <summary>
/// This destructor will run only if the <see cref="Dispose()"/>
/// method does not get called. This gives this base class the
/// opportunity to finalize.
/// <para>
/// Important: Do not provide destructor in types derived from
/// this class.
/// </para>
/// </summary>
~WindowMessageSink()
{
Dispose(false);
}
/// <summary>
/// Removes the windows hook that receives window
/// messages and closes the underlying helper window.
/// </summary>
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
}
}

View File

@@ -0,0 +1,197 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 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 Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This enum defines the windows messages we respond to.
/// See more on Windows messages <a href="https://docs.microsoft.com/en-us/windows/win32/learnwin32/window-messages">here</a>
/// </summary>
[SuppressMessage("ReSharper", "IdentifierTypo")]
public enum WindowsMessages : uint
{
/// <summary>
/// Notifies a window that the user clicked the right mouse button (right-clicked) in the window.
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/menurc/wm-contextmenu">WM_CONTEXTMENU message</a>
///
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a>
/// </summary>
WM_CONTEXTMENU = 0x007b,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousemove">WM_MOUSEMOVE message</a>
/// </summary>
WM_MOUSEMOVE = 0x0200,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown">WM_LBUTTONDOWN message</a>
/// </summary>
WM_LBUTTONDOWN = 0x0201,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttonup">WM_LBUTTONUP message</a>
/// </summary>
WM_LBUTTONUP = 0x0202,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondblclk">WM_LBUTTONDBLCLK message</a>
/// </summary>
WM_LBUTTONDBLCLK = 0x0203,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondown">WM_RBUTTONDOWN message</a>
/// </summary>
WM_RBUTTONDOWN = 0x0204,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttonup">WM_RBUTTONUP message</a>
/// </summary>
WM_RBUTTONUP = 0x0205,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondblclk">WM_RBUTTONDBLCLK message</a>
/// </summary>
WM_RBUTTONDBLCLK = 0x0206,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondown">WM_MBUTTONDOWN message</a>
/// </summary>
WM_MBUTTONDOWN = 0x0207,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttonup">WM_MBUTTONUP message</a>
/// </summary>
WM_MBUTTONUP = 0x0208,
/// <summary>
/// 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 <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondblclk">WM_MBUTTONDBLCLK message</a>
/// </summary>
WM_MBUTTONDBLCLK = 0x0209,
/// <summary>
/// Sent when the effective dots per inch (dpi) for a window has changed.
/// The DPI is the scale factor for a window.
/// There are multiple events that can cause the DPI to change.
/// </summary>
WM_DPICHANGED = 0x02e0,
/// <summary>
/// Used to define private messages for use by private window classes, usually of the form WM_USER+x, where x is an integer value.
/// </summary>
WM_USER = 0x0400,
/// <summary>
/// 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.
/// </summary>
NIN_SELECT = WM_USER,
/// <summary>
/// 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.
/// </summary>
NIN_KEYSELECT = WM_USER + 1,
/// <summary>
/// Sent when the balloon is shown (balloons are queued).
/// </summary>
NIN_BALLOONSHOW = WM_USER + 2,
/// <summary>
/// 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.
/// </summary>
NIN_BALLOONHIDE = WM_USER + 3,
/// <summary>
/// Sent when the balloon is dismissed because of a timeout.
/// </summary>
NIN_BALLOONTIMEOUT = WM_USER + 4,
/// <summary>
/// Sent when the balloon is dismissed because the user clicked the mouse.
/// </summary>
NIN_BALLOONUSERCLICK = WM_USER + 5,
/// <summary>
/// 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.
/// </summary>
NIN_POPUPOPEN = WM_USER + 6,
/// <summary>
/// Sent when a cursor no longer hovers over an icon to indicate that the rich pop-up UI should be closed.
/// </summary>
NIN_POPUPCLOSE = WM_USER + 7
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;net462;net472;net6.0-windows</TargetFrameworks>
<LangVersion>latest</LangVersion>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>Hardcodet.Wpf.TaskbarNotification</RootNamespace>
<AssemblyName>Hardcodet.NotifyIcon.Wpf</AssemblyName>
<AssemblyTitle>NotifyIcon for WPF</AssemblyTitle>
<Product>NotifyIcon WPF</Product>
</PropertyGroup>
<ItemGroup>
<None Include="Diagrams\TaskbarIcon Overview.cd" />
</ItemGroup>
<ItemGroup>
<Compile DependentUpon="%(Filename)" SubType="Code" Update="**\obj\**\*.g$(DefaultLanguageSourceExtension)" />
<Compile DependentUpon="%(Filename)" SubType="Designer" Update="**\*.xaml$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Project>

Binary file not shown.

View File

@@ -0,0 +1,75 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 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
namespace Hardcodet.Wpf.TaskbarNotification
{
/// <summary>
/// Defines flags that define when a popup
/// is being displyed.
/// </summary>
public enum PopupActivationMode
{
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left mouse button.
/// </summary>
LeftClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the right mouse button.
/// </summary>
RightClick,
/// <summary>
/// The item is displayed if the user double-clicks the
/// tray icon.
/// </summary>
DoubleClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left or the right mouse button.
/// </summary>
LeftOrRightClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left mouse button or if a
/// double-click is being performed.
/// </summary>
LeftOrDoubleClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the middle mouse button.
/// </summary>
MiddleClick,
/// <summary>
/// The item is displayed whenever a click occurs.
/// </summary>
All
}
}

View File

@@ -0,0 +1,45 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Markup;
//provides simplified declaration in XAML
[assembly: XmlnsPrefix("http://www.hardcodet.net/taskbar", "tb")]
[assembly: XmlnsDefinition("http://www.hardcodet.net/taskbar", "Hardcodet.Wpf.TaskbarNotification")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

View File

@@ -0,0 +1,71 @@
using System;
using System.Windows;
namespace Hardcodet.Wpf.TaskbarNotification
{
/// <summary>
/// Helper class used by routed events of the
/// <see cref="TaskbarIcon"/> class.
/// </summary>
internal static class RoutedEventHelper
{
#region RoutedEvent Helper Methods
/// <summary>
/// A static helper method to raise a routed event on a target UIElement or ContentElement.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
/// <param name="args">RoutedEventArgs to use when raising the event</param>
internal static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
{
if (target is UIElement uiElement)
{
uiElement.RaiseEvent(args);
}
else if (target is ContentElement contentElement)
{
contentElement.RaiseEvent(args);
}
}
/// <summary>
/// A static helper method that adds a handler for a routed event
/// to a target UIElement or ContentElement.
/// </summary>
/// <param name="element">UIElement or ContentElement that listens to the event</param>
/// <param name="routedEvent">Event that will be handled</param>
/// <param name="handler">Event handler to be added</param>
internal static void AddHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
{
if (element is UIElement uie)
{
uie.AddHandler(routedEvent, handler);
}
else if (element is ContentElement ce)
{
ce.AddHandler(routedEvent, handler);
}
}
/// <summary>
/// A static helper method that removes a handler for a routed event
/// from a target UIElement or ContentElement.
/// </summary>
/// <param name="element">UIElement or ContentElement that listens to the event</param>
/// <param name="routedEvent">Event that will no longer be handled</param>
/// <param name="handler">Event handler to be removed</param>
internal static void RemoveHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
{
if (element is UIElement uie)
{
uie.RemoveHandler(routedEvent, handler);
}
else if (element is ContentElement ce)
{
ce.RemoveHandler(routedEvent, handler);
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More