From d38750c0b99fa5b57e8aec56cd3796574e44349a Mon Sep 17 00:00:00 2001 From: Markus Hofknecht Date: Tue, 7 Jul 2020 17:05:19 +0200 Subject: [PATCH] Code Analyze and Refactor 0.12 (#109), version 0.11.4.4 --- Business/App.cs | 17 +- Business/KeyboardInput.cs | 44 +- Business/Menus.cs | 150 +-- Business/WaitLeave.cs | 16 +- Business/WaitToLoadMenu.cs | 20 +- Config/AppColors.cs | 19 + Config/Config.cs | 2 +- Config/MenuDefines.cs | 11 - DataClasses/RowData.cs | 50 +- GlobalSuppressions.cs | 8 +- Helpers/Fading.cs | 28 +- Helpers/KeyPressedEventArgs.cs | 28 + Helpers/KeyboardHook.cs | 21 +- NativeDllImport/CreatePopupMenu.cs | 8 +- NativeDllImport/DestroyIcon.cs | 6 +- NativeDllImport/DestroyMenu.cs | 8 +- NativeDllImport/FindExecuteable.cs | 6 +- NativeDllImport/GetMenuDefaultItem.cs | 8 +- NativeDllImport/RegisterHotKey.cs | 28 +- NativeDllImport/SHGetDesktopFolder.cs | 8 +- NativeDllImport/SHGetFolderPath.cs | 6 +- NativeDllImport/SetProcessDPIAware.cs | 6 +- NativeDllImport/StrCmpLogicalW.cs | 6 +- NativeDllImport/StrRetToBuf.cs | 8 +- Properties/AssemblyInfo.cs | 4 +- SystemTrayMenu.csproj | 4 - UserInterface/AboutBox.cs | 118 +- UserInterface/AppNotifyIcon.cs | 16 +- .../FolderBrowseDialog/FolderDialog.cs | 157 +++ .../IFolderDialog.cs | 2 +- .../NativeMethods.cs} | 187 +-- .../FolderBrowseDialog/WindowWrapper.cs | 27 + .../HotkeyTextboxControl/EventDelay.cs | 34 + .../HotkeyControl.cs | 477 ++++---- UserInterface/Language.cs | 13 + UserInterface/Menu.cs | 117 +- UserInterface/SettingsForm.Designer.cs | 4 +- UserInterface/SettingsForm.cs | 179 ++- .../ShellContextMenu/ShellContextMenu.cs | 1046 ++++++++--------- Utilities/AppRestart.cs | 40 +- Utilities/File/FileLnk.cs | 46 +- Utilities/File/IconReader.cs | 154 +-- Utilities/FolderOptions.cs | 2 +- Utilities/Language.cs | 13 + Utilities/Log.cs | 2 +- Utilities/Scaling.cs | 4 +- Utilities/Translator.cs | 7 - 47 files changed, 1615 insertions(+), 1550 deletions(-) create mode 100644 Config/AppColors.cs create mode 100644 Helpers/KeyPressedEventArgs.cs create mode 100644 UserInterface/FolderBrowseDialog/FolderDialog.cs rename UserInterface/{Dialogs => FolderBrowseDialog}/IFolderDialog.cs (91%) rename UserInterface/{Dialogs/FolderDialog.cs => FolderBrowseDialog/NativeMethods.cs} (55%) create mode 100644 UserInterface/FolderBrowseDialog/WindowWrapper.cs create mode 100644 UserInterface/HotkeyTextboxControl/EventDelay.cs rename UserInterface/{Controls => HotkeyTextboxControl}/HotkeyControl.cs (97%) create mode 100644 UserInterface/Language.cs create mode 100644 Utilities/Language.cs diff --git a/Business/App.cs b/Business/App.cs index 1eb10a5..699db34 100644 --- a/Business/App.cs +++ b/Business/App.cs @@ -1,12 +1,11 @@ // // Copyright (c) PlaceholderCompany. All rights reserved. // - namespace SystemTrayMenu { - using Microsoft.Win32; using System; using System.Windows.Forms; + using Microsoft.Win32; using SystemTrayMenu.Business; using SystemTrayMenu.UserInterface; using SystemTrayMenu.Utilities; @@ -61,6 +60,13 @@ namespace SystemTrayMenu DllImports.NativeMethods.User32ShowInactiveTopmost(taskbarForm); } + public void Dispose() + { + taskbarForm.Dispose(); + menus.Dispose(); + menuNotifyIcon.Dispose(); + } + private void TaskbarForm_Deactivate(object sender, EventArgs e) { SetStateNormal(); @@ -76,12 +82,5 @@ namespace SystemTrayMenu taskbarForm.WindowState = FormWindowState.Normal; } } - - public void Dispose() - { - taskbarForm.Dispose(); - menus.Dispose(); - menuNotifyIcon.Dispose(); - } } } \ No newline at end of file diff --git a/Business/KeyboardInput.cs b/Business/KeyboardInput.cs index efcb4e0..3e00e8f 100644 --- a/Business/KeyboardInput.cs +++ b/Business/KeyboardInput.cs @@ -16,8 +16,6 @@ namespace SystemTrayMenu.Handler internal class KeyboardInput : IDisposable { - internal bool InUse = false; - private readonly Menu[] menus; private readonly KeyboardHook hook = new KeyboardHook(); @@ -41,6 +39,8 @@ namespace SystemTrayMenu.Handler internal event EventHandlerEmpty Cleared; + internal bool InUse { get; set; } = false; + public void Dispose() { hook.Dispose(); @@ -205,6 +205,26 @@ namespace SystemTrayMenu.Handler ClearIsSelectedByKey(iMenuKey, iRowKey); } + internal void Select(DataGridView dgv, int i, bool refreshview) + { + int newiMenuKey = ((Menu)dgv.TopLevelControl).Level; + if (i != iRowKey || newiMenuKey != iMenuKey) + { + ClearIsSelectedByKey(); + } + + iRowKey = i; + iMenuKey = newiMenuKey; + DataGridViewRow row = dgv.Rows[i]; + RowData rowData = (RowData)row.Cells[2].Value; + rowData.IsSelected = true; + if (refreshview) + { + row.Selected = false; + row.Selected = true; + } + } + private bool IsAnyMenuSelectedByKey( ref DataGridView dgv, ref Menu menuFromSelected, @@ -453,26 +473,6 @@ namespace SystemTrayMenu.Handler return found; } - public void Select(DataGridView dgv, int i, bool refreshview) - { - int newiMenuKey = ((Menu)dgv.TopLevelControl).Level; - if (i != iRowKey || newiMenuKey != iMenuKey) - { - ClearIsSelectedByKey(); - } - - iRowKey = i; - iMenuKey = newiMenuKey; - DataGridViewRow row = dgv.Rows[i]; - RowData rowData = (RowData)row.Cells[2].Value; - rowData.IsSelected = true; - if (refreshview) - { - row.Selected = false; - row.Selected = true; - } - } - private bool Select(DataGridView dgv, int i, string keyInput = "") { bool found = false; diff --git a/Business/Menus.cs b/Business/Menus.cs index 33b1ad7..4d0c94a 100644 --- a/Business/Menus.cs +++ b/Business/Menus.cs @@ -194,43 +194,6 @@ namespace SystemTrayMenu.Business private List AsList => AsEnumerable.ToList(); - internal void SwitchOpenCloseByTaskbarItem() - { - SwitchOpenClose(true); - timerStillActiveCheck.Start(); - } - - internal void SwitchOpenClose(bool byClick) - { - waitToOpenMenu.MouseActive = byClick; - if (byClick && (DateTime.Now - deactivatedTime).TotalMilliseconds < 200) - { - // By click on notifyicon the menu gets deactivated and closed - } - else if (string.IsNullOrEmpty(Config.Path)) - { - // Case when Folder Dialog open - } - else if (openCloseState == OpenCloseState.Opening || - (menus[0].Visible && openCloseState == OpenCloseState.Default)) - { - openCloseState = OpenCloseState.Closing; - MenusFadeOut(); - StopWorker(); - if (!AsEnumerable.Any(m => m.Visible)) - { - openCloseState = OpenCloseState.Default; - } - } - else - { - openCloseState = OpenCloseState.Opening; - StartWorker(); - } - - deactivatedTime = DateTime.MinValue; - } - public void Dispose() { workerMainMenu.Dispose(); @@ -247,38 +210,6 @@ namespace SystemTrayMenu.Business DisposeMenu(menus[0]); } - internal void DisposeMenu(Menu menuToDispose) - { - if (menuToDispose != null) - { - menuToDispose.MouseWheel -= AdjustMenusSizeAndLocation; - menuToDispose.MouseLeave -= waitLeave.Start; - menuToDispose.MouseEnter -= waitLeave.Stop; - menuToDispose.KeyPress -= keyboardInput.KeyPress; - menuToDispose.CmdKeyProcessed -= keyboardInput.CmdKeyProcessed; - menuToDispose.SearchTextChanging -= keyboardInput.SearchTextChanging; - menuToDispose.SearchTextChanged -= Menu_SearchTextChanged; - DataGridView dgv = menuToDispose.GetDataGridView(); - dgv.CellMouseEnter -= waitToOpenMenu.MouseEnter; - dgv.CellMouseLeave -= waitToOpenMenu.MouseLeave; - dgv.MouseMove -= waitToOpenMenu.MouseMove; - dgv.MouseDown -= Dgv_MouseDown; - dgv.MouseDoubleClick -= Dgv_MouseDoubleClick; - dgv.SelectionChanged -= Dgv_SelectionChanged; - dgv.RowPostPaint -= Dgv_RowPostPaint; - dgv.ClearSelection(); - - foreach (DataGridViewRow row in dgv.Rows) - { - RowData rowData = (RowData)row.Cells[2].Value; - rowData.Dispose(); - DisposeMenu(rowData.SubMenu); - } - - menuToDispose.Dispose(); - } - } - internal static MenuData GetData(BackgroundWorker worker, string path, int level) { MenuData menuData = new MenuData @@ -434,6 +365,75 @@ namespace SystemTrayMenu.Business return menuData; } + internal void SwitchOpenCloseByTaskbarItem() + { + SwitchOpenClose(true); + timerStillActiveCheck.Start(); + } + + internal void SwitchOpenClose(bool byClick) + { + waitToOpenMenu.MouseActive = byClick; + if (byClick && (DateTime.Now - deactivatedTime).TotalMilliseconds < 200) + { + // By click on notifyicon the menu gets deactivated and closed + } + else if (string.IsNullOrEmpty(Config.Path)) + { + // Case when Folder Dialog open + } + else if (openCloseState == OpenCloseState.Opening || + (menus[0].Visible && openCloseState == OpenCloseState.Default)) + { + openCloseState = OpenCloseState.Closing; + MenusFadeOut(); + StopWorker(); + if (!AsEnumerable.Any(m => m.Visible)) + { + openCloseState = OpenCloseState.Default; + } + } + else + { + openCloseState = OpenCloseState.Opening; + StartWorker(); + } + + deactivatedTime = DateTime.MinValue; + } + + internal void DisposeMenu(Menu menuToDispose) + { + if (menuToDispose != null) + { + menuToDispose.MouseWheel -= AdjustMenusSizeAndLocation; + menuToDispose.MouseLeave -= waitLeave.Start; + menuToDispose.MouseEnter -= waitLeave.Stop; + menuToDispose.KeyPress -= keyboardInput.KeyPress; + menuToDispose.CmdKeyProcessed -= keyboardInput.CmdKeyProcessed; + menuToDispose.SearchTextChanging -= keyboardInput.SearchTextChanging; + menuToDispose.SearchTextChanged -= Menu_SearchTextChanged; + DataGridView dgv = menuToDispose.GetDataGridView(); + dgv.CellMouseEnter -= waitToOpenMenu.MouseEnter; + dgv.CellMouseLeave -= waitToOpenMenu.MouseLeave; + dgv.MouseMove -= waitToOpenMenu.MouseMove; + dgv.MouseDown -= Dgv_MouseDown; + dgv.MouseDoubleClick -= Dgv_MouseDoubleClick; + dgv.SelectionChanged -= Dgv_SelectionChanged; + dgv.RowPostPaint -= Dgv_RowPostPaint; + dgv.ClearSelection(); + + foreach (DataGridViewRow row in dgv.Rows) + { + RowData rowData = (RowData)row.Cells[2].Value; + rowData.Dispose(); + DisposeMenu(rowData.SubMenu); + } + + menuToDispose.Dispose(); + } + } + internal void MainPreload() { menus[0] = Create( @@ -509,6 +509,12 @@ namespace SystemTrayMenu.Business return rowData; } + private static bool IsActive() + { + return Form.ActiveForm is Menu || + Form.ActiveForm is UserInterface.TaskbarForm; + } + private Menu Create(MenuData menuData, string title = null) { Menu menu = new Menu(); @@ -777,12 +783,6 @@ namespace SystemTrayMenu.Business } } - private static bool IsActive() - { - return Form.ActiveForm is Menu || - Form.ActiveForm is UserInterface.TaskbarForm; - } - private void MenusFadeOut() { openCloseState = OpenCloseState.Closing; diff --git a/Business/WaitLeave.cs b/Business/WaitLeave.cs index 7ab3918..1adda8c 100644 --- a/Business/WaitLeave.cs +++ b/Business/WaitLeave.cs @@ -20,26 +20,26 @@ namespace SystemTrayMenu.Handler public event EventHandlerEmpty LeaveTriggered; - public void Start() + public void Dispose() + { + timerLeaveCheck.Dispose(); + } + + internal void Start() { timerLeaveCheck.Stop(); timerLeaveCheck.Start(); } - public void Stop() + internal void Stop() { timerLeaveCheck.Stop(); } - private void TimerLeaveCheckTick(object sender, EventArgs e) + internal void TimerLeaveCheckTick(object sender, EventArgs e) { timerLeaveCheck.Stop(); LeaveTriggered?.Invoke(); } - - public void Dispose() - { - timerLeaveCheck.Dispose(); - } } } diff --git a/Business/WaitToLoadMenu.cs b/Business/WaitToLoadMenu.cs index bc8d6d6..9757f57 100644 --- a/Business/WaitToLoadMenu.cs +++ b/Business/WaitToLoadMenu.cs @@ -13,8 +13,6 @@ namespace SystemTrayMenu.Handler internal class WaitToLoadMenu : IDisposable { - internal bool MouseActive = false; - private readonly Timer timerStartLoad = new Timer(); private DataGridView dgv = null; private int rowIndex = 0; @@ -39,6 +37,16 @@ namespace SystemTrayMenu.Handler internal event Action MouseEnterOk; + internal bool MouseActive { get; set; } = false; + + public void Dispose() + { + timerStartLoad.Stop(); + timerStartLoad.Dispose(); + dgv?.Dispose(); + dgvTmp?.Dispose(); + } + internal void MouseEnter(object sender, DataGridViewCellEventArgs e) { if (MouseActive) @@ -193,13 +201,5 @@ namespace SystemTrayMenu.Handler this.rowIndex = 0; } } - - public void Dispose() - { - timerStartLoad.Stop(); - timerStartLoad.Dispose(); - dgv?.Dispose(); - dgvTmp?.Dispose(); - } } } \ No newline at end of file diff --git a/Config/AppColors.cs b/Config/AppColors.cs new file mode 100644 index 0000000..5dcb887 --- /dev/null +++ b/Config/AppColors.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu +{ + using System.Drawing; + + internal static class AppColors + { + internal static readonly Color Blue = Color.FromArgb(204, 232, 255); + internal static readonly Color BlueBorder = Color.FromArgb(153, 209, 255); + internal static readonly Color Green = Color.FromArgb(194, 245, 222); + internal static readonly Color GreenBorder = Color.FromArgb(153, 255, 165); + internal static readonly Color Red = Color.FromArgb(255, 204, 232); + internal static readonly Color Yellow = Color.LightYellow; + internal static readonly Color Azure = Color.Azure; + } +} \ No newline at end of file diff --git a/Config/Config.cs b/Config/Config.cs index a5c722f..aab9b5b 100644 --- a/Config/Config.cs +++ b/Config/Config.cs @@ -8,7 +8,7 @@ namespace SystemTrayMenu using System.IO; using System.Reflection; using System.Windows.Forms; - using SystemTrayMenu.UserInterface.Dialogs; + using SystemTrayMenu.UserInterface.FolderBrowseDialog; using SystemTrayMenu.Utilities; public static class Config diff --git a/Config/MenuDefines.cs b/Config/MenuDefines.cs index 4c7a4b2..6181111 100644 --- a/Config/MenuDefines.cs +++ b/Config/MenuDefines.cs @@ -23,15 +23,4 @@ namespace SystemTrayMenu internal static readonly Color ColorTitleSelected = AppColors.Yellow; internal static readonly Color ColorTitleBackground = AppColors.Azure; } - - internal static class AppColors - { - internal static readonly Color Blue = Color.FromArgb(204, 232, 255); - internal static readonly Color BlueBorder = Color.FromArgb(153, 209, 255); - internal static readonly Color Green = Color.FromArgb(194, 245, 222); - internal static readonly Color GreenBorder = Color.FromArgb(153, 255, 165); - internal static readonly Color Red = Color.FromArgb(255, 204, 232); - internal static readonly Color Yellow = Color.LightYellow; - internal static readonly Color Azure = Color.Azure; - } } \ No newline at end of file diff --git a/DataClasses/RowData.cs b/DataClasses/RowData.cs index 8ea2024..4dde1af 100644 --- a/DataClasses/RowData.cs +++ b/DataClasses/RowData.cs @@ -4,7 +4,6 @@ namespace SystemTrayMenu.DataClasses { - using IWshRuntimeLibrary; using System; using System.Collections.Generic; using System.ComponentModel; @@ -16,24 +15,13 @@ namespace SystemTrayMenu.DataClasses using System.Security; using System.Text; using System.Windows.Forms; + using IWshRuntimeLibrary; using SystemTrayMenu.Utilities; using TAFactory.IconPack; using Menu = SystemTrayMenu.UserInterface.Menu; internal class RowData : IDisposable { - internal FileInfo FileInfo; - internal Menu SubMenu; - internal bool IsMenuOpen; - internal bool IsSelected; - internal bool ContainsMenu; - internal bool IsContextMenuOpen; - internal bool IsResolvedLnk; - internal bool HiddenEntry; - internal string TargetFilePath; - internal string TargetFilePathOrig; - internal int RowIndex; - internal int MenuLevel; private static DateTime contextMenuClosed; private string workingDirectory; private string arguments; @@ -46,6 +34,36 @@ namespace SystemTrayMenu.DataClasses { } + internal FileInfo FileInfo { get; set; } + + internal Menu SubMenu { get; set; } + + internal bool IsMenuOpen { get; set; } + + internal bool IsSelected { get; set; } + + internal bool ContainsMenu { get; set; } + + internal bool IsContextMenuOpen { get; set; } + + internal bool IsResolvedLnk { get; set; } + + internal bool HiddenEntry { get; set; } + + internal string TargetFilePath { get; set; } + + internal string TargetFilePathOrig { get; set; } + + internal int RowIndex { get; set; } + + internal int MenuLevel { get; set; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + internal void SetText(string text) { this.text = text; @@ -225,12 +243,6 @@ namespace SystemTrayMenu.DataClasses } } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - protected virtual void Dispose(bool disposing) { if (!isDisposed) diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs index 4bd6425..835ffc9 100644 --- a/GlobalSuppressions.cs +++ b/GlobalSuppressions.cs @@ -4,8 +4,10 @@ using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1600:Elements should be documented", Justification = "TODO")] -[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1601:Partial elements should be documented", Justification = "TODO")] -[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1602:Enumeration items should be documented", Justification = "TODO")] +[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA0001:XML comment analysis is disabled due to project configuration", Justification = "no idea what this is")] + +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "we need to document")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1601:Partial elements should be documented", Justification = "we need to document")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:Enumeration items should be documented", Justification = "we need to document")] [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Standard codecleanup removes the this")] diff --git a/Helpers/Fading.cs b/Helpers/Fading.cs index 1567173..b35a9aa 100644 --- a/Helpers/Fading.cs +++ b/Helpers/Fading.cs @@ -51,11 +51,25 @@ namespace SystemTrayMenu.UserInterface internal bool IsHiding => state == FadingState.Hide; + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + internal void Fade(FadingState state) { StartStopTimer(state); } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + timer.Dispose(); + } + } + private void StartStopTimer(FadingState newState) { if (newState == FadingState.Idle) @@ -143,19 +157,5 @@ namespace SystemTrayMenu.UserInterface break; } } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - timer.Dispose(); - } - } } } \ No newline at end of file diff --git a/Helpers/KeyPressedEventArgs.cs b/Helpers/KeyPressedEventArgs.cs new file mode 100644 index 0000000..1ee5cf6 --- /dev/null +++ b/Helpers/KeyPressedEventArgs.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.Helper +{ + using System; + using System.Windows.Forms; + + /// + /// Event Args for the event that is fired after the hot key has been pressed. + /// + internal class KeyPressedEventArgs : EventArgs + { + private readonly KeyboardHookModifierKeys modifier; + private readonly Keys key; + + internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key) + { + this.modifier = modifier; + this.key = key; + } + + internal KeyboardHookModifierKeys Modifier => modifier; + + internal Keys Key => key; + } +} diff --git a/Helpers/KeyboardHook.cs b/Helpers/KeyboardHook.cs index a96a08f..2325a98 100644 --- a/Helpers/KeyboardHook.cs +++ b/Helpers/KeyboardHook.cs @@ -6,7 +6,7 @@ namespace SystemTrayMenu.Helper { using System; using System.Windows.Forms; - using SystemTrayMenu.UserInterface.Controls; + using SystemTrayMenu.UserInterface.HotkeyTextboxControl; using SystemTrayMenu.Utilities; /// @@ -160,23 +160,4 @@ namespace SystemTrayMenu.Helper } } } - - /// - /// Event Args for the event that is fired after the hot key has been pressed. - /// - internal class KeyPressedEventArgs : EventArgs - { - private readonly KeyboardHookModifierKeys modifier; - private readonly Keys key; - - internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key) - { - this.modifier = modifier; - this.key = key; - } - - internal KeyboardHookModifierKeys Modifier => modifier; - - internal Keys Key => key; - } } diff --git a/NativeDllImport/CreatePopupMenu.cs b/NativeDllImport/CreatePopupMenu.cs index 710d438..f00744f 100644 --- a/NativeDllImport/CreatePopupMenu.cs +++ b/NativeDllImport/CreatePopupMenu.cs @@ -12,13 +12,13 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - // The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items. - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern IntPtr CreatePopupMenu(); - public static IntPtr User32CreatePopupMenu() { return CreatePopupMenu(); } + + // The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items. + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern IntPtr CreatePopupMenu(); } } diff --git a/NativeDllImport/DestroyIcon.cs b/NativeDllImport/DestroyIcon.cs index 2a79f40..8429793 100644 --- a/NativeDllImport/DestroyIcon.cs +++ b/NativeDllImport/DestroyIcon.cs @@ -12,12 +12,12 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("User32.dll")] - private static extern int DestroyIcon(IntPtr hIcon); - public static void User32DestroyIcon(IntPtr hIcon) { _ = DestroyIcon(hIcon); } + + [DllImport("User32.dll")] + private static extern int DestroyIcon(IntPtr hIcon); } } diff --git a/NativeDllImport/DestroyMenu.cs b/NativeDllImport/DestroyMenu.cs index ea353d0..a8b1819 100644 --- a/NativeDllImport/DestroyMenu.cs +++ b/NativeDllImport/DestroyMenu.cs @@ -12,13 +12,13 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - // The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies. - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern bool DestroyMenu(IntPtr hMenu); - public static bool User32DestroyMenu(IntPtr hMenu) { return DestroyMenu(hMenu); } + + // The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies. + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern bool DestroyMenu(IntPtr hMenu); } } diff --git a/NativeDllImport/FindExecuteable.cs b/NativeDllImport/FindExecuteable.cs index 0a4a45e..7953b3d 100644 --- a/NativeDllImport/FindExecuteable.cs +++ b/NativeDllImport/FindExecuteable.cs @@ -12,12 +12,12 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - private static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); - public static void Shell32FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult) { _ = FindExecutable(lpFile, lpDirectory, lpResult); } + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + private static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); } } diff --git a/NativeDllImport/GetMenuDefaultItem.cs b/NativeDllImport/GetMenuDefaultItem.cs index da44e9f..567ac9f 100644 --- a/NativeDllImport/GetMenuDefaultItem.cs +++ b/NativeDllImport/GetMenuDefaultItem.cs @@ -12,13 +12,13 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - // Determines the default menu item on the specified menu - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags); - public static int User32GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags) { return GetMenuDefaultItem(hMenu, fByPos, gmdiFlags); } + + // Determines the default menu item on the specified menu + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags); } } diff --git a/NativeDllImport/RegisterHotKey.cs b/NativeDllImport/RegisterHotKey.cs index 0d0d9f3..b0c8d67 100644 --- a/NativeDllImport/RegisterHotKey.cs +++ b/NativeDllImport/RegisterHotKey.cs @@ -13,20 +13,6 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool UnregisterHotKey(IntPtr hWnd, int id); - - [DllImport("user32.dll", SetLastError = true)] - private static extern uint MapVirtualKey(uint uCode, uint uMapType); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); - public static bool User32RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk) { return RegisterHotKey(hWnd, id, fsModifiers, vk); @@ -46,5 +32,19 @@ namespace SystemTrayMenu.DllImports { return GetKeyNameText(lParam, lpString, nSize); } + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + [DllImport("user32.dll", SetLastError = true)] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); } } diff --git a/NativeDllImport/SHGetDesktopFolder.cs b/NativeDllImport/SHGetDesktopFolder.cs index ddc775b..ae3cde9 100644 --- a/NativeDllImport/SHGetDesktopFolder.cs +++ b/NativeDllImport/SHGetDesktopFolder.cs @@ -12,13 +12,13 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - // Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace. - [DllImport("shell32.dll")] - private static extern int SHGetDesktopFolder(out IntPtr ppshf); - public static int Shell32SHGetDesktopFolder(out IntPtr ppshf) { return SHGetDesktopFolder(out ppshf); } + + // Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace. + [DllImport("shell32.dll")] + private static extern int SHGetDesktopFolder(out IntPtr ppshf); } } diff --git a/NativeDllImport/SHGetFolderPath.cs b/NativeDllImport/SHGetFolderPath.cs index 35d6d10..13683c0 100644 --- a/NativeDllImport/SHGetFolderPath.cs +++ b/NativeDllImport/SHGetFolderPath.cs @@ -13,12 +13,12 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("shfolder.dll", CharSet = CharSet.Unicode)] - private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath); - public static int ShfolderSHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath) { return SHGetFolderPath(hwndOwner, nFolder, hToken, dwFlags, lpszPath); } + + [DllImport("shfolder.dll", CharSet = CharSet.Unicode)] + private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath); } } diff --git a/NativeDllImport/SetProcessDPIAware.cs b/NativeDllImport/SetProcessDPIAware.cs index 09d5a1a..1da52b2 100644 --- a/NativeDllImport/SetProcessDPIAware.cs +++ b/NativeDllImport/SetProcessDPIAware.cs @@ -11,12 +11,12 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("user32.dll")] - private static extern bool SetProcessDPIAware(); - public static void User32SetProcessDPIAware() { _ = SetProcessDPIAware(); } + + [DllImport("user32.dll")] + private static extern bool SetProcessDPIAware(); } } diff --git a/NativeDllImport/StrCmpLogicalW.cs b/NativeDllImport/StrCmpLogicalW.cs index 75a4516..631f6e4 100644 --- a/NativeDllImport/StrCmpLogicalW.cs +++ b/NativeDllImport/StrCmpLogicalW.cs @@ -11,12 +11,12 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - private static extern int StrCmpLogicalW(string x, string y); - public static int ShlwapiStrCmpLogicalW(string x, string y) { return StrCmpLogicalW(x, y); } + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + private static extern int StrCmpLogicalW(string x, string y); } } diff --git a/NativeDllImport/StrRetToBuf.cs b/NativeDllImport/StrRetToBuf.cs index bd3d7d7..f960948 100644 --- a/NativeDllImport/StrRetToBuf.cs +++ b/NativeDllImport/StrRetToBuf.cs @@ -13,13 +13,13 @@ namespace SystemTrayMenu.DllImports /// public static partial class NativeMethods { - // Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer. - [DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)] - private static extern int StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf); - public static int ShlwapiStrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf) { return StrRetToBuf(pstr, pidl, pszBuf, cchBuf); } + + // Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer. + [DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf); } } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index ec40606..4fbda85 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -39,5 +39,5 @@ using System.Runtime.InteropServices; // 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.*")] -[assembly: AssemblyVersion("0.11.4.3")] -[assembly: AssemblyFileVersion("0.11.4.3")] +[assembly: AssemblyVersion("0.11.4.4")] +[assembly: AssemblyFileVersion("0.11.4.4")] diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj index 76ce0f9..3bbc57f 100644 --- a/SystemTrayMenu.csproj +++ b/SystemTrayMenu.csproj @@ -197,10 +197,6 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/UserInterface/AboutBox.cs b/UserInterface/AboutBox.cs index 5f17e34..b45339c 100644 --- a/UserInterface/AboutBox.cs +++ b/UserInterface/AboutBox.cs @@ -4,7 +4,6 @@ namespace SystemTrayMenu.UserInterface { - using Microsoft.Win32; using System; using System.Collections.Specialized; using System.Drawing; @@ -14,6 +13,7 @@ namespace SystemTrayMenu.UserInterface using System.Security; using System.Text.RegularExpressions; using System.Windows.Forms; + using Microsoft.Win32; using SystemTrayMenu.Utilities; /// @@ -189,14 +189,6 @@ namespace SystemTrayMenu.UserInterface set => buttonDetails.Visible = value; } - private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e) - { - if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails) - { - AssemblyNamesComboBox.Focus(); - } - } - // // exception-safe retrieval of LastWriteTime for this assembly. // @@ -438,6 +430,64 @@ namespace SystemTrayMenu.UserInterface return strSysInfoPath; } + // + // populate a listview with the specified key and value strings + // + private static void Populate(ListView lvw, string key, string value) + { + if (!string.IsNullOrEmpty(value)) + { + ListViewItem lvi = new ListViewItem + { + Text = key, + }; + lvi.SubItems.Add(value); + lvw.Items.Add(lvi); + } + } + + // + // populate details for a single assembly + // + private static void PopulateAssemblyDetails(Assembly a, ListView lvw) + { + lvw.Items.Clear(); + + // this assembly property is only available in framework versions 1.1+ + Populate(lvw, "Image Runtime Version", a.ImageRuntimeVersion); + Populate(lvw, "Loaded from GAC", a.GlobalAssemblyCache.ToString(CultureInfo.InvariantCulture)); + + NameValueCollection nvc = AssemblyAttribs(a); + foreach (string strKey in nvc) + { + Populate(lvw, strKey, nvc[strKey]); + } + } + + // + // matches assembly by Assembly.GetName.Name; returns nothing if no match + // + private static Assembly MatchAssemblyByName(string assemblyName) + { + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) + { + if (a.GetName().Name == assemblyName) + { + return a; + } + } + + return null; + } + + private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e) + { + if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails) + { + AssemblyNamesComboBox.Focus(); + } + } + // // launch the MSInfo "system information" application (works on XP, 2003, and Vista) // @@ -464,22 +514,6 @@ namespace SystemTrayMenu.UserInterface Log.ProcessStart(strSysInfoPath); } - // - // populate a listview with the specified key and value strings - // - private static void Populate(ListView lvw, string key, string value) - { - if (!string.IsNullOrEmpty(value)) - { - ListViewItem lvi = new ListViewItem - { - Text = key, - }; - lvi.SubItems.Add(value); - lvw.Items.Add(lvi); - } - } - // // populates the Application Information listview // @@ -620,40 +654,6 @@ namespace SystemTrayMenu.UserInterface return s; } - // - // populate details for a single assembly - // - private static void PopulateAssemblyDetails(Assembly a, ListView lvw) - { - lvw.Items.Clear(); - - // this assembly property is only available in framework versions 1.1+ - Populate(lvw, "Image Runtime Version", a.ImageRuntimeVersion); - Populate(lvw, "Loaded from GAC", a.GlobalAssemblyCache.ToString(CultureInfo.InvariantCulture)); - - NameValueCollection nvc = AssemblyAttribs(a); - foreach (string strKey in nvc) - { - Populate(lvw, strKey, nvc[strKey]); - } - } - - // - // matches assembly by Assembly.GetName.Name; returns nothing if no match - // - private static Assembly MatchAssemblyByName(string assemblyName) - { - foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) - { - if (a.GetName().Name == assemblyName) - { - return a; - } - } - - return null; - } - // // things to do when form is loaded // diff --git a/UserInterface/AppNotifyIcon.cs b/UserInterface/AppNotifyIcon.cs index 538c0ea..07d093a 100644 --- a/UserInterface/AppNotifyIcon.cs +++ b/UserInterface/AppNotifyIcon.cs @@ -82,14 +82,6 @@ namespace SystemTrayMenu.UserInterface public event EventHandlerEmpty Exit; - private void VerifyClick(MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - Click?.Invoke(); - } - } - public void Dispose() { notifyIcon.Icon = null; @@ -109,6 +101,14 @@ namespace SystemTrayMenu.UserInterface threadsLoading = false; } + private void VerifyClick(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + Click?.Invoke(); + } + } + private void Load_Tick(object sender, EventArgs e) { if (threadsLoading) diff --git a/UserInterface/FolderBrowseDialog/FolderDialog.cs b/UserInterface/FolderBrowseDialog/FolderDialog.cs new file mode 100644 index 0000000..b65f603 --- /dev/null +++ b/UserInterface/FolderBrowseDialog/FolderDialog.cs @@ -0,0 +1,157 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.UserInterface.FolderBrowseDialog +{ + using System; + using System.IO; + using System.Runtime.InteropServices; + using System.Windows.Forms; + using SystemTrayMenu.Utilities; + + public class FolderDialog : IFolderDialog, IDisposable + { + private bool isDisposed; + + /// + /// Gets or sets /sets folder in which dialog will be open. + /// + public string InitialFolder { get; set; } + + /// + /// Gets or sets /sets directory in which dialog will be open + /// if there is no recent directory available. + /// + public string DefaultFolder { get; set; } + + /// + /// Gets or sets selected folder. + /// + public string Folder { get; set; } + + public DialogResult ShowDialog() + { + return ShowDialog(owner: new WindowWrapper(IntPtr.Zero)); + } + + public DialogResult ShowDialog(IWin32Window owner) + { + if (Environment.OSVersion.Version.Major >= 6) + { + return ShowVistaDialog(owner); + } + else + { + return ShowLegacyDialog(owner); + } + } + + public DialogResult ShowVistaDialog(IWin32Window owner) + { + NativeMethods.IFileDialog frm = (NativeMethods.IFileDialog)new NativeMethods.FileOpenDialogRCW(); + frm.GetOptions(out uint options); + options |= NativeMethods.FOS_PICKFOLDERS | + NativeMethods.FOS_FORCEFILESYSTEM | + NativeMethods.FOS_NOVALIDATE | + NativeMethods.FOS_NOTESTFILECREATE | + NativeMethods.FOS_DONTADDTORECENT; + frm.SetOptions(options); + if (InitialFolder != null) + { + Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem + if (NativeMethods.SHCreateItemFromParsingName( + InitialFolder, + IntPtr.Zero, + ref riid, + out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK) + { + frm.SetFolder(directoryShellItem); + } + } + + if (DefaultFolder != null) + { + Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem + if (NativeMethods.SHCreateItemFromParsingName( + DefaultFolder, + IntPtr.Zero, + ref riid, + out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK) + { + frm.SetDefaultFolder(directoryShellItem); + } + } + + if (owner != null && frm.Show(owner.Handle) == NativeMethods.S_OK) + { + if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK) + { + if (shellItem.GetDisplayName( + NativeMethods.SIGDN_FILESYSPATH, + out IntPtr pszString) == NativeMethods.S_OK) + { + if (pszString != IntPtr.Zero) + { + try + { + Folder = Marshal.PtrToStringAuto(pszString); + return DialogResult.OK; + } + finally + { + Marshal.FreeCoTaskMem(pszString); + } + } + } + } + } + + return DialogResult.Cancel; + } + + public DialogResult ShowLegacyDialog(IWin32Window owner) + { + using SaveFileDialog frm = new SaveFileDialog + { + CheckFileExists = false, + CheckPathExists = true, + CreatePrompt = false, + Filter = "|" + Guid.Empty.ToString(), + FileName = "any", + }; + if (InitialFolder != null) + { + frm.InitialDirectory = InitialFolder; + } + + frm.OverwritePrompt = false; + frm.Title = Translator.GetText("Select Folder"); + frm.ValidateNames = false; + if (frm.ShowDialog(owner) == DialogResult.OK) + { + Folder = Path.GetDirectoryName(frm.FileName); + return DialogResult.OK; + } + else + { + return DialogResult.Cancel; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + } + + isDisposed = true; + } + } +} diff --git a/UserInterface/Dialogs/IFolderDialog.cs b/UserInterface/FolderBrowseDialog/IFolderDialog.cs similarity index 91% rename from UserInterface/Dialogs/IFolderDialog.cs rename to UserInterface/FolderBrowseDialog/IFolderDialog.cs index 7ec083b..56b8591 100644 --- a/UserInterface/Dialogs/IFolderDialog.cs +++ b/UserInterface/FolderBrowseDialog/IFolderDialog.cs @@ -2,7 +2,7 @@ // Copyright (c) PlaceholderCompany. All rights reserved. // -namespace SystemTrayMenu.UserInterface.Dialogs +namespace SystemTrayMenu.UserInterface.FolderBrowseDialog { using System.Windows.Forms; diff --git a/UserInterface/Dialogs/FolderDialog.cs b/UserInterface/FolderBrowseDialog/NativeMethods.cs similarity index 55% rename from UserInterface/Dialogs/FolderDialog.cs rename to UserInterface/FolderBrowseDialog/NativeMethods.cs index 48b3898..b855f19 100644 --- a/UserInterface/Dialogs/FolderDialog.cs +++ b/UserInterface/FolderBrowseDialog/NativeMethods.cs @@ -1,179 +1,12 @@ -// +// // Copyright (c) PlaceholderCompany. All rights reserved. // -namespace SystemTrayMenu.UserInterface.Dialogs +namespace SystemTrayMenu.UserInterface.FolderBrowseDialog { using System; - using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - using System.Windows.Forms; - using SystemTrayMenu.Utilities; - - public class FolderDialog : IFolderDialog, IDisposable - { - private bool isDisposed; - - /// - /// Gets or sets /sets folder in which dialog will be open. - /// - public string InitialFolder { get; set; } - - /// - /// Gets or sets /sets directory in which dialog will be open - /// if there is no recent directory available. - /// - public string DefaultFolder { get; set; } - - /// - /// Gets or sets selected folder. - /// - public string Folder { get; set; } - - public DialogResult ShowDialog() - { - return ShowDialog(owner: new WindowWrapper(IntPtr.Zero)); - } - - public DialogResult ShowDialog(IWin32Window owner) - { - if (Environment.OSVersion.Version.Major >= 6) - { - return ShowVistaDialog(owner); - } - else - { - return ShowLegacyDialog(owner); - } - } - - public DialogResult ShowVistaDialog(IWin32Window owner) - { - NativeMethods.IFileDialog frm = (NativeMethods.IFileDialog)new NativeMethods.FileOpenDialogRCW(); - frm.GetOptions(out uint options); - options |= NativeMethods.FOS_PICKFOLDERS | - NativeMethods.FOS_FORCEFILESYSTEM | - NativeMethods.FOS_NOVALIDATE | - NativeMethods.FOS_NOTESTFILECREATE | - NativeMethods.FOS_DONTADDTORECENT; - frm.SetOptions(options); - if (InitialFolder != null) - { - Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem - if (NativeMethods.SHCreateItemFromParsingName( - InitialFolder, - IntPtr.Zero, - ref riid, - out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK) - { - frm.SetFolder(directoryShellItem); - } - } - - if (DefaultFolder != null) - { - Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem - if (NativeMethods.SHCreateItemFromParsingName( - DefaultFolder, - IntPtr.Zero, - ref riid, - out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK) - { - frm.SetDefaultFolder(directoryShellItem); - } - } - - if (owner != null && frm.Show(owner.Handle) == NativeMethods.S_OK) - { - if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK) - { - if (shellItem.GetDisplayName( - NativeMethods.SIGDN_FILESYSPATH, - out IntPtr pszString) == NativeMethods.S_OK) - { - if (pszString != IntPtr.Zero) - { - try - { - Folder = Marshal.PtrToStringAuto(pszString); - return DialogResult.OK; - } - finally - { - Marshal.FreeCoTaskMem(pszString); - } - } - } - } - } - - return DialogResult.Cancel; - } - - public DialogResult ShowLegacyDialog(IWin32Window owner) - { - using SaveFileDialog frm = new SaveFileDialog - { - CheckFileExists = false, - CheckPathExists = true, - CreatePrompt = false, - Filter = "|" + Guid.Empty.ToString(), - FileName = "any", - }; - if (InitialFolder != null) - { - frm.InitialDirectory = InitialFolder; - } - - frm.OverwritePrompt = false; - frm.Title = Translator.GetText("Select Folder"); - frm.ValidateNames = false; - if (frm.ShowDialog(owner) == DialogResult.OK) - { - Folder = Path.GetDirectoryName(frm.FileName); - return DialogResult.OK; - } - else - { - return DialogResult.Cancel; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (!isDisposed) - { - } - - isDisposed = true; - } - } - - public class WindowWrapper : System.Windows.Forms.IWin32Window - { - /// - /// Initializes a new instance of the class. - /// - /// Handle to wrap. - public WindowWrapper(IntPtr handle) - { - hwnd = handle; - } - - /// - /// Gets original ptr. - /// - public IntPtr Handle => hwnd; - - private readonly IntPtr hwnd; - } internal static class NativeMethods { @@ -187,14 +20,6 @@ namespace SystemTrayMenu.UserInterface.Dialogs public const uint SIGDN_FILESYSPATH = 0x80058000; - [ComImport] - [ClassInterface(ClassInterfaceType.None)] - [TypeLibType(TypeLibTypeFlags.FCanCreate)] - [Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] - internal class FileOpenDialogRCW - { - } - [ComImport] [Guid("42F85136-DB7E-439C-85F1-E4075D135FC8")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] @@ -308,5 +133,13 @@ namespace SystemTrayMenu.UserInterface.Dialogs IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv); + + [ComImport] + [ClassInterface(ClassInterfaceType.None)] + [TypeLibType(TypeLibTypeFlags.FCanCreate)] + [Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")] + internal class FileOpenDialogRCW + { + } } } diff --git a/UserInterface/FolderBrowseDialog/WindowWrapper.cs b/UserInterface/FolderBrowseDialog/WindowWrapper.cs new file mode 100644 index 0000000..9311a3b --- /dev/null +++ b/UserInterface/FolderBrowseDialog/WindowWrapper.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.UserInterface.FolderBrowseDialog +{ + using System; + + public class WindowWrapper : System.Windows.Forms.IWin32Window + { + private readonly IntPtr hwnd; + + /// + /// Initializes a new instance of the class. + /// + /// Handle to wrap. + public WindowWrapper(IntPtr handle) + { + hwnd = handle; + } + + /// + /// Gets original ptr. + /// + public IntPtr Handle => hwnd; + } +} diff --git a/UserInterface/HotkeyTextboxControl/EventDelay.cs b/UserInterface/HotkeyTextboxControl/EventDelay.cs new file mode 100644 index 0000000..5923dfa --- /dev/null +++ b/UserInterface/HotkeyTextboxControl/EventDelay.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl +{ + using System; + +#pragma warning restore CA1308 + + public class EventDelay + { + private readonly long waitTime; + private long lastCheck; + + public EventDelay(long ticks) + { + waitTime = ticks; + } + + public bool Check() + { +#pragma warning disable CA2002 + lock (this) +#pragma warning restore CA2002 + { + long now = DateTime.Now.Ticks; + bool isPassed = now - lastCheck > waitTime; + lastCheck = now; + return isPassed; + } + } + } +} \ No newline at end of file diff --git a/UserInterface/Controls/HotkeyControl.cs b/UserInterface/HotkeyTextboxControl/HotkeyControl.cs similarity index 97% rename from UserInterface/Controls/HotkeyControl.cs rename to UserInterface/HotkeyTextboxControl/HotkeyControl.cs index afd851e..bcd56a5 100644 --- a/UserInterface/Controls/HotkeyControl.cs +++ b/UserInterface/HotkeyTextboxControl/HotkeyControl.cs @@ -2,7 +2,7 @@ // Copyright (c) PlaceholderCompany. All rights reserved. // -namespace SystemTrayMenu.UserInterface.Controls +namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl { using System; using System.Collections.Generic; @@ -55,24 +55,6 @@ namespace SystemTrayMenu.UserInterface.Controls PopulateModifierLists(); } - /// - /// Gets or sets used to make sure that there is no right-click menu available. - /// - public override ContextMenuStrip ContextMenuStrip - { - get => dummy; - set => base.ContextMenuStrip = dummy; - } - - /// - /// Gets or sets a value indicating whether forces the control to be non-multiline. - /// - public override bool Multiline - { - get => base.Multiline; - set => base.Multiline = false; - } - // Delegates for hooking up events. public delegate void HotKeyHandler(); @@ -96,143 +78,21 @@ namespace SystemTrayMenu.UserInterface.Controls } /// - /// Populates the ArrayLists specifying disallowed hotkeys - /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc. + /// Gets or sets used to make sure that there is no right-click menu available. /// - private void PopulateModifierLists() + public override ContextMenuStrip ContextMenuStrip { - // Shift + 0 - 9, A - Z - for (Keys k = Keys.D0; k <= Keys.Z; k++) - { - needNonShiftModifier.Add((int)k); - } - - // Shift + Numpad keys - for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) - { - needNonShiftModifier.Add((int)k); - } - - // Shift + Misc (,;<./ etc) - for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) - { - needNonShiftModifier.Add((int)k); - } - - // Shift + Space, PgUp, PgDn, End, Home - for (Keys k = Keys.Space; k <= Keys.Home; k++) - { - needNonShiftModifier.Add((int)k); - } - - // Misc keys that we can't loop through - needNonShiftModifier.Add((int)Keys.Insert); - needNonShiftModifier.Add((int)Keys.Help); - needNonShiftModifier.Add((int)Keys.Multiply); - needNonShiftModifier.Add((int)Keys.Add); - needNonShiftModifier.Add((int)Keys.Subtract); - needNonShiftModifier.Add((int)Keys.Divide); - needNonShiftModifier.Add((int)Keys.Decimal); - needNonShiftModifier.Add((int)Keys.Return); - needNonShiftModifier.Add((int)Keys.Escape); - needNonShiftModifier.Add((int)Keys.NumLock); - - // Ctrl+Alt + 0 - 9 - for (Keys k = Keys.D0; k <= Keys.D9; k++) - { - needNonAltGrModifier.Add((int)k); - } + get => dummy; + set => base.ContextMenuStrip = dummy; } /// - /// Resets this hotkey control to None. + /// Gets or sets a value indicating whether forces the control to be non-multiline. /// - public new void Clear() + public override bool Multiline { - Hotkey = Keys.None; - HotkeyModifiers = Keys.None; - } - - /// - /// Fires when a key is pushed down. Here, we'll want to update the text in the box - /// to notify the user what combination is currently pressed. - /// - private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) - { - // Clear the current hotkey - if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) - { - ResetHotkey(); - } - else - { - modifiers = e.Modifiers; - hotkey = e.KeyCode; - Redraw(); - } - } - - /// - /// Fires when all keys are released. If the current hotkey isn't valid, reset it. - /// Otherwise, do nothing and keep the text and hotkey as it was. - /// - private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) - { - // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. - if (e.KeyCode == Keys.PrintScreen) - { - modifiers = e.Modifiers; - hotkey = e.KeyCode; - Redraw(); - } - - if (hotkey == Keys.None && ModifierKeys == Keys.None) - { - ResetHotkey(); - } - } - - /// - /// Prevents the letter/whatever entered to show up in the TextBox - /// Without this, a "A" key press would appear as "aControl, Alt + A". - /// - private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) - { - e.Handled = true; - } - - /// - /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert. - /// - /// msg. - /// keyData. - /// bool if handled. - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) - { - if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) - { - ResetHotkey(); - return true; - } - - // Paste - if (keyData == (Keys.Shift | Keys.Insert)) - { - return true; // Don't allow - } - - // Allow the rest - return base.ProcessCmdKey(ref msg, keyData); - } - - /// - /// Clears the current hotkey and resets the TextBox. - /// - public void ResetHotkey() - { - hotkey = Keys.None; - modifiers = Keys.None; - Redraw(); + get => base.Multiline; + set => base.Multiline = false; } /// @@ -248,17 +108,6 @@ namespace SystemTrayMenu.UserInterface.Controls } } - /// - /// Used to get/set the hotkey (e.g. Keys.A). - /// - /// hotkey. - public void SetHotkey(string hotkey) - { - this.hotkey = HotkeyFromString(hotkey); - modifiers = HotkeyModifiersFromString(hotkey); - Redraw(true); - } - /// /// Gets or sets used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control). /// @@ -272,80 +121,6 @@ namespace SystemTrayMenu.UserInterface.Controls } } - /// - /// Redraws the TextBox when necessary. - /// - /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. - private void Redraw(bool bCalledProgramatically = false) - { - // No hotkey set - if (hotkey == Keys.None) - { - Text = string.Empty; - return; - } - - // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) - if (hotkey == Keys.LWin || hotkey == Keys.RWin) - { - Text = string.Empty; - return; - } - - // Only validate input if it comes from the user - if (bCalledProgramatically == false) - { - // No modifier or shift only, AND a hotkey that needs another modifier - if ((modifiers == Keys.Shift || modifiers == Keys.None) && needNonShiftModifier.Contains((int)hotkey)) - { - if (modifiers == Keys.None) - { - // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... - if (needNonAltGrModifier.Contains((int)hotkey) == false) - { - modifiers = Keys.Alt | Keys.Control; - } - else - { - // ... in that case, use Shift+Alt instead. - modifiers = Keys.Alt | Keys.Shift; - } - } - else - { - // User pressed Shift and an invalid key (e.g. a letter or a number), - // that needs another set of modifier keys - hotkey = Keys.None; - Text = string.Empty; - return; - } - } - - // Check all Ctrl+Alt keys - if ((modifiers == (Keys.Alt | Keys.Control)) && needNonAltGrModifier.Contains((int)hotkey)) - { - // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user - hotkey = Keys.None; - Text = string.Empty; - return; - } - } - - // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl - // will show up as "Control + ControlKey", etc. - if (hotkey == Keys.Menu /* Alt */ || hotkey == Keys.ShiftKey || hotkey == Keys.ControlKey) - { - hotkey = Keys.None; - } - - Text = HotkeyToLocalizedString(modifiers, hotkey); - } - - public override string ToString() - { - return HotkeyToString(HotkeyModifiers, Hotkey); - } - public static string GetLocalizedHotkeyStringFromString(string hotkeyString) { Keys virtualKeyCode = HotkeyFromString(hotkeyString); @@ -679,30 +454,230 @@ namespace SystemTrayMenu.UserInterface.Controls return givenKey.ToString(); } } - } -#pragma warning restore CA1308 - public class EventDelay - { - private readonly long waitTime; - private long lastCheck; - - public EventDelay(long ticks) + /// + /// Resets this hotkey control to None. + /// + public new void Clear() { - waitTime = ticks; + Hotkey = Keys.None; + HotkeyModifiers = Keys.None; } - public bool Check() + /// + /// Clears the current hotkey and resets the TextBox. + /// + public void ResetHotkey() { -#pragma warning disable CA2002 - lock (this) -#pragma warning restore CA2002 + hotkey = Keys.None; + modifiers = Keys.None; + Redraw(); + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A). + /// + /// hotkey. + public void SetHotkey(string hotkey) + { + this.hotkey = HotkeyFromString(hotkey); + modifiers = HotkeyModifiersFromString(hotkey); + Redraw(true); + } + + public override string ToString() + { + return HotkeyToString(HotkeyModifiers, Hotkey); + } + + /// + /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert. + /// + /// msg. + /// keyData. + /// bool if handled. + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) { - long now = DateTime.Now.Ticks; - bool isPassed = now - lastCheck > waitTime; - lastCheck = now; - return isPassed; + ResetHotkey(); + return true; } + + // Paste + if (keyData == (Keys.Shift | Keys.Insert)) + { + return true; // Don't allow + } + + // Allow the rest + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Redraws the TextBox when necessary. + /// + /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. + private void Redraw(bool bCalledProgramatically = false) + { + // No hotkey set + if (hotkey == Keys.None) + { + Text = string.Empty; + return; + } + + // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) + if (hotkey == Keys.LWin || hotkey == Keys.RWin) + { + Text = string.Empty; + return; + } + + // Only validate input if it comes from the user + if (bCalledProgramatically == false) + { + // No modifier or shift only, AND a hotkey that needs another modifier + if ((modifiers == Keys.Shift || modifiers == Keys.None) && needNonShiftModifier.Contains((int)hotkey)) + { + if (modifiers == Keys.None) + { + // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... + if (needNonAltGrModifier.Contains((int)hotkey) == false) + { + modifiers = Keys.Alt | Keys.Control; + } + else + { + // ... in that case, use Shift+Alt instead. + modifiers = Keys.Alt | Keys.Shift; + } + } + else + { + // User pressed Shift and an invalid key (e.g. a letter or a number), + // that needs another set of modifier keys + hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // Check all Ctrl+Alt keys + if ((modifiers == (Keys.Alt | Keys.Control)) && needNonAltGrModifier.Contains((int)hotkey)) + { + // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user + hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl + // will show up as "Control + ControlKey", etc. + if (hotkey == Keys.Menu /* Alt */ || hotkey == Keys.ShiftKey || hotkey == Keys.ControlKey) + { + hotkey = Keys.None; + } + + Text = HotkeyToLocalizedString(modifiers, hotkey); + } + + /// + /// Populates the ArrayLists specifying disallowed hotkeys + /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc. + /// + private void PopulateModifierLists() + { + // Shift + 0 - 9, A - Z + for (Keys k = Keys.D0; k <= Keys.Z; k++) + { + needNonShiftModifier.Add((int)k); + } + + // Shift + Numpad keys + for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) + { + needNonShiftModifier.Add((int)k); + } + + // Shift + Misc (,;<./ etc) + for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) + { + needNonShiftModifier.Add((int)k); + } + + // Shift + Space, PgUp, PgDn, End, Home + for (Keys k = Keys.Space; k <= Keys.Home; k++) + { + needNonShiftModifier.Add((int)k); + } + + // Misc keys that we can't loop through + needNonShiftModifier.Add((int)Keys.Insert); + needNonShiftModifier.Add((int)Keys.Help); + needNonShiftModifier.Add((int)Keys.Multiply); + needNonShiftModifier.Add((int)Keys.Add); + needNonShiftModifier.Add((int)Keys.Subtract); + needNonShiftModifier.Add((int)Keys.Divide); + needNonShiftModifier.Add((int)Keys.Decimal); + needNonShiftModifier.Add((int)Keys.Return); + needNonShiftModifier.Add((int)Keys.Escape); + needNonShiftModifier.Add((int)Keys.NumLock); + + // Ctrl+Alt + 0 - 9 + for (Keys k = Keys.D0; k <= Keys.D9; k++) + { + needNonAltGrModifier.Add((int)k); + } + } + + /// + /// Fires when a key is pushed down. Here, we'll want to update the text in the box + /// to notify the user what combination is currently pressed. + /// + private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) + { + // Clear the current hotkey + if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) + { + ResetHotkey(); + } + else + { + modifiers = e.Modifiers; + hotkey = e.KeyCode; + Redraw(); + } + } + + /// + /// Fires when all keys are released. If the current hotkey isn't valid, reset it. + /// Otherwise, do nothing and keep the text and hotkey as it was. + /// + private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) + { + // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. + if (e.KeyCode == Keys.PrintScreen) + { + modifiers = e.Modifiers; + hotkey = e.KeyCode; + Redraw(); + } + + if (hotkey == Keys.None && ModifierKeys == Keys.None) + { + ResetHotkey(); + } + } + + /// + /// Prevents the letter/whatever entered to show up in the TextBox + /// Without this, a "A" key press would appear as "aControl, Alt + A". + /// + private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) + { + e.Handled = true; } } } \ No newline at end of file diff --git a/UserInterface/Language.cs b/UserInterface/Language.cs new file mode 100644 index 0000000..0e31a08 --- /dev/null +++ b/UserInterface/Language.cs @@ -0,0 +1,13 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.UserInterface +{ + public class Language + { + public string Name { get; set; } + + public string Value { get; set; } + } +} diff --git a/UserInterface/Menu.cs b/UserInterface/Menu.cs index 9bf4141..d3871fb 100644 --- a/UserInterface/Menu.cs +++ b/UserInterface/Menu.cs @@ -17,7 +17,6 @@ namespace SystemTrayMenu.UserInterface internal partial class Menu : Form { - internal int Level = 0; private readonly Fading fading = new Fading(); private bool isShowing = false; @@ -131,25 +130,26 @@ namespace SystemTrayMenu.UserInterface MaxReached, } + internal int Level { get; set; } = 0; + internal bool IsUsable => Visible && !fading.IsHiding && !IsDisposed && !Disposing; + protected override CreateParams CreateParams + { + get + { + CreateParams createparams = base.CreateParams; + createparams.ExStyle |= 0x80; + return createparams; + } + } + internal void FocusTextBox() { textBoxSearch.Focus(); } - private static void SetDoubleBuffer(Control ctl, bool doubleBuffered) - { - typeof(Control).InvokeMember( - "DoubleBuffered", - BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, - null, - ctl, - new object[] { doubleBuffered }, - CultureInfo.InvariantCulture); - } - internal void SetTypeSub() { SetType(MenuType.Sub); @@ -378,6 +378,53 @@ namespace SystemTrayMenu.UserInterface Location = new Point(x, y); } + internal void SetTitleColorActive() + { + labelTitle.ForeColor = Color.Black; + } + + internal void KeyPressedSearch(string letter) + { + textBoxSearch.Text += letter; + textBoxSearch.SelectionStart = textBoxSearch.Text.Length; + textBoxSearch.SelectionLength = 0; + textBoxSearch.Focus(); + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keys) + { + switch (keys) + { + case Keys.Enter: + case Keys.Up: + case Keys.Down: + case Keys.Left: + case Keys.Right: + case Keys.Escape: + case Keys.Control | Keys.F: + case Keys.Tab: + case Keys.Tab | Keys.Shift: + case Keys.Apps: + CmdKeyProcessed.Invoke(this, keys); + return true; + default: + break; + } + + return base.ProcessCmdKey(ref msg, keys); + } + + private static void SetDoubleBuffer(Control ctl, bool doubleBuffered) + { + typeof(Control).InvokeMember( + "DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, + null, + ctl, + new object[] { doubleBuffered }, + CultureInfo.InvariantCulture); + } + private void AdjustDataGridViewWidth() { DataGridViewExtensions.FastAutoSizeColumns(dgv); @@ -456,11 +503,6 @@ namespace SystemTrayMenu.UserInterface MouseWheel?.Invoke(); } - internal void SetTitleColorActive() - { - labelTitle.ForeColor = Color.Black; - } - private void LabelTitle_MouseDoubleClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) @@ -479,39 +521,6 @@ namespace SystemTrayMenu.UserInterface labelTitle.BackColor = MenuDefines.ColorTitleBackground; } - protected override CreateParams CreateParams - { - get - { - CreateParams createparams = base.CreateParams; - createparams.ExStyle |= 0x80; - return createparams; - } - } - - protected override bool ProcessCmdKey(ref Message msg, Keys keys) - { - switch (keys) - { - case Keys.Enter: - case Keys.Up: - case Keys.Down: - case Keys.Left: - case Keys.Right: - case Keys.Escape: - case Keys.Control | Keys.F: - case Keys.Tab: - case Keys.Tab | Keys.Shift: - case Keys.Apps: - CmdKeyProcessed.Invoke(this, keys); - return true; - default: - break; - } - - return base.ProcessCmdKey(ref msg, keys); - } - private void TextBoxSearch_TextChanged(object sender, EventArgs e) { DataTable data = (DataTable)dgv.DataSource; @@ -531,13 +540,5 @@ namespace SystemTrayMenu.UserInterface SearchTextChanged.Invoke(this, null); } - - internal void KeyPressedSearch(string letter) - { - textBoxSearch.Text += letter; - textBoxSearch.SelectionStart = textBoxSearch.Text.Length; - textBoxSearch.SelectionLength = 0; - textBoxSearch.Focus(); - } } } \ No newline at end of file diff --git a/UserInterface/SettingsForm.Designer.cs b/UserInterface/SettingsForm.Designer.cs index 4d3d433..b73c9df 100644 --- a/UserInterface/SettingsForm.Designer.cs +++ b/UserInterface/SettingsForm.Designer.cs @@ -1,4 +1,4 @@ -using SystemTrayMenu.UserInterface.Controls; +using SystemTrayMenu.UserInterface.HotkeyTextboxControl; namespace SystemTrayMenu.UserInterface { @@ -37,7 +37,7 @@ namespace SystemTrayMenu.UserInterface this.tableLayoutPanelGeneral = new System.Windows.Forms.TableLayoutPanel(); this.comboBoxLanguage = new System.Windows.Forms.ComboBox(); this.labelLanguage = new System.Windows.Forms.Label(); - this.textBoxHotkey = new SystemTrayMenu.UserInterface.Controls.HotkeyControl(); + this.textBoxHotkey = new SystemTrayMenu.UserInterface.HotkeyTextboxControl.HotkeyControl(); this.checkBoxAutostart = new System.Windows.Forms.CheckBox(); this.labelHotkey = new System.Windows.Forms.Label(); this.labelAutostart = new System.Windows.Forms.Label(); diff --git a/UserInterface/SettingsForm.cs b/UserInterface/SettingsForm.cs index acbe781..7f25302 100644 --- a/UserInterface/SettingsForm.cs +++ b/UserInterface/SettingsForm.cs @@ -4,21 +4,19 @@ namespace SystemTrayMenu.UserInterface { - using Microsoft.Win32; using System; using System.Collections.Generic; using System.Drawing; using System.Reflection; using System.Text; using System.Windows.Forms; - using SystemTrayMenu.UserInterface.Controls; + using Microsoft.Win32; + using SystemTrayMenu.UserInterface.HotkeyTextboxControl; using SystemTrayMenu.Utilities; - using static SystemTrayMenu.UserInterface.Controls.HotkeyControl; + using static SystemTrayMenu.UserInterface.HotkeyTextboxControl.HotkeyControl; public partial class SettingsForm : Form { - public string NewHotKey => newHotKey; - private readonly string newHotKey = string.Empty; private bool inHotkey = false; @@ -79,82 +77,15 @@ namespace SystemTrayMenu.UserInterface } } - private void SettingsForm_Load(object sender, EventArgs e) - { - tabControl1.Size = new Size( - tableLayoutPanelGeneral.Size.Width, - tableLayoutPanelGeneral.Size.Height); - } + public string NewHotKey => newHotKey; - private void ButtonOk_Click(object sender, EventArgs e) + /// + /// Registers all hotkeys as configured, displaying a dialog in case of hotkey conflicts with other tools. + /// + /// Whether the hotkeys could be registered to the users content. This also applies if conflicts arise and the user decides to ignore these (i.e. not to register the conflicting hotkey). + public static bool RegisterHotkeys() { - SetAutostart(); - SetHotkey(); - SetLanguage(); - Properties.Settings.Default.Save(); - DialogResult = DialogResult.OK; - Close(); - } - - private void SetAutostart() - { - if (checkBoxAutostart.Checked) - { - RegistryKey key = Registry.CurrentUser.OpenSubKey( - @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - key.SetValue( - Assembly.GetExecutingAssembly().GetName().Name, - System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); - Properties.Settings.Default.IsAutostartActivated = true; - } - else - { - RegistryKey key = Registry.CurrentUser.OpenSubKey( - @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - key.DeleteValue("SystemTrayMenu", false); - Properties.Settings.Default.IsAutostartActivated = false; - } - } - - private void SetHotkey() - { - Properties.Settings.Default.HotKey = - new KeysConverter().ConvertToInvariantString( - textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers); - } - - private void SetLanguage() - { - Properties.Settings.Default.CurrentCultureInfoName = - comboBoxLanguage.SelectedValue.ToString(); - } - - private void ButtonCancel_Click(object sender, EventArgs e) - { - Properties.Settings.Default.Reload(); - DialogResult = DialogResult.Cancel; - Close(); - } - - private void ButtonChange_Click(object sender, EventArgs e) - { - Config.SetFolderByUser(false); - textBoxFolder.Text = Config.Path; - } - - private void TextBoxHotkeyEnter(object sender, EventArgs e) - { - HotkeyControl.UnregisterHotkeys(); - inHotkey = true; - } - - private void TextBoxHotkey_Leave(object sender, EventArgs e) - { - Properties.Settings.Default.HotKey = - new KeysConverter().ConvertToInvariantString( - textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers); - RegisterHotkeys(); - inHotkey = false; + return RegisterHotkeys(false); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) @@ -216,15 +147,6 @@ namespace SystemTrayMenu.UserInterface return success; } - /// - /// Registers all hotkeys as configured, displaying a dialog in case of hotkey conflicts with other tools. - /// - /// Whether the hotkeys could be registered to the users content. This also applies if conflicts arise and the user decides to ignore these (i.e. not to register the conflicting hotkey). - public static bool RegisterHotkeys() - { - return RegisterHotkeys(false); - } - /// /// Registers all hotkeys as configured, displaying a dialog in case of hotkey conflicts with other tools. /// @@ -312,12 +234,83 @@ namespace SystemTrayMenu.UserInterface return success; } - } - public class Language - { - public string Name { get; set; } + private void SettingsForm_Load(object sender, EventArgs e) + { + tabControl1.Size = new Size( + tableLayoutPanelGeneral.Size.Width, + tableLayoutPanelGeneral.Size.Height); + } - public string Value { get; set; } + private void ButtonOk_Click(object sender, EventArgs e) + { + SetAutostart(); + SetHotkey(); + SetLanguage(); + Properties.Settings.Default.Save(); + DialogResult = DialogResult.OK; + Close(); + } + + private void SetAutostart() + { + if (checkBoxAutostart.Checked) + { + RegistryKey key = Registry.CurrentUser.OpenSubKey( + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); + key.SetValue( + Assembly.GetExecutingAssembly().GetName().Name, + System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); + Properties.Settings.Default.IsAutostartActivated = true; + } + else + { + RegistryKey key = Registry.CurrentUser.OpenSubKey( + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); + key.DeleteValue("SystemTrayMenu", false); + Properties.Settings.Default.IsAutostartActivated = false; + } + } + + private void SetHotkey() + { + Properties.Settings.Default.HotKey = + new KeysConverter().ConvertToInvariantString( + textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers); + } + + private void SetLanguage() + { + Properties.Settings.Default.CurrentCultureInfoName = + comboBoxLanguage.SelectedValue.ToString(); + } + + private void ButtonCancel_Click(object sender, EventArgs e) + { + Properties.Settings.Default.Reload(); + DialogResult = DialogResult.Cancel; + Close(); + } + + private void ButtonChange_Click(object sender, EventArgs e) + { + Config.SetFolderByUser(false); + textBoxFolder.Text = Config.Path; + } + + private void TextBoxHotkeyEnter(object sender, EventArgs e) + { + HotkeyControl.UnregisterHotkeys(); + inHotkey = true; + } + + private void TextBoxHotkey_Leave(object sender, EventArgs e) + { + Properties.Settings.Default.HotKey = + new KeysConverter().ConvertToInvariantString( + textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers); + RegisterHotkeys(); + inHotkey = false; + } } } diff --git a/UserInterface/ShellContextMenu/ShellContextMenu.cs b/UserInterface/ShellContextMenu/ShellContextMenu.cs index a01d710..f62f2c5 100644 --- a/UserInterface/ShellContextMenu/ShellContextMenu.cs +++ b/UserInterface/ShellContextMenu/ShellContextMenu.cs @@ -76,499 +76,6 @@ namespace SystemTrayMenu.Utilities ReleaseAll(); } - /// Gets the interfaces to the context menu. - /// Parent folder. - /// PIDLs. - /// true if it got the interfaces, otherwise false. - private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr) - { - int nResult = oParentFolder.GetUIObjectOf( - IntPtr.Zero, - (uint)arrPIDLs.Length, - arrPIDLs, - ref iidIContextMenu, - IntPtr.Zero, - out ctxMenuPtr); - - if (nResult == ResultOK) - { - oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu)); - - /*IntPtr pUnknownContextMenu2 = IntPtr.Zero; - if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu2, out pUnknownContextMenu2)) - { - _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu2, typeof(IContextMenu2)); - } - IntPtr pUnknownContextMenu3 = IntPtr.Zero; - if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu3, out pUnknownContextMenu3)) - { - _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu3, typeof(IContextMenu3)); - }*/ - - return true; - } - else - { - ctxMenuPtr = IntPtr.Zero; - oContextMenu = null; - return false; - } - } - - /// - /// This method receives WindowMessages. It will make the "Open With" and "Send To" work - /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover - /// method of Browser when hovering over a ContextMenu item. - /// - /// the Message of the Browser's WndProc. - protected override void WndProc(ref Message m) - { - if (oContextMenu != null && - m.Msg == (int)WM.MENUSELECT && - ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.SEPARATOR) == 0 && - ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.POPUP) == 0) - { - } - - if (oContextMenu2 != null && - (m.Msg == (int)WM.INITMENUPOPUP || - m.Msg == (int)WM.MEASUREITEM || - m.Msg == (int)WM.DRAWITEM)) - { - if (oContextMenu2.HandleMenuMsg( - (uint)m.Msg, m.WParam, m.LParam) == ResultOK) - { - return; - } - } - - if (oContextMenu3 != null && - m.Msg == (int)WM.MENUCHAR) - { - if (oContextMenu3.HandleMenuMsg2( - (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == ResultOK) - { - return; - } - } - - base.WndProc(ref m); - } - - private static void InvokeCommand(IContextMenu contextMenu, uint nCmd, string strFolder, Point pointInvoke) - { - CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX - { - CbSize = CbInvokeCommand, - LpVerb = (IntPtr)(nCmd - CmdFirst), - LpDirectory = strFolder, - LpVerbW = (IntPtr)(nCmd - CmdFirst), - LpDirectoryW = strFolder, - FMask = CMIC.UNICODE | CMIC.PTINVOKE | - ((Control.ModifierKeys & Keys.Control) != 0 ? CMIC.CONTROL_DOWN : 0) | - ((Control.ModifierKeys & Keys.Shift) != 0 ? CMIC.SHIFT_DOWN : 0), - PtInvoke = new POINT(pointInvoke.X, pointInvoke.Y), - NShow = SW.SHOWNORMAL, - }; - - _ = contextMenu.InvokeCommand(ref invoke); - } - - /// - /// Release all allocated interfaces, PIDLs. - /// - private void ReleaseAll() - { - if (oContextMenu != null) - { - Marshal.ReleaseComObject(oContextMenu); - oContextMenu = null; - } - - if (oContextMenu2 != null) - { - Marshal.ReleaseComObject(oContextMenu2); - oContextMenu2 = null; - } - - if (oContextMenu3 != null) - { - Marshal.ReleaseComObject(oContextMenu3); - oContextMenu3 = null; - } - - if (oDesktopFolder != null) - { - Marshal.ReleaseComObject(oDesktopFolder); - oDesktopFolder = null; - } - - if (oParentFolder != null) - { - Marshal.ReleaseComObject(oParentFolder); - oParentFolder = null; - } - - if (arrPIDLs != null) - { - FreePIDLs(arrPIDLs); - arrPIDLs = null; - } - } - - /// - /// Gets the desktop folder. - /// - /// IShellFolder for desktop folder. - private IShellFolder GetDesktopFolder() - { - if (oDesktopFolder == null) - { - // Get desktop IShellFolder - int nResult = DllImports.NativeMethods.Shell32SHGetDesktopFolder(out IntPtr pUnkownDesktopFolder); - if (nResult != ResultOK) - { -#pragma warning disable CA1303 // Do not pass literals as localized parameters - throw new ShellContextMenuException("Failed to get the desktop shell folder"); -#pragma warning restore CA1303 //=> Exceptions not translated in logfile => OK - } - - oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder)); - } - - return oDesktopFolder; - } - - /// - /// Gets the parent folder. - /// - /// Folder path. - /// IShellFolder for the folder (relative from the desktop). - private IShellFolder GetParentFolder(string folderName) - { - if (oParentFolder == null) - { - IShellFolder oDesktopFolder = GetDesktopFolder(); - if (oDesktopFolder == null) - { - return null; - } - - // Get the PIDL for the folder file is in - uint pchEaten = 0; - SFGAO pdwAttributes = 0; - int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out IntPtr pPIDL, ref pdwAttributes); - if (nResult != ResultOK) - { - return null; - } - - IntPtr pStrRet = Marshal.AllocCoTaskMem((MaxPath * 2) + 4); - Marshal.WriteInt32(pStrRet, 0, 0); - _ = this.oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet); - StringBuilder strFolder = new StringBuilder(MaxPath); - _ = DllImports.NativeMethods.ShlwapiStrRetToBuf(pStrRet, pPIDL, strFolder, MaxPath); - Marshal.FreeCoTaskMem(pStrRet); - strParentFolder = strFolder.ToString(); - - // Get the IShellFolder for folder - nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref iidIShellFolder, out IntPtr pUnknownParentFolder); - - // Free the PIDL first - Marshal.FreeCoTaskMem(pPIDL); - if (nResult != ResultOK) - { - return null; - } - - oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder)); - } - - return oParentFolder; - } - - /// - /// Get the PIDLs. - /// - /// Array of FileInfo. - /// Array of PIDLs. - protected IntPtr[] GetPIDLs(FileInfo[] arrFI) - { - if (arrFI == null || arrFI.Length == 0) - { - return null; - } - - IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName); - if (oParentFolder == null) - { - return null; - } - - IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; - int n = 0; - foreach (FileInfo fi in arrFI) - { - // Get the file relative to folder - uint pchEaten = 0; - SFGAO pdwAttributes = 0; - IntPtr pPIDL = IntPtr.Zero; - int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); - if (nResult != ResultOK) - { - FreePIDLs(arrPIDLs); - return null; - } - - arrPIDLs[n] = pPIDL; - n++; - } - - return arrPIDLs; - } - - /// - /// Get the PIDLs. - /// - /// Array of DirectoryInfo. - /// Array of PIDLs. - protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI) - { - if (arrFI == null || arrFI.Length == 0 || arrFI[0].Parent == null) - { - return null; - } - - IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName); - if (oParentFolder == null) - { - return null; - } - - IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; - int n = 0; - foreach (DirectoryInfo fi in arrFI) - { - // Get the file relative to folder - uint pchEaten = 0; - SFGAO pdwAttributes = 0; - IntPtr pPIDL = IntPtr.Zero; - int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); - if (nResult != ResultOK) - { - FreePIDLs(arrPIDLs); - return null; - } - - arrPIDLs[n] = pPIDL; - n++; - } - - return arrPIDLs; - } - - /// - /// Free the PIDLs. - /// - /// Array of PIDLs (IntPtr). - protected static void FreePIDLs(IntPtr[] arrPIDLs) - { - if (arrPIDLs != null) - { - for (int n = 0; n < arrPIDLs.Length; n++) - { - if (arrPIDLs[n] != IntPtr.Zero) - { - Marshal.FreeCoTaskMem(arrPIDLs[n]); - arrPIDLs[n] = IntPtr.Zero; - } - } - } - } - - /// - /// Shows the context menu. - /// - /// FileInfos (should all be in same directory). - /// Where to show the menu. - public void ShowContextMenu(FileInfo[] files, Point pointScreen) - { - // Release all resources first. - ReleaseAll(); - arrPIDLs = GetPIDLs(files); - ShowContextMenu(pointScreen); - } - - /// - /// Shows the context menu. - /// - /// DirectoryInfos (should all be in same directory). - /// Where to show the menu. - public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen) - { - // Release all resources first. - ReleaseAll(); - arrPIDLs = GetPIDLs(dirs); - ShowContextMenu(pointScreen); - } - - /// - /// Shows the context menu. - /// - /// Where to show the menu. - public void ShowContextMenu(Point pointScreen) - { - IntPtr pMenu = IntPtr.Zero, - iContextMenuPtr = IntPtr.Zero, - iContextMenuPtr2 = IntPtr.Zero, - iContextMenuPtr3 = IntPtr.Zero; - - try - { - if (arrPIDLs == null) - { - ReleaseAll(); - return; - } - - if (!GetContextMenuInterfaces(oParentFolder, arrPIDLs, out iContextMenuPtr)) - { - ReleaseAll(); - return; - } - - pMenu = DllImports.NativeMethods.User32CreatePopupMenu(); - - int nResult = oContextMenu.QueryContextMenu( - pMenu, - 0, - CmdFirst, - CmdLast, - CMF.EXPLORE | CMF.NORMAL | ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); - - Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu2, out iContextMenuPtr2); - Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu3, out iContextMenuPtr3); - - oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2)); - oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3)); - - uint nSelected = DllImports.NativeMethods.User32TrackPopupMenuEx( - pMenu, - DllImports.NativeMethods.TPM.RETURNCMD, - pointScreen.X, - pointScreen.Y, - Handle, - IntPtr.Zero); - - DllImports.NativeMethods.User32DestroyMenu(pMenu); - pMenu = IntPtr.Zero; - - if (nSelected != 0) - { - InvokeCommand(oContextMenu, nSelected, strParentFolder, pointScreen); - } - } - catch - { - throw; - } - finally - { - if (pMenu != IntPtr.Zero) - { - DllImports.NativeMethods.User32DestroyMenu(pMenu); - } - - if (iContextMenuPtr != IntPtr.Zero) - { - Marshal.Release(iContextMenuPtr); - } - - if (iContextMenuPtr2 != IntPtr.Zero) - { - Marshal.Release(iContextMenuPtr2); - } - - if (iContextMenuPtr3 != IntPtr.Zero) - { - Marshal.Release(iContextMenuPtr3); - } - - ReleaseAll(); - } - } - - [StructLayout(LayoutKind.Sequential)] - private struct CWPSTRUCT - { - public IntPtr Lparam; - public IntPtr Wparam; - public int Message; - public IntPtr Hwnd; - } - - // Contains extended information about a shortcut menu command - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private struct CMINVOKECOMMANDINFOEX - { - public int CbSize; - public CMIC FMask; - public IntPtr Hwnd; - public IntPtr LpVerb; - [MarshalAs(UnmanagedType.LPStr)] - public string LpParameters; - [MarshalAs(UnmanagedType.LPStr)] - public string LpDirectory; - public SW NShow; - public int DwHotKey; - public IntPtr HIcon; - [MarshalAs(UnmanagedType.LPStr)] - public string LpTitle; - public IntPtr LpVerbW; - [MarshalAs(UnmanagedType.LPWStr)] - public string LpParametersW; - [MarshalAs(UnmanagedType.LPWStr)] - public string LpDirectoryW; - [MarshalAs(UnmanagedType.LPWStr)] - public string LpTitleW; - public POINT PtInvoke; - } - - // Contains information about a menu item - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private struct MENUITEMINFO - { - private readonly int cbSize; - private readonly MIIM fMask; - private readonly MFT fType; - private readonly MFS fState; - private readonly uint wID; - private readonly IntPtr hSubMenu; - private readonly IntPtr hbmpChecked; - private readonly IntPtr hbmpUnchecked; - private readonly IntPtr dwItemData; - [MarshalAs(UnmanagedType.LPTStr)] - private readonly string dwTypeData; - private readonly int cch; - private readonly IntPtr hbmpItem; - - public MENUITEMINFO(string text) - { - cbSize = CbMenuItemInfo; - dwTypeData = text; - cch = text.Length; - fMask = 0; - fType = 0; - fState = 0; - wID = 0; - hSubMenu = IntPtr.Zero; - hbmpChecked = IntPtr.Zero; - hbmpUnchecked = IntPtr.Zero; - dwItemData = IntPtr.Zero; - hbmpItem = IntPtr.Zero; - } - } - // Defines the values used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf // methods to specify the type of file or folder names used by those methods [Flags] @@ -967,36 +474,6 @@ namespace SystemTrayMenu.Utilities NULL = 0, } - // A generalized global memory handle used for data transfer operations by the - // IAdviseSink, IDataObject, and IOleCache interfaces - [StructLayout(LayoutKind.Sequential)] - private struct STGMEDIUM - { - public TYMED Tymed; - public IntPtr HBitmap; - public IntPtr HMetaFilePict; - public IntPtr HEnhMetaFile; - public IntPtr HGlobal; - public IntPtr LpszFileName; - public IntPtr Pstm; - public IntPtr Pstg; - public IntPtr PUnkForRelease; - } - - // Defines the x- and y-coordinates of a point - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private struct POINT - { - public POINT(int x, int y) - { - X = x; - Y = y; - } - - public int X; - public int Y; - } - [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("000214E6-0000-0000-C000-000000000046")] @@ -1222,5 +699,528 @@ namespace SystemTrayMenu.Utilities IntPtr lParam, IntPtr plResult); } + + /// + /// Shows the context menu. + /// + /// FileInfos (should all be in same directory). + /// Where to show the menu. + public void ShowContextMenu(FileInfo[] files, Point pointScreen) + { + // Release all resources first. + ReleaseAll(); + arrPIDLs = GetPIDLs(files); + ShowContextMenu(pointScreen); + } + + /// + /// Shows the context menu. + /// + /// DirectoryInfos (should all be in same directory). + /// Where to show the menu. + public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen) + { + // Release all resources first. + ReleaseAll(); + arrPIDLs = GetPIDLs(dirs); + ShowContextMenu(pointScreen); + } + + /// + /// Shows the context menu. + /// + /// Where to show the menu. + public void ShowContextMenu(Point pointScreen) + { + IntPtr pMenu = IntPtr.Zero, + iContextMenuPtr = IntPtr.Zero, + iContextMenuPtr2 = IntPtr.Zero, + iContextMenuPtr3 = IntPtr.Zero; + + try + { + if (arrPIDLs == null) + { + ReleaseAll(); + return; + } + + if (!GetContextMenuInterfaces(oParentFolder, arrPIDLs, out iContextMenuPtr)) + { + ReleaseAll(); + return; + } + + pMenu = DllImports.NativeMethods.User32CreatePopupMenu(); + + int nResult = oContextMenu.QueryContextMenu( + pMenu, + 0, + CmdFirst, + CmdLast, + CMF.EXPLORE | CMF.NORMAL | ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); + + Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu2, out iContextMenuPtr2); + Marshal.QueryInterface(iContextMenuPtr, ref iidIContextMenu3, out iContextMenuPtr3); + + oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2)); + oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3)); + + uint nSelected = DllImports.NativeMethods.User32TrackPopupMenuEx( + pMenu, + DllImports.NativeMethods.TPM.RETURNCMD, + pointScreen.X, + pointScreen.Y, + Handle, + IntPtr.Zero); + + DllImports.NativeMethods.User32DestroyMenu(pMenu); + pMenu = IntPtr.Zero; + + if (nSelected != 0) + { + InvokeCommand(oContextMenu, nSelected, strParentFolder, pointScreen); + } + } + catch + { + throw; + } + finally + { + if (pMenu != IntPtr.Zero) + { + DllImports.NativeMethods.User32DestroyMenu(pMenu); + } + + if (iContextMenuPtr != IntPtr.Zero) + { + Marshal.Release(iContextMenuPtr); + } + + if (iContextMenuPtr2 != IntPtr.Zero) + { + Marshal.Release(iContextMenuPtr2); + } + + if (iContextMenuPtr3 != IntPtr.Zero) + { + Marshal.Release(iContextMenuPtr3); + } + + ReleaseAll(); + } + } + + /// + /// Free the PIDLs. + /// + /// Array of PIDLs (IntPtr). + protected static void FreePIDLs(IntPtr[] arrPIDLs) + { + if (arrPIDLs != null) + { + for (int n = 0; n < arrPIDLs.Length; n++) + { + if (arrPIDLs[n] != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(arrPIDLs[n]); + arrPIDLs[n] = IntPtr.Zero; + } + } + } + } + + /// + /// This method receives WindowMessages. It will make the "Open With" and "Send To" work + /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover + /// method of Browser when hovering over a ContextMenu item. + /// + /// the Message of the Browser's WndProc. + protected override void WndProc(ref Message m) + { + if (oContextMenu != null && + m.Msg == (int)WM.MENUSELECT && + ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.SEPARATOR) == 0 && + ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.POPUP) == 0) + { + } + + if (oContextMenu2 != null && + (m.Msg == (int)WM.INITMENUPOPUP || + m.Msg == (int)WM.MEASUREITEM || + m.Msg == (int)WM.DRAWITEM)) + { + if (oContextMenu2.HandleMenuMsg( + (uint)m.Msg, m.WParam, m.LParam) == ResultOK) + { + return; + } + } + + if (oContextMenu3 != null && + m.Msg == (int)WM.MENUCHAR) + { + if (oContextMenu3.HandleMenuMsg2( + (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == ResultOK) + { + return; + } + } + + base.WndProc(ref m); + } + + /// + /// Get the PIDLs. + /// + /// Array of FileInfo. + /// Array of PIDLs. + protected IntPtr[] GetPIDLs(FileInfo[] arrFI) + { + if (arrFI == null || arrFI.Length == 0) + { + return null; + } + + IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName); + if (oParentFolder == null) + { + return null; + } + + IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; + int n = 0; + foreach (FileInfo fi in arrFI) + { + // Get the file relative to folder + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + IntPtr pPIDL = IntPtr.Zero; + int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); + if (nResult != ResultOK) + { + FreePIDLs(arrPIDLs); + return null; + } + + arrPIDLs[n] = pPIDL; + n++; + } + + return arrPIDLs; + } + + /// + /// Get the PIDLs. + /// + /// Array of DirectoryInfo. + /// Array of PIDLs. + protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI) + { + if (arrFI == null || arrFI.Length == 0 || arrFI[0].Parent == null) + { + return null; + } + + IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName); + if (oParentFolder == null) + { + return null; + } + + IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; + int n = 0; + foreach (DirectoryInfo fi in arrFI) + { + // Get the file relative to folder + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + IntPtr pPIDL = IntPtr.Zero; + int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); + if (nResult != ResultOK) + { + FreePIDLs(arrPIDLs); + return null; + } + + arrPIDLs[n] = pPIDL; + n++; + } + + return arrPIDLs; + } + + private static void InvokeCommand(IContextMenu contextMenu, uint nCmd, string strFolder, Point pointInvoke) + { + CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX + { + CbSize = CbInvokeCommand, + LpVerb = (IntPtr)(nCmd - CmdFirst), + LpDirectory = strFolder, + LpVerbW = (IntPtr)(nCmd - CmdFirst), + LpDirectoryW = strFolder, + FMask = CMIC.UNICODE | CMIC.PTINVOKE | + ((Control.ModifierKeys & Keys.Control) != 0 ? CMIC.CONTROL_DOWN : 0) | + ((Control.ModifierKeys & Keys.Shift) != 0 ? CMIC.SHIFT_DOWN : 0), + PtInvoke = new POINT(pointInvoke.X, pointInvoke.Y), + NShow = SW.SHOWNORMAL, + }; + + _ = contextMenu.InvokeCommand(ref invoke); + } + + /// Gets the interfaces to the context menu. + /// Parent folder. + /// PIDLs. + /// true if it got the interfaces, otherwise false. + private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr) + { + int nResult = oParentFolder.GetUIObjectOf( + IntPtr.Zero, + (uint)arrPIDLs.Length, + arrPIDLs, + ref iidIContextMenu, + IntPtr.Zero, + out ctxMenuPtr); + + if (nResult == ResultOK) + { + oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu)); + + /*IntPtr pUnknownContextMenu2 = IntPtr.Zero; + if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu2, out pUnknownContextMenu2)) + { + _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu2, typeof(IContextMenu2)); + } + IntPtr pUnknownContextMenu3 = IntPtr.Zero; + if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu3, out pUnknownContextMenu3)) + { + _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu3, typeof(IContextMenu3)); + }*/ + + return true; + } + else + { + ctxMenuPtr = IntPtr.Zero; + oContextMenu = null; + return false; + } + } + + /// + /// Release all allocated interfaces, PIDLs. + /// + private void ReleaseAll() + { + if (oContextMenu != null) + { + Marshal.ReleaseComObject(oContextMenu); + oContextMenu = null; + } + + if (oContextMenu2 != null) + { + Marshal.ReleaseComObject(oContextMenu2); + oContextMenu2 = null; + } + + if (oContextMenu3 != null) + { + Marshal.ReleaseComObject(oContextMenu3); + oContextMenu3 = null; + } + + if (oDesktopFolder != null) + { + Marshal.ReleaseComObject(oDesktopFolder); + oDesktopFolder = null; + } + + if (oParentFolder != null) + { + Marshal.ReleaseComObject(oParentFolder); + oParentFolder = null; + } + + if (arrPIDLs != null) + { + FreePIDLs(arrPIDLs); + arrPIDLs = null; + } + } + + /// + /// Gets the desktop folder. + /// + /// IShellFolder for desktop folder. + private IShellFolder GetDesktopFolder() + { + if (oDesktopFolder == null) + { + // Get desktop IShellFolder + int nResult = DllImports.NativeMethods.Shell32SHGetDesktopFolder(out IntPtr pUnkownDesktopFolder); + if (nResult != ResultOK) + { +#pragma warning disable CA1303 // Do not pass literals as localized parameters + throw new ShellContextMenuException("Failed to get the desktop shell folder"); +#pragma warning restore CA1303 //=> Exceptions not translated in logfile => OK + } + + oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder)); + } + + return oDesktopFolder; + } + + /// + /// Gets the parent folder. + /// + /// Folder path. + /// IShellFolder for the folder (relative from the desktop). + private IShellFolder GetParentFolder(string folderName) + { + if (oParentFolder == null) + { + IShellFolder oDesktopFolder = GetDesktopFolder(); + if (oDesktopFolder == null) + { + return null; + } + + // Get the PIDL for the folder file is in + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out IntPtr pPIDL, ref pdwAttributes); + if (nResult != ResultOK) + { + return null; + } + + IntPtr pStrRet = Marshal.AllocCoTaskMem((MaxPath * 2) + 4); + Marshal.WriteInt32(pStrRet, 0, 0); + _ = this.oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet); + StringBuilder strFolder = new StringBuilder(MaxPath); + _ = DllImports.NativeMethods.ShlwapiStrRetToBuf(pStrRet, pPIDL, strFolder, MaxPath); + Marshal.FreeCoTaskMem(pStrRet); + strParentFolder = strFolder.ToString(); + + // Get the IShellFolder for folder + nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref iidIShellFolder, out IntPtr pUnknownParentFolder); + + // Free the PIDL first + Marshal.FreeCoTaskMem(pPIDL); + if (nResult != ResultOK) + { + return null; + } + + oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder)); + } + + return oParentFolder; + } + + [StructLayout(LayoutKind.Sequential)] + private struct CWPSTRUCT + { + public IntPtr Lparam; + public IntPtr Wparam; + public int Message; + public IntPtr Hwnd; + } + + // Contains extended information about a shortcut menu command + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct CMINVOKECOMMANDINFOEX + { + public int CbSize; + public CMIC FMask; + public IntPtr Hwnd; + public IntPtr LpVerb; + [MarshalAs(UnmanagedType.LPStr)] + public string LpParameters; + [MarshalAs(UnmanagedType.LPStr)] + public string LpDirectory; + public SW NShow; + public int DwHotKey; + public IntPtr HIcon; + [MarshalAs(UnmanagedType.LPStr)] + public string LpTitle; + public IntPtr LpVerbW; + [MarshalAs(UnmanagedType.LPWStr)] + public string LpParametersW; + [MarshalAs(UnmanagedType.LPWStr)] + public string LpDirectoryW; + [MarshalAs(UnmanagedType.LPWStr)] + public string LpTitleW; + public POINT PtInvoke; + } + + // Contains information about a menu item + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct MENUITEMINFO + { + private readonly int cbSize; + private readonly MIIM fMask; + private readonly MFT fType; + private readonly MFS fState; + private readonly uint wID; + private readonly IntPtr hSubMenu; + private readonly IntPtr hbmpChecked; + private readonly IntPtr hbmpUnchecked; + private readonly IntPtr dwItemData; + [MarshalAs(UnmanagedType.LPTStr)] + private readonly string dwTypeData; + private readonly int cch; + private readonly IntPtr hbmpItem; + + public MENUITEMINFO(string text) + { + cbSize = CbMenuItemInfo; + dwTypeData = text; + cch = text.Length; + fMask = 0; + fType = 0; + fState = 0; + wID = 0; + hSubMenu = IntPtr.Zero; + hbmpChecked = IntPtr.Zero; + hbmpUnchecked = IntPtr.Zero; + dwItemData = IntPtr.Zero; + hbmpItem = IntPtr.Zero; + } + } + + // A generalized global memory handle used for data transfer operations by the + // IAdviseSink, IDataObject, and IOleCache interfaces + [StructLayout(LayoutKind.Sequential)] + private struct STGMEDIUM + { + public TYMED Tymed; + public IntPtr HBitmap; + public IntPtr HMetaFilePict; + public IntPtr HEnhMetaFile; + public IntPtr HGlobal; + public IntPtr LpszFileName; + public IntPtr Pstm; + public IntPtr Pstg; + public IntPtr PUnkForRelease; + } + + // Defines the x- and y-coordinates of a point + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct POINT + { + public int X; + public int Y; + + public POINT(int x, int y) + { + X = x; + Y = y; + } + } } } diff --git a/Utilities/AppRestart.cs b/Utilities/AppRestart.cs index 32f3b4f..5798c9c 100644 --- a/Utilities/AppRestart.cs +++ b/Utilities/AppRestart.cs @@ -13,6 +13,26 @@ namespace SystemTrayMenu.Utilities { public static event EventHandlerEmpty BeforeRestarting; + internal static void ByThreadException() + { + Restart(GetCurrentMethod()); + } + + internal static void ByMenuNotifyIcon() + { + Restart(GetCurrentMethod()); + } + + internal static void ByDisplaySettings(object sender, EventArgs e) + { + Restart(GetCurrentMethod()); + } + + internal static void ByConfigChange() + { + Restart(GetCurrentMethod()); + } + private static void Restart(string reason) { BeforeRestarting?.Invoke(); @@ -38,25 +58,5 @@ namespace SystemTrayMenu.Utilities return sf.GetMethod().Name; } - - internal static void ByThreadException() - { - Restart(GetCurrentMethod()); - } - - internal static void ByMenuNotifyIcon() - { - Restart(GetCurrentMethod()); - } - - internal static void ByDisplaySettings(object sender, EventArgs e) - { - Restart(GetCurrentMethod()); - } - - internal static void ByConfigChange() - { - Restart(GetCurrentMethod()); - } } } diff --git a/Utilities/File/FileLnk.cs b/Utilities/File/FileLnk.cs index 0d95fe0..4bbad63 100644 --- a/Utilities/File/FileLnk.cs +++ b/Utilities/File/FileLnk.cs @@ -4,10 +4,10 @@ namespace SystemTrayMenu.Utilities { - using Shell32; using System; using System.IO; using System.Threading; + using Shell32; internal class FileLnk { @@ -34,6 +34,28 @@ namespace SystemTrayMenu.Utilities return resolvedFilename; } + public static bool IsDirectory(string filePath) + { + bool isDirectory = false; + if (Directory.Exists(filePath)) + { + FileAttributes attributes = File.GetAttributes(filePath); + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + { + isDirectory = true; + } + } + + return isDirectory; + } + + public static bool IsNetworkRoot(string path) + { + return !System.IO.File.Exists(path) && + path.StartsWith(@"\\", StringComparison.InvariantCulture) && + !path.Substring(2).Contains(@"\", StringComparison.InvariantCulture); + } + private static string GetShortcutFileNamePath(object shortcutFilename) { string resolvedFilename = string.Empty; @@ -65,27 +87,5 @@ namespace SystemTrayMenu.Utilities return resolvedFilename; } - - public static bool IsDirectory(string filePath) - { - bool isDirectory = false; - if (Directory.Exists(filePath)) - { - FileAttributes attributes = File.GetAttributes(filePath); - if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - { - isDirectory = true; - } - } - - return isDirectory; - } - - public static bool IsNetworkRoot(string path) - { - return !System.IO.File.Exists(path) && - path.StartsWith(@"\\", StringComparison.InvariantCulture) && - !path.Substring(2).Contains(@"\", StringComparison.InvariantCulture); - } } } \ No newline at end of file diff --git a/Utilities/File/IconReader.cs b/Utilities/File/IconReader.cs index ea37ffc..0eddc38 100644 --- a/Utilities/File/IconReader.cs +++ b/Utilities/File/IconReader.cs @@ -69,83 +69,6 @@ namespace SystemTrayMenu.Utilities return icon; } - private static bool IsExtensionWitSameIcon(string fileExtension) - { - bool isExtensionWitSameIcon = true; - List extensionsWithDiffIcons = new List - { string.Empty, ".EXE", ".LNK", ".ICO", ".URL" }; - if (extensionsWithDiffIcons.Contains(fileExtension.ToUpperInvariant())) - { - isExtensionWitSameIcon = false; - } - - return isExtensionWitSameIcon; - } - - private static Icon GetFileIcon(string filePath, bool linkOverlay, IconSize size = IconSize.Small) - { - Icon icon = null; - DllImports.NativeMethods.SHFILEINFO shfi = default; - uint flags = DllImports.NativeMethods.ShgfiIcon | DllImports.NativeMethods.ShgfiSYSICONINDEX; - - if (linkOverlay) - { - flags += DllImports.NativeMethods.ShgfiLINKOVERLAY; - } - - /* Check the size specified for return. */ - if (size == IconSize.Small) - { - flags += DllImports.NativeMethods.ShgfiSMALLICON; - } - else - { - flags += DllImports.NativeMethods.ShgfiLARGEICON; - } - - IntPtr hImageList = DllImports.NativeMethods.Shell32SHGetFileInfo( - filePath, - DllImports.NativeMethods.FileAttributeNormal, - ref shfi, - (uint)Marshal.SizeOf(shfi), - flags); - if (hImageList != IntPtr.Zero) - { - IntPtr hIcon; - if (linkOverlay) - { - hIcon = shfi.hIcon; // Get icon directly - } - else - { - // Get icon from .ink without overlay - hIcon = DllImports.NativeMethods.ImageList_GetIcon(hImageList, shfi.iIcon, DllImports.NativeMethods.IldTransparent); - } - - try - { - // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly - icon = (Icon)Icon.FromHandle(hIcon).Clone(); - } -#pragma warning disable CA1031 // Do not catch general exception types - catch (Exception ex) -#pragma warning restore CA1031 // Do not catch general exception types - { - Log.Error($"filePath:'{filePath}'", ex); - } - - // Cleanup - if (!linkOverlay) - { - DllImports.NativeMethods.User32DestroyIcon(hIcon); - } - - DllImports.NativeMethods.User32DestroyIcon(shfi.hIcon); - } - - return icon; - } - public static Icon GetFolderIcon( string directoryPath, FolderType folderType, @@ -224,5 +147,82 @@ namespace SystemTrayMenu.Utilities return icon; } + + private static bool IsExtensionWitSameIcon(string fileExtension) + { + bool isExtensionWitSameIcon = true; + List extensionsWithDiffIcons = new List + { string.Empty, ".EXE", ".LNK", ".ICO", ".URL" }; + if (extensionsWithDiffIcons.Contains(fileExtension.ToUpperInvariant())) + { + isExtensionWitSameIcon = false; + } + + return isExtensionWitSameIcon; + } + + private static Icon GetFileIcon(string filePath, bool linkOverlay, IconSize size = IconSize.Small) + { + Icon icon = null; + DllImports.NativeMethods.SHFILEINFO shfi = default; + uint flags = DllImports.NativeMethods.ShgfiIcon | DllImports.NativeMethods.ShgfiSYSICONINDEX; + + if (linkOverlay) + { + flags += DllImports.NativeMethods.ShgfiLINKOVERLAY; + } + + /* Check the size specified for return. */ + if (size == IconSize.Small) + { + flags += DllImports.NativeMethods.ShgfiSMALLICON; + } + else + { + flags += DllImports.NativeMethods.ShgfiLARGEICON; + } + + IntPtr hImageList = DllImports.NativeMethods.Shell32SHGetFileInfo( + filePath, + DllImports.NativeMethods.FileAttributeNormal, + ref shfi, + (uint)Marshal.SizeOf(shfi), + flags); + if (hImageList != IntPtr.Zero) + { + IntPtr hIcon; + if (linkOverlay) + { + hIcon = shfi.hIcon; // Get icon directly + } + else + { + // Get icon from .ink without overlay + hIcon = DllImports.NativeMethods.ImageList_GetIcon(hImageList, shfi.iIcon, DllImports.NativeMethods.IldTransparent); + } + + try + { + // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly + icon = (Icon)Icon.FromHandle(hIcon).Clone(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + Log.Error($"filePath:'{filePath}'", ex); + } + + // Cleanup + if (!linkOverlay) + { + DllImports.NativeMethods.User32DestroyIcon(hIcon); + } + + DllImports.NativeMethods.User32DestroyIcon(shfi.hIcon); + } + + return icon; + } } } \ No newline at end of file diff --git a/Utilities/FolderOptions.cs b/Utilities/FolderOptions.cs index 44003d8..7f1ed45 100644 --- a/Utilities/FolderOptions.cs +++ b/Utilities/FolderOptions.cs @@ -4,11 +4,11 @@ namespace SystemTrayMenu.Utilities { - using Shell32; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; + using Shell32; internal static class FolderOptions { diff --git a/Utilities/Language.cs b/Utilities/Language.cs new file mode 100644 index 0000000..ee4f3d3 --- /dev/null +++ b/Utilities/Language.cs @@ -0,0 +1,13 @@ +// +// Copyright (c) PlaceholderCompany. All rights reserved. +// + +namespace SystemTrayMenu.Utilities +{ + internal class Language + { + public string Name { get; set; } + + public string Value { get; set; } + } +} diff --git a/Utilities/Log.cs b/Utilities/Log.cs index 78c3654..e1fcd1b 100644 --- a/Utilities/Log.cs +++ b/Utilities/Log.cs @@ -4,13 +4,13 @@ namespace SystemTrayMenu.Utilities { - using Clearcove.Logging; using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Reflection; using System.Windows.Forms; + using Clearcove.Logging; internal static class Log { diff --git a/Utilities/Scaling.cs b/Utilities/Scaling.cs index d5d9132..cd97281 100644 --- a/Utilities/Scaling.cs +++ b/Utilities/Scaling.cs @@ -9,14 +9,14 @@ namespace SystemTrayMenu.Utilities internal static class Scaling { - internal static float Factor = 1; - private enum DeviceCap { VERTRES = 10, DESKTOPVERTRES = 117, } + public static float Factor { get; private set; } = 1; + internal static void Initialize() { CalculateScalingFactor(); diff --git a/Utilities/Translator.cs b/Utilities/Translator.cs index 26671c0..39ede94 100644 --- a/Utilities/Translator.cs +++ b/Utilities/Translator.cs @@ -34,11 +34,4 @@ namespace SystemTrayMenu.Utilities return rm.GetString(id, culture); } } - - public class Language - { - public string Name { get; set; } - - public string Value { get; set; } - } }