Code Analyze and Refactor 0.12 (#109), version 0.11.4.3

This commit is contained in:
Markus Hofknecht 2020-07-06 23:37:55 +02:00
parent 2d2eb88339
commit 2686adf0df
49 changed files with 956 additions and 909 deletions

View file

@ -16,25 +16,31 @@ namespace SystemTrayMenu.Handler
internal class KeyboardInput : IDisposable
{
internal event EventHandlerEmpty HotKeyPressed;
internal event EventHandlerEmpty ClosePressed;
internal event Action<DataGridView, int> RowSelected;
internal event Action<int, DataGridView> RowDeselected;
internal Action<DataGridView, int> EnterPressed;
internal event EventHandlerEmpty Cleared;
internal bool InUse = false;
internal int iRowKey = -1;
internal int iMenuKey = 0;
private readonly Menu[] menus;
private readonly KeyboardHook hook = new KeyboardHook();
private int iRowKey = -1;
private int iMenuKey = 0;
public KeyboardInput(Menu[] menus)
{
this.menus = menus;
}
internal event EventHandlerEmpty HotKeyPressed;
internal event EventHandlerEmpty ClosePressed;
internal event Action<DataGridView, int> RowSelected;
internal event Action<int, DataGridView> RowDeselected;
internal event Action<DataGridView, int> EnterPressed;
internal event EventHandlerEmpty Cleared;
public void Dispose()
{
hook.Dispose();
@ -47,8 +53,8 @@ namespace SystemTrayMenu.Handler
try
{
hook.RegisterHotKey();
hook.KeyPressed += hook_KeyPressed;
void hook_KeyPressed(object sender, KeyPressedEventArgs e)
hook.KeyPressed += Hook_KeyPressed;
void Hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
HotKeyPressed?.Invoke();
}
@ -161,8 +167,8 @@ namespace SystemTrayMenu.Handler
/// <summary>
/// While menu is open user presses a key to search for specific entries.
/// </summary>
/// <param name="sender">not used</param>
/// <param name="e">Key data of the pressed key</param>
/// <param name="sender">not used.</param>
/// <param name="e">Key data of the pressed key.</param>
internal void KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetterOrDigit(e.KeyChar) ||
@ -227,7 +233,7 @@ namespace SystemTrayMenu.Handler
return isStillSelected;
}
private void SelectByKey(Keys keys, string keyInput = "", bool KeepSelection = false)
private void SelectByKey(Keys keys, string keyInput = "", bool keepSelection = false)
{
int iRowBefore = iRowKey;
int iMenuBefore = iMenuKey;
@ -240,7 +246,7 @@ namespace SystemTrayMenu.Handler
bool isStillSelected = IsAnyMenuSelectedByKey(ref dgv, ref menuFromSelected, ref textselected);
if (isStillSelected)
{
if (KeepSelection)
if (keepSelection)
{
// If current selection is still valid for this search then skip selecting different item
if (textselected.StartsWith(keyInput, true, CultureInfo.InvariantCulture))

View file

@ -1,4 +1,7 @@

// <copyright file="Menus.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Business
{
using System;
@ -20,27 +23,21 @@ namespace SystemTrayMenu.Business
internal class Menus : IDisposable
{
internal event EventHandlerEmpty LoadStarted;
internal event EventHandlerEmpty LoadStopped;
private enum OpenCloseState { Default, Opening, Closing };
private OpenCloseState openCloseState = OpenCloseState.Default;
private readonly Menu[] menus = new Menu[MenuDefines.MenusMax];
private readonly BackgroundWorker workerMainMenu = new BackgroundWorker();
private readonly List<BackgroundWorker> workersSubMenu = new List<BackgroundWorker>();
private readonly int screenHeight = Screen.PrimaryScreen.Bounds.Height;
private readonly int screenWidth = Screen.PrimaryScreen.Bounds.Width;
private readonly int screenRight = Screen.PrimaryScreen.Bounds.Right;
private readonly int taskbarHeight = new WindowsTaskbar().Size.Height;
private readonly WaitToLoadMenu waitToOpenMenu = new WaitToLoadMenu();
private readonly KeyboardInput keyboardInput = null;
private readonly Timer timerStillActiveCheck = new Timer();
private readonly WaitLeave waitLeave = new WaitLeave(MenuDefines.TimeUntilClose);
private DateTime deactivatedTime = DateTime.MinValue;
private IEnumerable<Menu> AsEnumerable => menus.Where(m => m != null && !m.IsDisposed);
private List<Menu> AsList => AsEnumerable.ToList();
private readonly int screenHeight = Screen.PrimaryScreen.Bounds.Height;
private readonly int screenWidth = Screen.PrimaryScreen.Bounds.Width;
private readonly int screenRight = Screen.PrimaryScreen.Bounds.Right;
private readonly int taskbarHeight = new WindowsTaskbar().Size.Height;
private OpenCloseState openCloseState = OpenCloseState.Default;
public Menus()
{
@ -107,11 +104,10 @@ namespace SystemTrayMenu.Business
workersSubMenu.Add(workerSubMenu);
}
workerSubMenu.RunWorkerAsync(rowData); ;
workerSubMenu.RunWorkerAsync(rowData);
}
void LoadSubMenuCompleted(object senderCompleted,
RunWorkerCompletedEventArgs e)
void LoadSubMenuCompleted(object senderCompleted, RunWorkerCompletedEventArgs e)
{
LoadStopped();
MenuData menuData = (MenuData)e.Result;
@ -183,6 +179,21 @@ namespace SystemTrayMenu.Business
}
}
internal event EventHandlerEmpty LoadStarted;
internal event EventHandlerEmpty LoadStopped;
private enum OpenCloseState
{
Default,
Opening,
Closing,
}
private IEnumerable<Menu> AsEnumerable => menus.Where(m => m != null && !m.IsDisposed);
private List<Menu> AsList => AsEnumerable.ToList();
internal void SwitchOpenCloseByTaskbarItem()
{
SwitchOpenClose(true);
@ -201,7 +212,7 @@ namespace SystemTrayMenu.Business
// Case when Folder Dialog open
}
else if (openCloseState == OpenCloseState.Opening ||
menus[0].Visible && openCloseState == OpenCloseState.Default)
(menus[0].Visible && openCloseState == OpenCloseState.Default))
{
openCloseState = OpenCloseState.Closing;
MenusFadeOut();
@ -310,8 +321,9 @@ namespace SystemTrayMenu.Business
return
output
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => Path.Combine(networkLocationRootPath,
x.Substring(0, x.IndexOf(' ', StringComparison.InvariantCulture))))
.Select(x => Path.Combine(
networkLocationRootPath,
x.Substring(0, x.IndexOf(' ', StringComparison.InvariantCulture))))
.ToArray();
}
}
@ -497,7 +509,6 @@ namespace SystemTrayMenu.Business
return rowData;
}
private Menu Create(MenuData menuData, string title = null)
{
Menu menu = new Menu();

View file

@ -7,20 +7,19 @@ namespace SystemTrayMenu.Handler
using System;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitLeave : IDisposable
{
public event EventHandlerEmpty LeaveTriggered;
private readonly Timer timerLeaveCheck = new Timer();
public bool IsRunning => timerLeaveCheck.Enabled;
public WaitLeave(int timeUntilTriggered)
{
timerLeaveCheck.Interval = timeUntilTriggered;
timerLeaveCheck.Tick += TimerLeaveCheckTick;
}
public event EventHandlerEmpty LeaveTriggered;
public void Start()
{
timerLeaveCheck.Stop();

View file

@ -13,10 +13,6 @@ namespace SystemTrayMenu.Handler
internal class WaitToLoadMenu : IDisposable
{
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event EventHandlerEmpty StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
internal bool MouseActive = false;
private readonly Timer timerStartLoad = new Timer();
@ -35,6 +31,14 @@ namespace SystemTrayMenu.Handler
timerStartLoad.Tick += WaitStartLoad_Tick;
}
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event EventHandlerEmpty StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
internal void MouseEnter(object sender, DataGridViewCellEventArgs e)
{
if (MouseActive)

View file

@ -5,10 +5,14 @@
namespace SystemTrayMenu
{
using System.Drawing;
using System.Reflection;
internal static class MenuDefines
{
internal static string NotifyIconText = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyTitleAttribute>().Title;
internal const int Scrollspeed = 4;
internal const int TimeUntilClose = 1000;
internal const int MenusMax = 50;
internal const int LengthMax = 37;
internal const float MaxMenuWidth = 300;
internal static readonly Color File = Color.White;
internal static readonly Color Folder = Color.White;
internal static readonly Color ColorSelectedItem = AppColors.Blue;
@ -18,11 +22,6 @@ namespace SystemTrayMenu
internal static readonly Color ColorTitleWarning = AppColors.Red;
internal static readonly Color ColorTitleSelected = AppColors.Yellow;
internal static readonly Color ColorTitleBackground = AppColors.Azure;
internal const int Scrollspeed = 4;
internal const int TimeUntilClose = 1000;
internal const int MenusMax = 50;
internal const int LengthMax = 37;
internal static float MaxMenuWidth = 300;
}
internal static class AppColors

View file

@ -34,11 +34,11 @@ namespace SystemTrayMenu.DataClasses
internal string TargetFilePathOrig;
internal int RowIndex;
internal int MenuLevel;
private static DateTime ContextMenuClosed;
private string WorkingDirectory;
private string Arguments;
private string Text;
private Icon Icon = null;
private static DateTime contextMenuClosed;
private string workingDirectory;
private string arguments;
private string text;
private Icon icon = null;
private bool diposeIcon = true;
private bool isDisposed = false;
@ -48,7 +48,7 @@ namespace SystemTrayMenu.DataClasses
internal void SetText(string text)
{
Text = text;
this.text = text;
}
internal void SetData(RowData data, DataTable dataTable)
@ -56,22 +56,23 @@ namespace SystemTrayMenu.DataClasses
DataRow row = dataTable.Rows.Add();
data.RowIndex = dataTable.Rows.IndexOf(row);
if (Icon == null)
if (icon == null)
{
Icon = Properties.Resources.WhiteTransparency;
icon = Properties.Resources.WhiteTransparency;
}
if (HiddenEntry)
{
row[0] = IconReader.AddIconOverlay(data.Icon,
row[0] = IconReader.AddIconOverlay(
data.icon,
Properties.Resources.WhiteTransparency);
}
else
{
row[0] = data.Icon;
row[0] = data.icon;
}
row[1] = data.Text;
row[1] = data.text;
row[2] = data;
}
@ -85,7 +86,7 @@ namespace SystemTrayMenu.DataClasses
}
else if (isDirectory)
{
Icon = IconReader.GetFolderIcon(
icon = IconReader.GetFolderIcon(
TargetFilePath,
IconReader.FolderType.Closed,
false);
@ -97,7 +98,8 @@ namespace SystemTrayMenu.DataClasses
if (fileExtension == ".lnk")
{
handled = SetLnk(ref isLnkDirectory,
handled = SetLnk(
ref isLnkDirectory,
ref resolvedLnkPath);
}
else if (fileExtension == ".url")
@ -113,7 +115,7 @@ namespace SystemTrayMenu.DataClasses
{
try
{
Icon = IconReader.GetFileIconWithCache(TargetFilePath, false);
icon = IconReader.GetFileIconWithCache(TargetFilePath, false);
diposeIcon = false;
// other project -> fails sometimes
@ -154,7 +156,7 @@ namespace SystemTrayMenu.DataClasses
FileInfo != null &&
dgv != null &&
dgv.Rows.Count > RowIndex &&
(DateTime.Now - ContextMenuClosed).TotalMilliseconds > 200)
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
{
IsContextMenuOpen = true;
Color colorbefore = dgv.Rows[RowIndex].DefaultCellStyle.SelectionBackColor;
@ -185,15 +187,14 @@ namespace SystemTrayMenu.DataClasses
}
IsContextMenuOpen = false;
ContextMenuClosed = DateTime.Now;
contextMenuClosed = DateTime.Now;
}
}
internal void DoubleClick(MouseEventArgs e)
{
if (e == null ||
e.Button == MouseButtons.Left &&
!ContainsMenu)
if (!ContainsMenu &&
(e == null || e.Button == MouseButtons.Left))
{
try
{
@ -202,11 +203,11 @@ namespace SystemTrayMenu.DataClasses
StartInfo = new ProcessStartInfo(TargetFilePath)
{
FileName = TargetFilePathOrig,
Arguments = Arguments,
WorkingDirectory = WorkingDirectory,
Arguments = arguments,
WorkingDirectory = workingDirectory,
CreateNoWindow = true,
UseShellExecute = true,
}
},
};
p.Start();
}
@ -217,9 +218,8 @@ namespace SystemTrayMenu.DataClasses
}
}
if (e == null ||
e.Button == MouseButtons.Left &&
ContainsMenu)
if (ContainsMenu &&
(e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart("explorer.exe", TargetFilePath);
}
@ -237,21 +237,22 @@ namespace SystemTrayMenu.DataClasses
{
if (diposeIcon)
{
Icon?.Dispose();
icon?.Dispose();
}
}
isDisposed = true;
}
private bool SetLnk(ref bool isLnkDirectory,
private bool SetLnk(
ref bool isLnkDirectory,
ref string resolvedLnkPath)
{
bool handled = false;
resolvedLnkPath = FileLnk.GetResolvedFileName(TargetFilePath);
if (FileLnk.IsDirectory(resolvedLnkPath))
{
Icon = IconReader.GetFolderIcon(TargetFilePath, IconReader.FolderType.Open, true);
icon = IconReader.GetFolderIcon(TargetFilePath, IconReader.FolderType.Open, true);
handled = true;
isLnkDirectory = true;
}
@ -268,8 +269,8 @@ namespace SystemTrayMenu.DataClasses
IWshShell shell = new WshShell();
IWshShortcut lnk = shell.CreateShortcut(TargetFilePath)
as IWshShortcut;
Arguments = lnk.Arguments;
WorkingDirectory = lnk.WorkingDirectory;
arguments = lnk.Arguments;
workingDirectory = lnk.WorkingDirectory;
string iconLocation = lnk.IconLocation;
if (iconLocation.Length > 2)
{
@ -278,7 +279,7 @@ namespace SystemTrayMenu.DataClasses
{
try
{
Icon = Icon.ExtractAssociatedIcon(iconLocation);
icon = Icon.ExtractAssociatedIcon(iconLocation);
handled = true;
}
catch (ArgumentException ex)
@ -314,14 +315,14 @@ namespace SystemTrayMenu.DataClasses
}
else
{
Icon = IconReader.GetFileIconWithCache(browserPath, false);
icon = IconReader.GetFileIconWithCache(browserPath, false);
diposeIcon = false;
handled = true;
}
}
else if (System.IO.File.Exists(iconFile))
{
Icon = Icon.ExtractAssociatedIcon(iconFile);
icon = Icon.ExtractAssociatedIcon(iconFile);
handled = true;
}
else
@ -337,7 +338,8 @@ namespace SystemTrayMenu.DataClasses
ex is PathTooLongException ||
ex is NotSupportedException)
{
Log.Warn($"path:'{TargetFilePath}', " +
Log.Warn(
$"path:'{TargetFilePath}', " +
$"iconFile:'{iconFile}'", ex);
}
else
@ -358,11 +360,12 @@ namespace SystemTrayMenu.DataClasses
try
{
DllImports.NativeMethods.Shell32FindExecutable(TargetFilePath, string.Empty, executable);
// icon = IconReader.GetFileIcon(executable, false);
// e.g. VS 2019 icon, need another icom in imagelist
List<Icon> extractedIcons = IconHelper.ExtractAllIcons(
executable.ToString());
Icon = extractedIcons.Last();
icon = extractedIcons.Last();
handled = true;
}
catch (Exception ex)
@ -373,7 +376,8 @@ namespace SystemTrayMenu.DataClasses
ex is PathTooLongException ||
ex is NotSupportedException)
{
Log.Warn($"path:'{TargetFilePath}', " +
Log.Warn(
$"path:'{TargetFilePath}', " +
$"executable:'{executable}'", ex);
}
else

View file

@ -1,10 +1,11 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
// <copyright file="GlobalSuppressions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
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", "SA1101:Prefix local calls with this", Justification = "Standard codecleanup removes the this")]

View file

@ -10,16 +10,6 @@ namespace SystemTrayMenu.UserInterface
public class Fading : IDisposable
{
internal event EventHandlerEmpty Hide;
internal event EventHandlerEmpty Show;
internal event EventHandler<double> ChangeOpacity;
internal enum FadingState { Idle, Show, ShowTransparent, Hide }
internal bool IsHiding => state == FadingState.Hide;
private const int Interval60FPS = 16; // 60fps=>1s/60fps=~16.6ms
private const double StepIn = 0.20;
@ -45,6 +35,22 @@ namespace SystemTrayMenu.UserInterface
}
}
internal event EventHandlerEmpty Hide;
internal event EventHandlerEmpty Show;
internal event EventHandler<double> ChangeOpacity;
internal enum FadingState
{
Idle,
Show,
ShowTransparent,
Hide,
}
internal bool IsHiding => state == FadingState.Hide;
internal void Fade(FadingState state)
{
StartStopTimer(state);

View file

@ -9,61 +9,50 @@ namespace SystemTrayMenu.Helper
using SystemTrayMenu.UserInterface.Controls;
using SystemTrayMenu.Utilities;
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
internal enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8,
}
public sealed class KeyboardHook : IDisposable
{
/// <summary>
/// Represents the window that is used internally to get the messages.
/// </summary>
private class Window : NativeWindow, IDisposable
{
private const int WM_HOTKEY = 0x0312;
public Window()
{
// create the handle for the window.
CreateHandle(new CreateParams());
}
/// <summary>
/// Overridden to get the notifications.
/// </summary>
/// <param name="m">m.</param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// check if we got a hot key pressed.
if (m.Msg == WM_HOTKEY)
{
// get the keys.
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF);
// invoke the event to notify the parent.
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
}
}
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
DestroyHandle();
}
}
private readonly Window _window = new Window();
private int _currentId;
private readonly Window window = new Window();
private int currentId;
public KeyboardHook()
{
// register the event of the inner native window.
_window.KeyPressed += delegate (object sender, KeyPressedEventArgs args)
window.KeyPressed += (sender, args) =>
{
KeyPressed?.Invoke(this, args);
};
}
/// <summary>
/// A hot key has been pressed.
/// </summary>
internal event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
// unregister all the registered hot keys.
for (int i = currentId; i > 0; i--)
{
DllImports.NativeMethods.User32UnregisterHotKey(window.Handle, i);
}
// dispose the inner native window.
window.Dispose();
}
/// <summary>
/// Registers a hot key in the system.
/// </summary>
@ -102,7 +91,8 @@ namespace SystemTrayMenu.Helper
}
}
RegisterHotKey(modifiers,
RegisterHotKey(
modifiers,
HotkeyControl.HotkeyFromString(
Properties.Settings.Default.HotKey));
}
@ -119,10 +109,10 @@ namespace SystemTrayMenu.Helper
private void RegisterHotKey(uint modifier, Keys key)
{
_currentId += 1;
currentId += 1;
if (!DllImports.NativeMethods.User32RegisterHotKey(
_window.Handle, _currentId, modifier, (uint)key))
window.Handle, currentId, modifier, (uint)key))
{
throw new InvalidOperationException(
Translator.GetText("Could not register the hot key."));
@ -130,20 +120,44 @@ namespace SystemTrayMenu.Helper
}
/// <summary>
/// A hot key has been pressed.
/// Represents the window that is used internally to get the messages.
/// </summary>
internal event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
private class Window : NativeWindow, IDisposable
{
// unregister all the registered hot keys.
for (int i = _currentId; i > 0; i--)
private const int WmHotkey = 0x0312;
public Window()
{
DllImports.NativeMethods.User32UnregisterHotKey(_window.Handle, i);
// create the handle for the window.
CreateHandle(new CreateParams());
}
// dispose the inner native window.
_window.Dispose();
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
DestroyHandle();
}
/// <summary>
/// Overridden to get the notifications.
/// </summary>
/// <param name="m">m.</param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// check if we got a hot key pressed.
if (m.Msg == WmHotkey)
{
// get the keys.
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF);
// invoke the event to notify the parent.
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
}
}
}
}
@ -152,30 +166,17 @@ namespace SystemTrayMenu.Helper
/// </summary>
internal class KeyPressedEventArgs : EventArgs
{
private readonly KeyboardHookModifierKeys _modifier;
private readonly Keys _key;
private readonly KeyboardHookModifierKeys modifier;
private readonly Keys key;
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key)
{
_modifier = modifier;
_key = key;
this.modifier = modifier;
this.key = key;
}
internal KeyboardHookModifierKeys Modifier => _modifier;
internal KeyboardHookModifierKeys Modifier => modifier;
internal Keys Key => _key;
}
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
internal enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8,
internal Keys Key => key;
}
}

View file

@ -5,6 +5,7 @@
namespace SystemTrayMenu.Helper
{
using System.Collections.Generic;
internal class WindowsExplorerSort : IComparer<string>
{
public int Compare(string x, string y)

View file

@ -8,6 +8,7 @@ namespace SystemTrayMenu.Helper
using System.Drawing;
using System.Runtime.InteropServices;
using static SystemTrayMenu.DllImports.NativeMethods;
public enum TaskbarPosition
{
Unknown = -1,
@ -21,6 +22,33 @@ namespace SystemTrayMenu.Helper
{
private const string ClassName = "Shell_TrayWnd";
public WindowsTaskbar()
{
IntPtr taskbarHandle = User32FindWindow(ClassName, null);
APPBARDATA data = new APPBARDATA
{
cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
hWnd = taskbarHandle,
};
IntPtr result = Shell32SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
{
Bounds = new Rectangle(20, 20, 20, 20);
}
else
{
Position = (TaskbarPosition)data.uEdge;
Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);
data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA));
result = Shell32SHAppBarMessage(ABM.GetState, ref data);
int state = result.ToInt32();
AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
}
public Rectangle Bounds
{
get;
@ -48,32 +76,5 @@ namespace SystemTrayMenu.Helper
get;
private set;
}
public WindowsTaskbar()
{
IntPtr taskbarHandle = User32FindWindow(ClassName, null);
APPBARDATA data = new APPBARDATA
{
cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
hWnd = taskbarHandle,
};
IntPtr result = Shell32SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
{
Bounds = new Rectangle(20, 20, 20, 20);
}
else
{
Position = (TaskbarPosition)data.uEdge;
Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);
data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA));
result = Shell32SHAppBarMessage(ABM.GetState, ref data);
int state = result.ToInt32();
AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
}
}
}

View file

@ -6,11 +6,41 @@ namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SwRestore = 9;
public static void ForceForegroundWindow(IntPtr hWnd)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const int SW_SHOW = 5;
int cmdShow = SW_SHOW;
if (IsIconic(hWnd))
{
cmdShow = SwRestore;
}
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
}
}
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
@ -28,34 +58,5 @@ namespace SystemTrayMenu.DllImports
[DllImport("user32.dll", SetLastError = true)]
private static extern bool BringWindowToTop(IntPtr hWnd);
private const int SW_RESTORE = 9;
public static void ForceForegroundWindow(IntPtr hWnd)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const int SW_SHOW = 5;
int cmdShow = SW_SHOW;
if (IsIconic(hWnd))
{
cmdShow = SW_RESTORE;
}
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
}
}
}
}

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>

View file

@ -12,7 +12,6 @@ namespace SystemTrayMenu.DllImports
/// </summary>
public static partial class NativeMethods
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "<Pending>")]
public static IntPtr User32FindWindow(string lpClassName, string lpWindowName)
{
return FindWindow(lpClassName, lpWindowName);

View file

@ -12,12 +12,12 @@ namespace SystemTrayMenu.DllImports
/// </summary>
public static partial class NativeMethods
{
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public static int Gdi32GetDeviceCaps(IntPtr hdc, int nIndex)
{
return GetDeviceCaps(hdc, nIndex);
}
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
}
}

View file

@ -35,12 +35,14 @@ namespace SystemTrayMenu.DllImports
Bottom = 3,
}
internal static class ABS
internal static IntPtr Shell32SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData)
{
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
return SHAppBarMessage(dwMessage, ref pData);
}
[DllImport("shell32.dll", SetLastError = true)]
private static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
[StructLayout(LayoutKind.Sequential)]
internal struct APPBARDATA
{
@ -61,12 +63,10 @@ namespace SystemTrayMenu.DllImports
public int bottom;
}
internal static IntPtr Shell32SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData)
internal static class ABS
{
return SHAppBarMessage(dwMessage, ref pData);
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
}
[DllImport("shell32.dll", SetLastError = true)]
private static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
}
}

View file

@ -14,19 +14,6 @@ namespace SystemTrayMenu.DllImports
{
private const int maxPath = 256;
[StructLayout(LayoutKind.Sequential)]
internal struct SHFILEINFO
{
public const int NAMESIZE = 80;
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = maxPath)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
public string szTypeName;
}
internal static IntPtr Shell32SHGetFileInfo(
string pszPath,
uint dwFileAttributes,
@ -49,5 +36,18 @@ namespace SystemTrayMenu.DllImports
ref SHFILEINFO psfi,
uint cbFileInfo,
uint uFlags);
[StructLayout(LayoutKind.Sequential)]
internal struct SHFILEINFO
{
public const int NAMESIZE = 80;
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = maxPath)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
public string szTypeName;
}
}
}

View file

@ -15,6 +15,7 @@ namespace SystemTrayMenu.DllImports
{
[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);

View file

@ -5,6 +5,7 @@
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
@ -12,6 +13,7 @@ namespace SystemTrayMenu.DllImports
{
[DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
public static void User32SetProcessDPIAware()
{
_ = SetProcessDPIAware();

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>

View file

@ -5,6 +5,7 @@
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>

View file

@ -1,4 +1,8 @@
using System.Reflection;
// <copyright file="AssemblyInfo.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
@ -35,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.2")]
[assembly: AssemblyFileVersion("0.11.4.2")]
[assembly: AssemblyVersion("0.11.4.3")]
[assembly: AssemblyFileVersion("0.11.4.3")]

View file

@ -197,7 +197,11 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.6">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.164">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -1,4 +1,8 @@
namespace SystemTrayMenu.UserInterface
// <copyright file="AboutBox.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
{
using Microsoft.Win32;
using System;
@ -13,16 +17,24 @@
using SystemTrayMenu.Utilities;
/// <summary>
/// Generic, self-contained About Box dialog
/// Generic, self-contained About Box dialog.
/// </summary>
/// <remarks>
/// Jeff Atwood
/// http://www.codinghorror.com
/// converted to C# by Scott Ferguson
/// http://www.forestmoon.com
/// .
/// </remarks>
public partial class AboutBox : Form
{
private bool isPainted = false;
private string entryAssemblyName;
private string callingAssemblyName;
private string executingAssemblyName;
private Assembly entryAssembly;
private NameValueCollection entryAssemblyAttribCollection;
public AboutBox()
{
InitializeComponent();
@ -31,13 +43,6 @@
buttonSystemInfo.Text = Translator.GetText("buttonSystemInfo");
}
private bool _IsPainted = false;
private string _EntryAssemblyName;
private string _CallingAssemblyName;
private string _ExecutingAssemblyName;
private Assembly _EntryAssembly;
private NameValueCollection _EntryAssemblyAttribCollection;
// <summary>
// returns the entry assembly for the current application domain
// </summary>
@ -47,8 +52,8 @@
// </remarks>
public Assembly AppEntryAssembly
{
get => _EntryAssembly;
set => _EntryAssembly = value;
get => entryAssembly;
set => entryAssembly = value;
}
// <summary>
@ -184,6 +189,14 @@
set => buttonDetails.Visible = value;
}
private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e)
{
if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails)
{
AssemblyNamesComboBox.Focus();
}
}
// <summary>
// exception-safe retrieval of LastWriteTime for this assembly.
// </summary>
@ -191,7 +204,9 @@
private static DateTime AssemblyLastWriteTime(Assembly a)
{
DateTime assemblyLastWriteTime = DateTime.MaxValue;
if (!a.IsDynamic) // Location property not available for dynamic assemblies
// Location property not available for dynamic assemblies
if (!a.IsDynamic)
{
if (!string.IsNullOrEmpty(a.Location))
{
@ -209,18 +224,18 @@
// <param name="a">Assembly to get build date for</param>
// <param name="ForceFileDate">Don't attempt to use the build number to calculate the date</param>
// <returns>DateTime this assembly was last built</returns>
private static DateTime AssemblyBuildDate(Assembly a, bool ForceFileDate)
private static DateTime AssemblyBuildDate(Assembly a, bool forceFileDate)
{
Version AssemblyVersion = a.GetName().Version;
Version assemblyVersion = a.GetName().Version;
DateTime dt;
if (ForceFileDate)
if (forceFileDate)
{
dt = AssemblyLastWriteTime(a);
}
else
{
dt = DateTime.Parse("01/01/2000", CultureInfo.InvariantCulture).AddDays(AssemblyVersion.Build).AddSeconds(AssemblyVersion.Revision * 2);
dt = DateTime.Parse("01/01/2000", CultureInfo.InvariantCulture).AddDays(assemblyVersion.Build).AddSeconds(assemblyVersion.Revision * 2);
#pragma warning disable CS0618
if (TimeZone.IsDaylightSavingTime(dt, TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year)))
#pragma warning restore CS0618
@ -228,7 +243,7 @@
dt = dt.AddHours(1);
}
if (dt > DateTime.Now || AssemblyVersion.Build < 730 || AssemblyVersion.Revision == 0)
if (dt > DateTime.Now || assemblyVersion.Build < 730 || assemblyVersion.Revision == 0)
{
dt = AssemblyLastWriteTime(a);
}
@ -303,7 +318,8 @@
{
System.Runtime.InteropServices.ComCompatibleVersionAttribute x;
x = (System.Runtime.InteropServices.ComCompatibleVersionAttribute)attrib;
value = x.MajorVersion + "." + x.MinorVersion + "." + x.RevisionNumber + "." + x.BuildNumber; break;
value = x.MajorVersion + "." + x.MinorVersion + "." + x.RevisionNumber + "." + x.BuildNumber;
break;
}
case "System.Runtime.InteropServices.ComVisibleAttribute":
@ -314,7 +330,8 @@
{
System.Runtime.InteropServices.TypeLibVersionAttribute x;
x = (System.Runtime.InteropServices.TypeLibVersionAttribute)attrib;
value = x.MajorVersion + "." + x.MinorVersion; break;
value = x.MajorVersion + "." + x.MinorVersion;
break;
}
case "System.Security.AllowPartiallyTrustedCallersAttribute":
@ -396,13 +413,13 @@
// <summary>
// reads an HKLM Windows Registry key value
// </summary>
private static string RegistryHklmValue(string KeyName, string SubKeyRef)
private static string RegistryHklmValue(string keyName, string subKeyRef)
{
string strSysInfoPath = string.Empty;
try
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey(KeyName);
strSysInfoPath = (string)rk.GetValue(SubKeyRef, string.Empty);
RegistryKey rk = Registry.LocalMachine.OpenSubKey(keyName);
strSysInfoPath = (string)rk.GetValue(subKeyRef, string.Empty);
}
catch (Exception ex)
{
@ -410,7 +427,7 @@
ex is UnauthorizedAccessException ||
ex is IOException)
{
Log.Warn($"KeyName:'{KeyName}' SubKeyRef:'{SubKeyRef}'", ex);
Log.Warn($"KeyName:'{keyName}' SubKeyRef:'{subKeyRef}'", ex);
}
else
{
@ -450,15 +467,15 @@
// <summary>
// populate a listview with the specified key and value strings
// </summary>
private static void Populate(ListView lvw, string Key, string Value)
private static void Populate(ListView lvw, string key, string value)
{
if (!string.IsNullOrEmpty(Value))
if (!string.IsNullOrEmpty(value))
{
ListViewItem lvi = new ListViewItem
{
Text = Key,
Text = key,
};
lvi.SubItems.Add(Value);
lvi.SubItems.Add(value);
lvw.Items.Add(lvi);
}
}
@ -473,9 +490,9 @@
Populate(AppInfoListView, "Application Base", d.SetupInformation.ApplicationBase);
Populate(AppInfoListView, "Friendly Name", d.FriendlyName);
Populate(AppInfoListView, " ", " ");
Populate(AppInfoListView, "Entry Assembly", _EntryAssemblyName);
Populate(AppInfoListView, "Executing Assembly", _ExecutingAssemblyName);
Populate(AppInfoListView, "Calling Assembly", _CallingAssemblyName);
Populate(AppInfoListView, "Entry Assembly", entryAssemblyName);
Populate(AppInfoListView, "Executing Assembly", executingAssemblyName);
Populate(AppInfoListView, "Calling Assembly", callingAssemblyName);
}
// <summary>
@ -488,7 +505,7 @@
PopulateAssemblySummary(a);
}
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(_EntryAssemblyName);
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(entryAssemblyName);
}
// <summary>
@ -505,17 +522,17 @@
Text = strAssemblyName,
Tag = strAssemblyName,
};
if (strAssemblyName == _CallingAssemblyName)
if (strAssemblyName == callingAssemblyName)
{
lvi.Text += " (calling)";
}
if (strAssemblyName == _ExecutingAssemblyName)
if (strAssemblyName == executingAssemblyName)
{
lvi.Text += " (executing)";
}
if (strAssemblyName == _EntryAssemblyName)
if (strAssemblyName == entryAssemblyName)
{
lvi.Text += " (entry)";
}
@ -532,13 +549,13 @@
// </summary>
private string EntryAssemblyAttrib(string strName)
{
if (_EntryAssemblyAttribCollection[strName] == null)
if (entryAssemblyAttribCollection[strName] == null)
{
return "<Assembly: Assembly" + strName + "(\"\")>";
}
else
{
return _EntryAssemblyAttribCollection[strName].ToString(CultureInfo.InvariantCulture);
return entryAssemblyAttribCollection[strName].ToString(CultureInfo.InvariantCulture);
}
}
@ -548,7 +565,7 @@
private void PopulateLabels()
{
// get entry assembly attribs
_EntryAssemblyAttribCollection = AssemblyAttribs(_EntryAssembly);
entryAssemblyAttribCollection = AssemblyAttribs(entryAssembly);
// set icon from parent, if present
if (Owner != null)
@ -624,11 +641,11 @@
// <summary>
// matches assembly by Assembly.GetName.Name; returns nothing if no match
// </summary>
private static Assembly MatchAssemblyByName(string AssemblyName)
private static Assembly MatchAssemblyByName(string assemblyName)
{
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
if (a.GetName().Name == AssemblyName)
if (a.GetName().Name == assemblyName)
{
return a;
}
@ -643,21 +660,21 @@
private void AboutBox_Load(object sender, EventArgs e)
{
// if the user didn't provide an assembly, try to guess which one is the entry assembly
if (_EntryAssembly == null)
if (entryAssembly == null)
{
_EntryAssembly = Assembly.GetEntryAssembly();
entryAssembly = Assembly.GetEntryAssembly();
}
if (_EntryAssembly == null)
if (entryAssembly == null)
{
_EntryAssembly = Assembly.GetExecutingAssembly();
entryAssembly = Assembly.GetExecutingAssembly();
}
_ExecutingAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
_CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name;
executingAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
callingAssemblyName = Assembly.GetCallingAssembly().GetName().Name;
// for web hosted apps, GetEntryAssembly = nothing
_EntryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
TabPanelDetails.Visible = false;
if (!MoreRichTextBox.Visible)
@ -671,9 +688,9 @@
// </summary>
private void AboutBox_Paint(object sender, PaintEventArgs e)
{
if (!_IsPainted)
if (!isPainted)
{
_IsPainted = true;
isPainted = true;
Application.DoEvents();
Cursor.Current = Cursors.WaitCursor;
PopulateLabels();
@ -769,37 +786,37 @@
// </summary>
private class ListViewItemComparer : System.Collections.IComparer
{
private readonly int _intCol;
private readonly bool _IsAscending = true;
private readonly int intCol;
private readonly bool isAscending = true;
public ListViewItemComparer()
{
_intCol = 0;
_IsAscending = true;
intCol = 0;
isAscending = true;
}
public ListViewItemComparer(int column, bool ascending)
{
if (column < 0)
{
_IsAscending = false;
isAscending = false;
}
else
{
_IsAscending = ascending;
isAscending = ascending;
}
_intCol = Math.Abs(column) - 1;
intCol = Math.Abs(column) - 1;
}
public int Compare(object x, object y)
{
int intResult = string.Compare(
((ListViewItem)x).SubItems[_intCol].Text,
((ListViewItem)y).SubItems[_intCol].Text,
((ListViewItem)x).SubItems[intCol].Text,
((ListViewItem)y).SubItems[intCol].Text,
CultureInfo.InvariantCulture,
CompareOptions.None);
if (_IsAscending)
if (isAscending)
{
return intResult;
}
@ -809,14 +826,5 @@
}
}
}
private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e)
{
if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails)
{
AssemblyNamesComboBox.Focus();
}
}
}
}

View file

@ -11,10 +11,13 @@ namespace SystemTrayMenu.Helper
using System.Windows.Forms;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
internal class AppContextMenu
{
public event EventHandlerEmpty ClickedOpenLog;
public event EventHandlerEmpty ClickedRestart;
public event EventHandlerEmpty ClickedExit;
public ContextMenuStrip Create()

View file

@ -13,23 +13,23 @@ namespace SystemTrayMenu.UserInterface
using SystemTrayMenu.Utilities;
using R = SystemTrayMenu.Properties.Resources;
using Timer = System.Windows.Forms.Timer;
internal class AppNotifyIcon : IDisposable
{
public event EventHandlerEmpty Click;
public event EventHandlerEmpty OpenLog;
public event EventHandlerEmpty Restart;
public event EventHandlerEmpty Exit;
private const int Interval60FPS = 16; // 60fps=>1s/60fps=~16.6ms
private readonly Timer load = new Timer();
private readonly NotifyIcon notifyIcon = new NotifyIcon();
private readonly int indexLoad = 0;
private readonly List<Icon> bitmapsLoading = new List<Icon>()
{
R.L010, R.L020, R.L030,
R.L040, R.L050, R.L060, R.L070, R.L080, R.L090, R.L100, R.L110, R.L120,
R.L130, R.L140, R.L150, R.L160, R.L170, R.L180,
};
private DateTime timeLoadingStart;
private bool threadsLoading = false;
private readonly Timer load = new Timer();
private int loadCount = 0;
private readonly int indexLoad = 0;
private readonly List<Icon> bitmapsLoading = new List<Icon>() { R.L010, R.L020, R.L030,
R.L040, R.L050, R.L060, R.L070, R.L080, R.L090, R.L100, R.L110, R.L120,
R.L130, R.L140, R.L150, R.L160, R.L170, R.L180, };
public AppNotifyIcon()
{
@ -37,7 +37,7 @@ namespace SystemTrayMenu.UserInterface
notifyIcon.Icon = bitmapsLoading.First();
load.Tick += Load_Tick;
load.Interval = Interval60FPS;
notifyIcon.Text = MenuDefines.NotifyIconText;
notifyIcon.Text = Translator.GetText("SystemTrayMenu");
notifyIcon.Visible = true;
notifyIcon.Icon = R.SystemTrayMenu;
AppContextMenu contextMenus = new AppContextMenu();
@ -74,6 +74,14 @@ namespace SystemTrayMenu.UserInterface
}
}
public event EventHandlerEmpty Click;
public event EventHandlerEmpty OpenLog;
public event EventHandlerEmpty Restart;
public event EventHandlerEmpty Exit;
private void VerifyClick(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)

View file

@ -6,7 +6,6 @@ namespace SystemTrayMenu.UserInterface.Controls
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Windows.Forms;
using SystemTrayMenu.DllImports;
@ -15,80 +14,37 @@ namespace SystemTrayMenu.UserInterface.Controls
/// <summary>
/// A simple control that allows the user to select pretty much any valid hotkey combination
/// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx
/// But is modified to fit in Greenshot, and have localized support
/// But is modified to fit in Greenshot, and have localized support.
/// </summary>
public sealed class HotkeyControl : TextBox
{
// Delegates for hooking up events.
public delegate void HotKeyHandler();
private const uint WmHotkey = 0x312;
private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks);
private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1;
// Holds the list of hotkeys
private static readonly IDictionary<int, HotKeyHandler> KeyHandlers = new Dictionary<int, HotKeyHandler>();
private static int _hotKeyCounter = 1;
private const uint WM_HOTKEY = 0x312;
private static IntPtr _hotkeyHwnd;
[SuppressMessage("ReSharper", "InconsistentNaming")]
private enum Modifiers
{
NONE = 0,
ALT = 1,
CTRL = 2,
SHIFT = 4,
WIN = 8,
NOREPEAT = 0x4000,
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
private enum MapType : uint
{
MAPVK_VK_TO_VSC = 0, // The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK = 1, // The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
MAPVK_VK_TO_CHAR = 2, // The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK_EX = 3, // The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
MAPVK_VK_TO_VSC_EX = 4, // The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0.
}
// These variables store the current hotkey and modifier(s)
private Keys _hotkey = Keys.None;
private Keys _modifiers = Keys.None;
private static int hotKeyCounter = 1;
private static IntPtr hotkeyHwnd;
// ArrayLists used to enforce the use of proper modifiers.
// Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.
private readonly IList<int> _needNonShiftModifier = new List<int>();
private readonly IList<int> _needNonAltGrModifier = new List<int>();
private readonly IList<int> needNonShiftModifier = new List<int>();
private readonly IList<int> needNonAltGrModifier = new List<int>();
private readonly ContextMenuStrip _dummy = new ContextMenuStrip();
private readonly ContextMenuStrip dummy = new ContextMenuStrip();
/// <summary>
/// Used to make sure that there is no right-click menu available
/// </summary>
public override ContextMenuStrip ContextMenuStrip
{
get => _dummy;
set => base.ContextMenuStrip = _dummy;
}
/// <summary>
/// Forces the control to be non-multiline
/// </summary>
public override bool Multiline
{
get => base.Multiline;
set =>
// Ignore what the user wants; force Multiline to false
base.Multiline = false;
}
// These variables store the current hotkey and modifier(s)
private Keys hotkey = Keys.None;
private Keys modifiers = Keys.None;
/// <summary>
/// Initializes a new instance of the <see cref="HotkeyControl"/> class.
/// </summary>
public HotkeyControl()
{
ContextMenuStrip = _dummy; // Disable right-clicking
ContextMenuStrip = dummy; // Disable right-clicking
Text = string.Empty;
// Handle events that occurs when keys are pressed
@ -99,57 +55,97 @@ namespace SystemTrayMenu.UserInterface.Controls
PopulateModifierLists();
}
/// <summary>
/// Gets or sets used to make sure that there is no right-click menu available.
/// </summary>
public override ContextMenuStrip ContextMenuStrip
{
get => dummy;
set => base.ContextMenuStrip = dummy;
}
/// <summary>
/// Gets or sets a value indicating whether forces the control to be non-multiline.
/// </summary>
public override bool Multiline
{
get => base.Multiline;
set => base.Multiline = false;
}
// Delegates for hooking up events.
public delegate void HotKeyHandler();
private enum Modifiers
{
NONE = 0,
ALT = 1,
CTRL = 2,
SHIFT = 4,
WIN = 8,
NOREPEAT = 0x4000,
}
private enum MapType : uint
{
MAPVK_VK_TO_VSC = 0, // The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK = 1, // The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
MAPVK_VK_TO_CHAR = 2, // The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
MAPVK_VSC_TO_VK_EX = 3, // The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
MAPVK_VK_TO_VSC_EX = 4, // The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0.
}
/// <summary>
/// Populates the ArrayLists specifying disallowed hotkeys
/// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc
/// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc.
/// </summary>
private void PopulateModifierLists()
{
// Shift + 0 - 9, A - Z
for (Keys k = Keys.D0; k <= Keys.Z; k++)
{
_needNonShiftModifier.Add((int)k);
needNonShiftModifier.Add((int)k);
}
// Shift + Numpad keys
for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++)
{
_needNonShiftModifier.Add((int)k);
needNonShiftModifier.Add((int)k);
}
// Shift + Misc (,;<./ etc)
for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++)
{
_needNonShiftModifier.Add((int)k);
needNonShiftModifier.Add((int)k);
}
// Shift + Space, PgUp, PgDn, End, Home
for (Keys k = Keys.Space; k <= Keys.Home; k++)
{
_needNonShiftModifier.Add((int)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);
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);
needNonAltGrModifier.Add((int)k);
}
}
/// <summary>
/// Resets this hotkey control to None
/// Resets this hotkey control to None.
/// </summary>
public new void Clear()
{
@ -170,8 +166,8 @@ namespace SystemTrayMenu.UserInterface.Controls
}
else
{
_modifiers = e.Modifiers;
_hotkey = e.KeyCode;
modifiers = e.Modifiers;
hotkey = e.KeyCode;
Redraw();
}
}
@ -185,12 +181,12 @@ namespace SystemTrayMenu.UserInterface.Controls
// Somehow the PrintScreen only comes as a keyup, therefore we handle it here.
if (e.KeyCode == Keys.PrintScreen)
{
_modifiers = e.Modifiers;
_hotkey = e.KeyCode;
modifiers = e.Modifiers;
hotkey = e.KeyCode;
Redraw();
}
if (_hotkey == Keys.None && ModifierKeys == Keys.None)
if (hotkey == Keys.None && ModifierKeys == Keys.None)
{
ResetHotkey();
}
@ -198,7 +194,7 @@ namespace SystemTrayMenu.UserInterface.Controls
/// <summary>
/// Prevents the letter/whatever entered to show up in the TextBox
/// Without this, a "A" key press would appear as "aControl, Alt + A"
/// Without this, a "A" key press would appear as "aControl, Alt + A".
/// </summary>
private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e)
{
@ -206,8 +202,11 @@ namespace SystemTrayMenu.UserInterface.Controls
}
/// <summary>
/// Handles some misc keys, such as Ctrl+Delete and Shift+Insert
/// Handles some misc keys, such as Ctrl+Delete and Shift+Insert.
/// </summary>
/// <param name="msg">msg.</param>
/// <param name="keyData">keyData.</param>
/// <returns>bool if handled.</returns>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete))
@ -227,47 +226,48 @@ namespace SystemTrayMenu.UserInterface.Controls
}
/// <summary>
/// Clears the current hotkey and resets the TextBox
/// Clears the current hotkey and resets the TextBox.
/// </summary>
public void ResetHotkey()
{
_hotkey = Keys.None;
_modifiers = Keys.None;
hotkey = Keys.None;
modifiers = Keys.None;
Redraw();
}
/// <summary>
/// Used to get/set the hotkey (e.g. Keys.A)
/// Gets or sets used to get/set the hotkey (e.g. Keys.A).
/// </summary>
public Keys Hotkey
{
get => _hotkey;
get => hotkey;
set
{
_hotkey = value;
hotkey = value;
Redraw(true);
}
}
/// <summary>
/// Used to get/set the hotkey (e.g. Keys.A)
/// Used to get/set the hotkey (e.g. Keys.A).
/// </summary>
/// <param name="hotkey">hotkey.</param>
public void SetHotkey(string hotkey)
{
_hotkey = HotkeyFromString(hotkey);
_modifiers = HotkeyModifiersFromString(hotkey);
this.hotkey = HotkeyFromString(hotkey);
modifiers = HotkeyModifiersFromString(hotkey);
Redraw(true);
}
/// <summary>
/// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control)
/// Gets or sets used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control).
/// </summary>
public Keys HotkeyModifiers
{
get => _modifiers;
get => modifiers;
set
{
_modifiers = value;
modifiers = value;
Redraw(true);
}
}
@ -279,14 +279,14 @@ namespace SystemTrayMenu.UserInterface.Controls
private void Redraw(bool bCalledProgramatically = false)
{
// No hotkey set
if (_hotkey == Keys.None)
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)
if (hotkey == Keys.LWin || hotkey == Keys.RWin)
{
Text = string.Empty;
return;
@ -296,36 +296,36 @@ namespace SystemTrayMenu.UserInterface.Controls
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.Shift || modifiers == Keys.None) && needNonShiftModifier.Contains((int)hotkey))
{
if (_modifiers == Keys.None)
if (modifiers == Keys.None)
{
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...
if (_needNonAltGrModifier.Contains((int)_hotkey) == false)
if (needNonAltGrModifier.Contains((int)hotkey) == false)
{
_modifiers = Keys.Alt | Keys.Control;
modifiers = Keys.Alt | Keys.Control;
}
else
{
// ... in that case, use Shift+Alt instead.
_modifiers = Keys.Alt | Keys.Shift;
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;
hotkey = Keys.None;
Text = string.Empty;
return;
}
}
// Check all Ctrl+Alt keys
if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int)_hotkey))
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;
hotkey = Keys.None;
Text = string.Empty;
return;
}
@ -333,12 +333,12 @@ namespace SystemTrayMenu.UserInterface.Controls
// 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)
if (hotkey == Keys.Menu /* Alt */ || hotkey == Keys.ShiftKey || hotkey == Keys.ControlKey)
{
_hotkey = Keys.None;
hotkey = Keys.None;
}
Text = HotkeyToLocalizedString(_modifiers, _hotkey);
Text = HotkeyToLocalizedString(modifiers, hotkey);
}
public override string ToString()
@ -384,7 +384,6 @@ namespace SystemTrayMenu.UserInterface.Controls
return hotkeyString.ToString();
}
public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode)
{
return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode);
@ -416,7 +415,6 @@ namespace SystemTrayMenu.UserInterface.Controls
return hotkeyString.ToString();
}
public static Keys HotkeyModifiersFromString(string modifiersString)
{
Keys modifiers = Keys.None;
@ -475,7 +473,7 @@ namespace SystemTrayMenu.UserInterface.Controls
public static void RegisterHotkeyHwnd(IntPtr hWnd)
{
_hotkeyHwnd = hWnd;
hotkeyHwnd = hWnd;
}
public static int RegisterHotKey(string hotkey, HotKeyHandler handler)
@ -484,12 +482,12 @@ namespace SystemTrayMenu.UserInterface.Controls
}
/// <summary>
/// Register a hotkey
/// Register a hotkey.
/// </summary>
/// <param name="modifierKeyCode">The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT</param>
/// <param name="virtualKeyCode">The virtual key code</param>
/// <param name="handler">A HotKeyHandler, this will be called to handle the hotkey press</param>
/// <returns>the hotkey number, -1 if failed</returns>
/// <param name="modifierKeyCode">The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT .</param>
/// <param name="virtualKeyCode">The virtual key code.</param>
/// <param name="handler">A HotKeyHandler, this will be called to handle the hotkey press.</param>
/// <returns>the hotkey number, -1 if failed.</returns>
public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler)
{
if (virtualKeyCode == Keys.None)
@ -524,10 +522,10 @@ namespace SystemTrayMenu.UserInterface.Controls
modifiers |= (uint)Modifiers.NOREPEAT;
}
if (NativeMethods.User32RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint)virtualKeyCode))
if (NativeMethods.User32RegisterHotKey(hotkeyHwnd, hotKeyCounter, modifiers, (uint)virtualKeyCode))
{
KeyHandlers.Add(_hotKeyCounter, handler);
return _hotKeyCounter++;
KeyHandlers.Add(hotKeyCounter, handler);
return hotKeyCounter++;
}
else
{
@ -540,7 +538,7 @@ namespace SystemTrayMenu.UserInterface.Controls
{
foreach (int hotkey in KeyHandlers.Keys)
{
NativeMethods.User32UnregisterHotKey(_hotkeyHwnd, hotkey);
NativeMethods.User32UnregisterHotKey(hotkeyHwnd, hotkey);
}
KeyHandlers.Clear();
@ -553,7 +551,7 @@ namespace SystemTrayMenu.UserInterface.Controls
{
if (availableHotkey == hotkey)
{
NativeMethods.User32UnregisterHotKey(_hotkeyHwnd, hotkey);
NativeMethods.User32UnregisterHotKey(hotkeyHwnd, hotkey);
removeHotkey = true;
}
}
@ -572,7 +570,7 @@ namespace SystemTrayMenu.UserInterface.Controls
/// <returns>true if the message was handled.</returns>
public static bool HandleMessages(ref Message m)
{
if (m.Msg != WM_HOTKEY)
if (m.Msg != WmHotkey)
{
return false;
}
@ -598,6 +596,7 @@ namespace SystemTrayMenu.UserInterface.Controls
Keys virtualKey = givenKey;
string keyString = string.Empty;
// Make VC's to real keys
switch (virtualKey)
{

View file

@ -16,20 +16,21 @@ namespace SystemTrayMenu.UserInterface.Dialogs
private bool isDisposed;
/// <summary>
/// Gets/sets folder in which dialog will be open.
/// Gets or sets /sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets/sets directory in which dialog will be open
/// Gets or sets /sets directory in which dialog will be open
/// if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets selected folder.
/// Gets or sets selected folder.
/// </summary>
public string Folder { get; set; }
public DialogResult ShowDialog()
{
return ShowDialog(owner: new WindowWrapper(IntPtr.Zero));
@ -87,7 +88,8 @@ namespace SystemTrayMenu.UserInterface.Dialogs
{
if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK)
{
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH,
if (shellItem.GetDisplayName(
NativeMethods.SIGDN_FILESYSPATH,
out IntPtr pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
@ -119,7 +121,11 @@ namespace SystemTrayMenu.UserInterface.Dialogs
Filter = "|" + Guid.Empty.ToString(),
FileName = "any",
};
if (InitialFolder != null) { frm.InitialDirectory = InitialFolder; }
if (InitialFolder != null)
{
frm.InitialDirectory = InitialFolder;
}
frm.OverwritePrompt = false;
frm.Title = Translator.GetText("Select Folder");
frm.ValidateNames = false;
@ -155,17 +161,18 @@ namespace SystemTrayMenu.UserInterface.Dialogs
/// <summary>
/// Initializes a new instance of the <see cref="WindowWrapper"/> class.
/// </summary>
/// <param name="handle">Handle to wrap</param>
/// <param name="handle">Handle to wrap.</param>
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
hwnd = handle;
}
/// <summary>
/// Original ptr
/// Gets original ptr.
/// </summary>
public IntPtr Handle => _hwnd;
private readonly IntPtr _hwnd;
public IntPtr Handle => hwnd;
private readonly IntPtr hwnd;
}
internal static class NativeMethods
@ -180,124 +187,102 @@ 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]
[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)]
[ComImport]
[Guid("42F85136-DB7E-439C-85F1-E4075D135FC8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog
{
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig()]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
uint Show([In, Optional] IntPtr hwndOwner);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes,
[In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileTypeIndex([In] uint iFileType);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileTypeIndex(out uint piFileType);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde,
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Advise(
[In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde,
out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Unadvise([In] uint dwCookie);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOptions([In] uint fos);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetOptions(out uint fos);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection
([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace
([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)]
string pszDefaultExtension);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetClientGuid([In] ref Guid guid);
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint ClearClientData();
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
}
[ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem
{
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType = MethodCodeType.Runtime)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint BindToHandler(
[In] IntPtr pbc,
[In] ref Guid rbhid,

View file

@ -9,12 +9,19 @@ namespace SystemTrayMenu.UserInterface.Dialogs
public interface IFolderDialog
{
string InitialFolder { get; set; }
string DefaultFolder { get; set; }
string Folder { get; set; }
DialogResult ShowDialog();
DialogResult ShowDialog(IWin32Window owner);
DialogResult ShowVistaDialog(IWin32Window owner);
DialogResult ShowLegacyDialog(IWin32Window owner);
void Dispose();
}
}

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.UserInterface
{
using System;
using System.Windows.Forms;
/// <summary>
/// Workaround class for "Clipboard" issue on .Net Windows Forms Label (https://github.com/Hofknecht/SystemTrayMenu/issues/5)
/// On Label MouseDoubleClick the framework will copy the title text into the clipboard.
@ -18,10 +19,11 @@ namespace SystemTrayMenu.UserInterface
/// </summary>
public class LabelNoCopy : Label
{
private string _text;
private string text;
public override string Text
{
get => _text;
get => text;
set
{
if (value == null)
@ -29,9 +31,9 @@ namespace SystemTrayMenu.UserInterface
value = string.Empty;
}
if (_text != value)
if (text != value)
{
_text = value;
text = value;
Refresh();
OnTextChanged(EventArgs.Empty);
}

View file

@ -1,4 +1,8 @@
namespace SystemTrayMenu.UserInterface
// <copyright file="Menu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Data;
@ -13,28 +17,7 @@
internal partial class Menu : Form
{
internal new event EventHandlerEmpty MouseWheel;
internal new event EventHandlerEmpty MouseEnter;
internal new event EventHandlerEmpty MouseLeave;
internal event EventHandlerEmpty UserClickedOpenFolder;
internal event EventHandler<Keys> CmdKeyProcessed;
internal event EventHandlerEmpty SearchTextChanging;
internal event EventHandler SearchTextChanged;
internal bool IsUsable => Visible && !fading.IsHiding &&
!IsDisposed && !Disposing;
internal enum MenuType
{
Main,
Sub,
Empty,
NoAccess,
MaxReached,
}
internal int Level = 0;
private readonly Fading fading = new Fading();
private bool isShowing = false;
@ -92,7 +75,8 @@
pictureBoxSearch.Paint += PictureBoxSearch_Paint;
void PictureBoxSearch_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawIcon(Properties.Resources.search2,
e.Graphics.DrawIcon(
Properties.Resources.search2,
new Rectangle(0, 0, pictureBoxSearch.Width, pictureBoxSearch.Height));
}
@ -124,18 +108,45 @@
}
}
internal new event EventHandlerEmpty MouseWheel;
internal new event EventHandlerEmpty MouseEnter;
internal new event EventHandlerEmpty MouseLeave;
internal event EventHandlerEmpty UserClickedOpenFolder;
internal event EventHandler<Keys> CmdKeyProcessed;
internal event EventHandlerEmpty SearchTextChanging;
internal event EventHandler SearchTextChanged;
internal enum MenuType
{
Main,
Sub,
Empty,
NoAccess,
MaxReached,
}
internal bool IsUsable => Visible && !fading.IsHiding &&
!IsDisposed && !Disposing;
internal void FocusTextBox()
{
textBoxSearch.Focus();
}
private static void SetDoubleBuffer(Control ctl, bool DoubleBuffered)
private static void SetDoubleBuffer(Control ctl, bool doubleBuffered)
{
typeof(Control).InvokeMember("DoubleBuffered",
typeof(Control).InvokeMember(
"DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
null,
ctl,
new object[] { DoubleBuffered },
new object[] { doubleBuffered },
CultureInfo.InvariantCulture);
}
@ -445,11 +456,6 @@
MouseWheel?.Invoke();
}
internal void SetTitleColorDeactive()
{
labelTitle.ForeColor = Color.LightGray;
}
internal void SetTitleColorActive()
{
labelTitle.ForeColor = Color.Black;
@ -477,9 +483,9 @@
{
get
{
CreateParams Params = base.CreateParams;
Params.ExStyle |= 0x80;
return Params;
CreateParams createparams = base.CreateParams;
createparams.ExStyle |= 0x80;
return createparams;
}
}

View file

@ -1,5 +1,5 @@
// <copyright file="SettingsForm.cs" company="TAMAHO">
// Copyright (c) TAMAHO. All rights reserved.
// <copyright file="SettingsForm.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
@ -18,8 +18,9 @@ namespace SystemTrayMenu.UserInterface
public partial class SettingsForm : Form
{
public string NewHotKey => newHotKey;
private readonly string newHotKey = string.Empty;
private bool _inHotkey = false;
private bool inHotkey = false;
public SettingsForm()
{
@ -56,7 +57,6 @@ namespace SystemTrayMenu.UserInterface
void InitializeHotkey()
{
textBoxHotkey.SetHotkey(Properties.Settings.Default.HotKey);
//textBoxHotkey.Text = Properties.Settings.Default.HotKey;
}
InitializeLanguage();
@ -102,7 +102,8 @@ namespace SystemTrayMenu.UserInterface
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
key.SetValue(Assembly.GetExecutingAssembly().GetName().Name,
key.SetValue(
Assembly.GetExecutingAssembly().GetName().Name,
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
Properties.Settings.Default.IsAutostartActivated = true;
}
@ -120,12 +121,6 @@ namespace SystemTrayMenu.UserInterface
Properties.Settings.Default.HotKey =
new KeysConverter().ConvertToInvariantString(
textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers);
//Keys keys1 = HotkeyControl.Hotkey;
// Hotkey
// Keys keys = HotkeyControl.ModifierKeys;
//Keys keys2 = HotkeyControl.HotkeyToString(keys, keys);
}
private void SetLanguage()
@ -150,7 +145,7 @@ namespace SystemTrayMenu.UserInterface
private void TextBoxHotkeyEnter(object sender, EventArgs e)
{
HotkeyControl.UnregisterHotkeys();
_inHotkey = true;
inHotkey = true;
}
private void TextBoxHotkey_Leave(object sender, EventArgs e)
@ -159,8 +154,7 @@ namespace SystemTrayMenu.UserInterface
new KeysConverter().ConvertToInvariantString(
textBoxHotkey.Hotkey | textBoxHotkey.HotkeyModifiers);
RegisterHotkeys();
//MainForm.RegisterHotkeys();
_inHotkey = false;
inHotkey = false;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
@ -168,7 +162,7 @@ namespace SystemTrayMenu.UserInterface
switch (keyData)
{
case Keys.Escape:
if (!_inHotkey)
if (!inHotkey)
{
DialogResult = DialogResult.Cancel;
}
@ -186,13 +180,12 @@ namespace SystemTrayMenu.UserInterface
}
/// <summary>
/// Helper method to cleanly register a hotkey
/// Helper method to cleanly register a hotkey.
/// </summary>
/// <param name="failedKeys"></param>
/// <param name="functionName"></param>
/// <param name="hotkeyString"></param>
/// <param name="handler"></param>
/// <returns></returns>
/// <param name="failedKeys">failedKeys.</param>
/// <param name="hotkeyString">hotkeyString.</param>
/// <param name="handler">handler.</param>
/// <returns>bool success.</returns>
private static bool RegisterHotkey(StringBuilder failedKeys, string hotkeyString, HotKeyHandler handler)
{
Keys modifierKeyCode = HotkeyControl.HotkeyModifiersFromString(hotkeyString);
@ -216,34 +209,11 @@ namespace SystemTrayMenu.UserInterface
private static bool RegisterWrapper(StringBuilder failedKeys, HotKeyHandler handler)
{
//IniValue hotkeyValue = _conf.Values[configurationKey];
//try
//{
bool success = RegisterHotkey(failedKeys,
//hotkeyValue.Value.ToString(),
bool success = RegisterHotkey(
failedKeys,
Properties.Settings.Default.HotKey,
handler);
//if (!success && ignoreFailedRegistration)
//{
// //LOG.DebugFormat("Ignoring failed hotkey registration for {0}, with value '{1}', resetting to 'None'.", functionName, hotkeyValue);
// //_conf.Values[configurationKey].Value = Keys.None.ToString();
// //_conf.IsDirty = true;
//}
return success;
//}
//catch (Exception)
//{
// //LOG.Warn(ex);
// //LOG.WarnFormat("Restoring default hotkey for {0}, stored under {1} from '{2}' to '{3}'", functionName, configurationKey, hotkeyValue.Value, hotkeyValue.Attributes.DefaultValue);
// // when getting an exception the key wasn't found: reset the hotkey value
// //hotkeyValue.UseValueOrDefault(null);
// //hotkeyValue.ContainingIniSection.IsDirty = true;
// return RegisterHotkey(failedKeys,
// //hotkeyValue.Value.ToString(),
// Properties.Settings.Default.HotKey,
// handler);
//}
}
/// <summary>
@ -258,14 +228,14 @@ namespace SystemTrayMenu.UserInterface
/// <summary>
/// Registers all hotkeys as configured, displaying a dialog in case of hotkey conflicts with other tools.
/// </summary>
/// <param name="ignoreFailedRegistration">if true, a failed hotkey registration will not be reported to the user - the hotkey will simply not be registered</param>
/// <param name="ignoreFailedRegistration">if true, a failed hotkey registration will not be reported to the user - the hotkey will simply not be registered.</param>
/// <returns>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).</returns>
private static bool RegisterHotkeys(bool ignoreFailedRegistration)
{
//if (_instance == null)
//{
// if (_instance == null)
// {
// return false;
//}
// }
bool success = true;
StringBuilder failedKeys = new StringBuilder();
if (!RegisterWrapper(failedKeys, Handler))
@ -292,8 +262,8 @@ namespace SystemTrayMenu.UserInterface
///// Check if OneDrive is blocking hotkeys
///// </summary>
///// <returns>true if onedrive has hotkeys turned on</returns>
//private static bool IsOneDriveBlockingHotkey()
//{
// private static bool IsOneDriveBlockingHotkey()
// {
// if (!Environment.OSVersion.IsWindows10())
// {
// return false;
@ -311,16 +281,16 @@ namespace SystemTrayMenu.UserInterface
// }
// var screenshotSetting = File.ReadAllLines(oneDriveSettingsFile).Skip(1).Take(1).First();
// return "2".Equals(screenshotSetting);
//}
// }
/// <summary>
/// Displays a dialog for the user to choose how to handle hotkey registration failures:
/// retry (allowing to shut down the conflicting application before),
/// ignore (not registering the conflicting hotkey and resetting the respective config to "None", i.e. not trying to register it again on next startup)
/// abort (do nothing about it)
/// abort (do nothing about it).
/// </summary>
/// <param name="failedKeys">comma separated list of the hotkeys that could not be registered, for display in dialog text</param>
/// <returns></returns>
/// <param name="failedKeys">comma separated list of the hotkeys that could not be registered, for display in dialog text.</param>
/// <returns>bool success.</returns>
private static bool HandleFailedHotkeyRegistration(string failedKeys)
{
bool success = false;
@ -329,13 +299,13 @@ namespace SystemTrayMenu.UserInterface
DialogResult dr = MessageBox.Show(message, warningTitle, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Exclamation);
if (dr == DialogResult.Retry)
{
//LOG.DebugFormat("Re-trying to register hotkeys");
// LOG.DebugFormat("Re-trying to register hotkeys");
HotkeyControl.UnregisterHotkeys();
success = RegisterHotkeys(false);
}
else if (dr == DialogResult.Ignore)
{
//LOG.DebugFormat("Ignoring failed hotkey registration");
// LOG.DebugFormat("Ignoring failed hotkey registration");
HotkeyControl.UnregisterHotkeys();
success = RegisterHotkeys(true);
}
@ -347,6 +317,7 @@ namespace SystemTrayMenu.UserInterface
public class Language
{
public string Name { get; set; }
public string Value { get; set; }
}
}

View file

@ -1,4 +1,8 @@
namespace SystemTrayMenu.Utilities
// <copyright file="ShellContextMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Drawing;
@ -25,15 +29,37 @@
/// Andreas Johansson
/// afjohansson@hotmail.com
/// http://afjohansson.spaces.live.com
/// .
/// </summary>
/// <example>
/// ShellContextMenu scm = new ShellContextMenu();
/// FileInfo[] files = new FileInfo[1];
/// files[0] = new FileInfo(@"c:\windows\notepad.exe");
/// scm.ShowContextMenu(this.Handle, files, Cursor.Position);
/// scm.ShowContextMenu(this.Handle, files, Cursor.Position);.
/// </example>
public class ShellContextMenu : NativeWindow
{
private const int MaxPath = 260;
private const uint CmdFirst = 1;
private const uint CmdLast = 30000;
private const int ResultOK = 0;
private static readonly int CbMenuItemInfo = Marshal.SizeOf(typeof(MENUITEMINFO));
private static readonly int CbInvokeCommand = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
private static Guid iidIShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
private static Guid iidIContextMenu = new Guid("{000214e4-0000-0000-c000-000000000046}");
private static Guid iidIContextMenu2 = new Guid("{000214f4-0000-0000-c000-000000000046}");
private static Guid iidIContextMenu3 = new Guid("{bcfce0a0-ec17-11d0-8d10-00a0c90f2719}");
private IContextMenu oContextMenu;
private IContextMenu2 oContextMenu2;
private IContextMenu3 oContextMenu3;
private IShellFolder oDesktopFolder;
private IShellFolder oParentFolder;
private IntPtr[] arrPIDLs;
private string strParentFolder;
/// <summary>
/// Initializes a new instance of the <see cref="ShellContextMenu"/> class.
/// </summary>
@ -50,23 +76,23 @@
ReleaseAll();
}
/// <summary>Gets the interfaces to the context menu</summary>
/// <param name="oParentFolder">Parent folder</param>
/// <param name="arrPIDLs">PIDLs</param>
/// <returns>true if it got the interfaces, otherwise false</returns>
/// <summary>Gets the interfaces to the context menu.</summary>
/// <param name="oParentFolder">Parent folder.</param>
/// <param name="arrPIDLs">PIDLs.</param>
/// <returns>true if it got the interfaces, otherwise false.</returns>
private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr)
{
int nResult = oParentFolder.GetUIObjectOf(
IntPtr.Zero,
(uint)arrPIDLs.Length,
arrPIDLs,
ref IID_IContextMenu,
ref iidIContextMenu,
IntPtr.Zero,
out ctxMenuPtr);
if (S_OK == nResult)
if (nResult == ResultOK)
{
_oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu));
oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu));
/*IntPtr pUnknownContextMenu2 = IntPtr.Zero;
if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu2, out pUnknownContextMenu2))
@ -84,7 +110,7 @@
else
{
ctxMenuPtr = IntPtr.Zero;
_oContextMenu = null;
oContextMenu = null;
return false;
}
}
@ -94,34 +120,33 @@
/// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover
/// method of Browser when hovering over a ContextMenu item.
/// </summary>
/// <param name="m">the Message of the Browser's WndProc</param>
/// <returns>true if the message has been handled, false otherwise</returns>
/// <param name="m">the Message of the Browser's WndProc.</param>
protected override void WndProc(ref Message m)
{
if (_oContextMenu != null &&
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 &&
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) == S_OK)
if (oContextMenu2.HandleMenuMsg(
(uint)m.Msg, m.WParam, m.LParam) == ResultOK)
{
return;
}
}
if (_oContextMenu3 != null &&
if (oContextMenu3 != null &&
m.Msg == (int)WM.MENUCHAR)
{
if (_oContextMenu3.HandleMenuMsg2(
(uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == S_OK)
if (oContextMenu3.HandleMenuMsg2(
(uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == ResultOK)
{
return;
}
@ -134,16 +159,16 @@
{
CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX
{
cbSize = cbInvokeCommand,
lpVerb = (IntPtr)(nCmd - CMD_FIRST),
lpDirectory = strFolder,
lpVerbW = (IntPtr)(nCmd - CMD_FIRST),
lpDirectoryW = strFolder,
fMask = CMIC.UNICODE | CMIC.PTINVOKE |
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,
PtInvoke = new POINT(pointInvoke.X, pointInvoke.Y),
NShow = SW.SHOWNORMAL,
};
_ = contextMenu.InvokeCommand(ref invoke);
@ -154,77 +179,77 @@
/// </summary>
private void ReleaseAll()
{
if (_oContextMenu != null)
if (oContextMenu != null)
{
Marshal.ReleaseComObject(_oContextMenu);
_oContextMenu = null;
Marshal.ReleaseComObject(oContextMenu);
oContextMenu = null;
}
if (_oContextMenu2 != null)
if (oContextMenu2 != null)
{
Marshal.ReleaseComObject(_oContextMenu2);
_oContextMenu2 = null;
Marshal.ReleaseComObject(oContextMenu2);
oContextMenu2 = null;
}
if (_oContextMenu3 != null)
if (oContextMenu3 != null)
{
Marshal.ReleaseComObject(_oContextMenu3);
_oContextMenu3 = null;
Marshal.ReleaseComObject(oContextMenu3);
oContextMenu3 = null;
}
if (_oDesktopFolder != null)
if (oDesktopFolder != null)
{
Marshal.ReleaseComObject(_oDesktopFolder);
_oDesktopFolder = null;
Marshal.ReleaseComObject(oDesktopFolder);
oDesktopFolder = null;
}
if (_oParentFolder != null)
if (oParentFolder != null)
{
Marshal.ReleaseComObject(_oParentFolder);
_oParentFolder = null;
Marshal.ReleaseComObject(oParentFolder);
oParentFolder = null;
}
if (_arrPIDLs != null)
if (arrPIDLs != null)
{
FreePIDLs(_arrPIDLs);
_arrPIDLs = null;
FreePIDLs(arrPIDLs);
arrPIDLs = null;
}
}
/// <summary>
/// Gets the desktop folder
/// Gets the desktop folder.
/// </summary>
/// <returns>IShellFolder for desktop folder</returns>
/// <returns>IShellFolder for desktop folder.</returns>
private IShellFolder GetDesktopFolder()
{
if (null == _oDesktopFolder)
if (oDesktopFolder == null)
{
// Get desktop IShellFolder
int nResult = DllImports.NativeMethods.Shell32SHGetDesktopFolder(out IntPtr pUnkownDesktopFolder);
if (S_OK != nResult)
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));
oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder));
}
return _oDesktopFolder;
return oDesktopFolder;
}
/// <summary>
/// Gets the parent folder
/// Gets the parent folder.
/// </summary>
/// <param name="folderName">Folder path</param>
/// <returns>IShellFolder for the folder (relative from the desktop)</returns>
/// <param name="folderName">Folder path.</param>
/// <returns>IShellFolder for the folder (relative from the desktop).</returns>
private IShellFolder GetParentFolder(string folderName)
{
if (null == _oParentFolder)
if (oParentFolder == null)
{
IShellFolder oDesktopFolder = GetDesktopFolder();
if (null == oDesktopFolder)
if (oDesktopFolder == null)
{
return null;
}
@ -233,48 +258,49 @@
uint pchEaten = 0;
SFGAO pdwAttributes = 0;
int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out IntPtr pPIDL, ref pdwAttributes);
if (S_OK != nResult)
if (nResult != ResultOK)
{
return null;
}
IntPtr pStrRet = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4);
IntPtr pStrRet = Marshal.AllocCoTaskMem((MaxPath * 2) + 4);
Marshal.WriteInt32(pStrRet, 0, 0);
_ = _oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet);
StringBuilder strFolder = new StringBuilder(MAX_PATH);
_ = DllImports.NativeMethods.ShlwapiStrRetToBuf(pStrRet, pPIDL, strFolder, MAX_PATH);
_ = 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();
strParentFolder = strFolder.ToString();
// Get the IShellFolder for folder
nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref IID_IShellFolder, out IntPtr pUnknownParentFolder);
nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref iidIShellFolder, out IntPtr pUnknownParentFolder);
// Free the PIDL first
Marshal.FreeCoTaskMem(pPIDL);
if (S_OK != nResult)
if (nResult != ResultOK)
{
return null;
}
_oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder));
oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder));
}
return _oParentFolder;
return oParentFolder;
}
/// <summary>
/// Get the PIDLs
/// Get the PIDLs.
/// </summary>
/// <param name="arrFI">Array of FileInfo</param>
/// <returns>Array of PIDLs</returns>
/// <param name="arrFI">Array of FileInfo.</param>
/// <returns>Array of PIDLs.</returns>
protected IntPtr[] GetPIDLs(FileInfo[] arrFI)
{
if (null == arrFI || 0 == arrFI.Length)
if (arrFI == null || arrFI.Length == 0)
{
return null;
}
IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName);
if (null == oParentFolder)
if (oParentFolder == null)
{
return null;
}
@ -288,7 +314,7 @@
SFGAO pdwAttributes = 0;
IntPtr pPIDL = IntPtr.Zero;
int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
if (S_OK != nResult)
if (nResult != ResultOK)
{
FreePIDLs(arrPIDLs);
return null;
@ -302,19 +328,19 @@
}
/// <summary>
/// Get the PIDLs
/// Get the PIDLs.
/// </summary>
/// <param name="arrFI">Array of DirectoryInfo</param>
/// <returns>Array of PIDLs</returns>
/// <param name="arrFI">Array of DirectoryInfo.</param>
/// <returns>Array of PIDLs.</returns>
protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI)
{
if (null == arrFI || 0 == arrFI.Length || arrFI[0].Parent == null)
if (arrFI == null || arrFI.Length == 0 || arrFI[0].Parent == null)
{
return null;
}
IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName);
if (null == oParentFolder)
if (oParentFolder == null)
{
return null;
}
@ -328,7 +354,7 @@
SFGAO pdwAttributes = 0;
IntPtr pPIDL = IntPtr.Zero;
int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
if (S_OK != nResult)
if (nResult != ResultOK)
{
FreePIDLs(arrPIDLs);
return null;
@ -342,9 +368,9 @@
}
/// <summary>
/// Free the PIDLs
/// Free the PIDLs.
/// </summary>
/// <param name="arrPIDLs">Array of PIDLs (IntPtr)</param>
/// <param name="arrPIDLs">Array of PIDLs (IntPtr).</param>
protected static void FreePIDLs(IntPtr[] arrPIDLs)
{
if (arrPIDLs != null)
@ -361,54 +387,51 @@
}
/// <summary>
/// Shows the context menu
/// Shows the context menu.
/// </summary>
/// <param name="files">FileInfos (should all be in same directory)</param>
/// <param name="pointScreen">Where to show the menu</param>
/// <param name="files">FileInfos (should all be in same directory).</param>
/// <param name="pointScreen">Where to show the menu.</param>
public void ShowContextMenu(FileInfo[] files, Point pointScreen)
{
// Release all resources first.
ReleaseAll();
_arrPIDLs = GetPIDLs(files);
arrPIDLs = GetPIDLs(files);
ShowContextMenu(pointScreen);
}
/// <summary>
/// Shows the context menu
/// Shows the context menu.
/// </summary>
/// <param name="dirs">DirectoryInfos (should all be in same directory)</param>
/// <param name="pointScreen">Where to show the menu</param>
/// <param name="dirs">DirectoryInfos (should all be in same directory).</param>
/// <param name="pointScreen">Where to show the menu.</param>
public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen)
{
// Release all resources first.
ReleaseAll();
_arrPIDLs = GetPIDLs(dirs);
arrPIDLs = GetPIDLs(dirs);
ShowContextMenu(pointScreen);
}
/// <summary>
/// Shows the context menu
/// Shows the context menu.
/// </summary>
/// <param name="arrFI">FileInfos (should all be in same directory)</param>
/// <param name="pointScreen">Where to show the menu</param>
/// <param name="pointScreen">Where to show the menu.</param>
public void ShowContextMenu(Point pointScreen)
{
IntPtr pMenu = IntPtr.Zero,
iContextMenuPtr = IntPtr.Zero,
iContextMenuPtr2 = IntPtr.Zero,
iContextMenuPtr3 = IntPtr.Zero;
//LocalWindowsHook hook = new LocalWindowsHook(HookType.WH_CALLWNDPROC);
//hook.HookInvoked += new LocalWindowsHook.HookEventHandler(WindowsHookInvoked);
try
{
if (_arrPIDLs == null)
if (arrPIDLs == null)
{
ReleaseAll();
return;
}
if (!GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr))
if (!GetContextMenuInterfaces(oParentFolder, arrPIDLs, out iContextMenuPtr))
{
ReleaseAll();
return;
@ -416,18 +439,18 @@
pMenu = DllImports.NativeMethods.User32CreatePopupMenu();
int nResult = _oContextMenu.QueryContextMenu(
int nResult = oContextMenu.QueryContextMenu(
pMenu,
0,
CMD_FIRST,
CMD_LAST,
CmdFirst,
CmdLast,
CMF.EXPLORE | CMF.NORMAL | ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0));
Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu2, out iContextMenuPtr2);
Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu3, out iContextMenuPtr3);
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));
oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2));
oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3));
uint nSelected = DllImports.NativeMethods.User32TrackPopupMenuEx(
pMenu,
@ -442,7 +465,7 @@
if (nSelected != 0)
{
InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen);
InvokeCommand(oContextMenu, nSelected, strParentFolder, pointScreen);
}
}
catch
@ -475,71 +498,63 @@
}
}
private IContextMenu _oContextMenu;
private IContextMenu2 _oContextMenu2;
private IContextMenu3 _oContextMenu3;
private IShellFolder _oDesktopFolder;
private IShellFolder _oParentFolder;
private IntPtr[] _arrPIDLs;
private string _strParentFolder;
private const int MAX_PATH = 260;
private const uint CMD_FIRST = 1;
private const uint CMD_LAST = 30000;
private const int S_OK = 0;
private static readonly int cbMenuItemInfo = Marshal.SizeOf(typeof(MENUITEMINFO));
private static readonly int cbInvokeCommand = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
private static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
private static Guid IID_IContextMenu = new Guid("{000214e4-0000-0000-c000-000000000046}");
private static Guid IID_IContextMenu2 = new Guid("{000214f4-0000-0000-c000-000000000046}");
private static Guid IID_IContextMenu3 = new Guid("{bcfce0a0-ec17-11d0-8d10-00a0c90f2719}");
[StructLayout(LayoutKind.Sequential)]
private struct CWPSTRUCT
{
public IntPtr lparam;
public IntPtr wparam;
public int message;
public IntPtr hwnd;
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;
public int CbSize;
public CMIC FMask;
public IntPtr Hwnd;
public IntPtr LpVerb;
[MarshalAs(UnmanagedType.LPStr)]
public string lpParameters;
public string LpParameters;
[MarshalAs(UnmanagedType.LPStr)]
public string lpDirectory;
public SW nShow;
public int dwHotKey;
public IntPtr hIcon;
public string LpDirectory;
public SW NShow;
public int DwHotKey;
public IntPtr HIcon;
[MarshalAs(UnmanagedType.LPStr)]
public string lpTitle;
public IntPtr lpVerbW;
public string LpTitle;
public IntPtr LpVerbW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpParametersW;
public string LpParametersW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpDirectoryW;
public string LpDirectoryW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpTitleW;
public POINT ptInvoke;
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;
cbSize = CbMenuItemInfo;
dwTypeData = text;
cch = text.Length;
fMask = 0;
@ -552,50 +567,6 @@
dwItemData = IntPtr.Zero;
hbmpItem = IntPtr.Zero;
}
public int cbSize;
public MIIM fMask;
public MFT fType;
public MFS fState;
public uint wID;
public IntPtr hSubMenu;
public IntPtr hbmpChecked;
public IntPtr hbmpUnchecked;
public IntPtr dwItemData;
[MarshalAs(UnmanagedType.LPTStr)]
public string dwTypeData;
public int cch;
public IntPtr hbmpItem;
}
// 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)
{
this.x = x;
this.y = y;
}
public int x;
public int y;
}
// Defines the values used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf
@ -691,7 +662,7 @@
// The cmd for a custom added menu item
private enum CMD_CUSTOM
{
ExpandCollapse = (int)CMD_LAST + 1,
ExpandCollapse = (int)CmdLast + 1,
}
// Flags used with the CMINVOKECOMMANDINFOEX structure
@ -814,8 +785,7 @@
INITMENUPOPUP = 0x117,
INPUTLANGCHANGE = 0x51,
INPUTLANGCHANGEREQUEST = 0x50,
KEYDOWN = 0x100,
//KEYFIRST = 0x100,
KEYDOWN = 0x100, // KEYFIRST = 0x100,
KEYLAST = 0x108,
KEYUP = 0x101,
KILLFOCUS = 0x8,
@ -847,12 +817,10 @@
MENURBUTTONUP = 0x122,
MENUSELECT = 0x11F,
MOUSEACTIVATE = 0x21,
MOUSEFIRST = 0x200,
MOUSEFIRST = 0x200, // MOUSEMOVE = 0x200,
MOUSEHOVER = 0x2A1,
MOUSELAST = 0x20A,
MOUSELAST = 0x20A, // MOUSEWHEEL = 0x20A,
MOUSELEAVE = 0x2A3,
//MOUSEMOVE = 0x200,
//MOUSEWHEEL = 0x20A,
MOVE = 0x3,
MOVING = 0x216,
NCACTIVATE = 0x86,
@ -909,7 +877,7 @@
SETMARGINS = 0xD3,
SETREDRAW = 0xB,
SETTEXT = 0xC,
SETTINGCHANGE = 0x1A,
SETTINGCHANGE = 0x1A, // WININICHANGE = 0x1A,
SHOWWINDOW = 0x18,
SIZE = 0x5,
SIZECLIPBOARD = 0x30B,
@ -938,7 +906,6 @@
VSCROLLCLIPBOARD = 0x30A,
WINDOWPOSCHANGED = 0x47,
WINDOWPOSCHANGING = 0x46,
//WININICHANGE = 0x1A,
SH_NOTIFY = 0x0401,
}
@ -946,8 +913,7 @@
[Flags]
private enum MFT : uint
{
GRAYED = 0x00000003,
//DISABLED = 0x00000003,
GRAYED = 0x00000003, // DISABLED = 0x00000003,
CHECKED = 0x00000008,
SEPARATOR = 0x00000800,
RADIOCHECK = 0x00000200,
@ -965,13 +931,10 @@
[Flags]
private enum MFS : uint
{
GRAYED = 0x00000003,
//DISABLED = 0x00000003,
GRAYED = 0x00000003, // DISABLED = 0x00000003,
CHECKED = 0x00000008,
HILITE = 0x00000080,
ENABLED = 0x00000000,
//UNCHECKED = 0x00000000,
//UNHILITE = 0x00000000,
ENABLED = 0x00000000, // UNCHECKED = 0x00000000, // UNHILITE = 0x00000000,
DEFAULT = 0x00001000,
}
@ -1004,6 +967,36 @@
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")]
@ -1015,8 +1008,7 @@
int ParseDisplayName(
IntPtr hwnd,
IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)]
string pszDisplayName,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
ref uint pchEaten,
out IntPtr ppidl,
ref SFGAO pdwAttributes);
@ -1078,8 +1070,7 @@
[PreserveSig]
int GetAttributesOf(
uint cidl,
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] apidl,
[MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
ref SFGAO rgfInOut);
// Retrieves an OLE interface that can be used to carry out actions on the
@ -1089,15 +1080,14 @@
int GetUIObjectOf(
IntPtr hwndOwner,
uint cidl,
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] apidl,
[MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
ref Guid riid,
IntPtr rgfReserved,
out IntPtr ppv);
// Retrieves the display name for the specified file object or subfolder.
// Return value: error code, if any
[PreserveSig()]
[PreserveSig]
int GetDisplayNameOf(
IntPtr pidl,
SHGNO uFlags,
@ -1110,19 +1100,18 @@
int SetNameOf(
IntPtr hwnd,
IntPtr pidl,
[MarshalAs(UnmanagedType.LPWStr)]
string pszName,
[MarshalAs(UnmanagedType.LPWStr)] string pszName,
SHGNO uFlags,
out IntPtr ppidlOut);
}
[ComImport()]
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[GuidAttribute("000214e4-0000-0000-c000-000000000046")]
private interface IContextMenu
{
// Adds commands to a shortcut menu
[PreserveSig()]
[PreserveSig]
int QueryContextMenu(
IntPtr hmenu,
uint iMenu,
@ -1131,29 +1120,29 @@
CMF uFlags);
// Carries out the command associated with a shortcut menu item
[PreserveSig()]
[PreserveSig]
int InvokeCommand(
ref CMINVOKECOMMANDINFOEX info);
// Retrieves information about a shortcut menu command,
// including the help string and the language-independent,
// or canonical, name for the command
[PreserveSig()]
[PreserveSig]
int GetCommandString(
uint idcmd,
GCS uflags,
uint reserved,
[MarshalAs(UnmanagedType.LPArray)]
byte[] commandstring,
[MarshalAs(UnmanagedType.LPArray)] byte[] commandstring,
int cch);
}
[ComImport, Guid("000214f4-0000-0000-c000-000000000046")]
[ComImport]
[Guid("000214f4-0000-0000-c000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IContextMenu2
{
// Adds commands to a shortcut menu
[PreserveSig()]
[PreserveSig]
int QueryContextMenu(
IntPtr hmenu,
uint iMenu,
@ -1162,20 +1151,19 @@
CMF uFlags);
// Carries out the command associated with a shortcut menu item
[PreserveSig()]
[PreserveSig]
int InvokeCommand(
ref CMINVOKECOMMANDINFOEX info);
// Retrieves information about a shortcut menu command,
// including the help string and the language-independent,
// or canonical, name for the command
[PreserveSig()]
[PreserveSig]
int GetCommandString(
uint idcmd,
GCS uflags,
uint reserved,
[MarshalAs(UnmanagedType.LPWStr)]
StringBuilder commandstring,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder commandstring,
int cch);
// Allows client objects of the IContextMenu interface to
@ -1187,12 +1175,13 @@
IntPtr lParam);
}
[ComImport, Guid("bcfce0a0-ec17-11d0-8d10-00a0c90f2719")]
[ComImport]
[Guid("bcfce0a0-ec17-11d0-8d10-00a0c90f2719")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IContextMenu3
{
// Adds commands to a shortcut menu
[PreserveSig()]
[PreserveSig]
int QueryContextMenu(
IntPtr hmenu,
uint iMenu,
@ -1201,20 +1190,19 @@
CMF uFlags);
// Carries out the command associated with a shortcut menu item
[PreserveSig()]
[PreserveSig]
int InvokeCommand(
ref CMINVOKECOMMANDINFOEX info);
// Retrieves information about a shortcut menu command,
// including the help string and the language-independent,
// or canonical, name for the command
[PreserveSig()]
[PreserveSig]
int GetCommandString(
uint idcmd,
GCS uflags,
uint reserved,
[MarshalAs(UnmanagedType.LPWStr)]
StringBuilder commandstring,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder commandstring,
int cch);
// Allows client objects of the IContextMenu interface to

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.Helper
{
using System;
using System.Runtime.Serialization;
[Serializable]
public class ShellContextMenuException : Exception
{
@ -27,12 +28,10 @@ namespace SystemTrayMenu.Helper
}
protected ShellContextMenuException(
SerializationInfo info,
StreamingContext context)
SerializationInfo info, StreamingContext context)
: base(info, context)
{
// Implement type-specific serialization constructor logic.
}
}
}

View file

@ -5,13 +5,14 @@
namespace SystemTrayMenu.Helper
{
using System;
internal static class ShellHelper
{
/// <summary>
/// Retrieves the High Word of a WParam of a WindowMessage
/// Retrieves the High Word of a WParam of a WindowMessage.
/// </summary>
/// <param name="ptr">The pointer to the WParam</param>
/// <returns>The unsigned integer for the High Word</returns>
/// <param name="ptr">The pointer to the WParam.</param>
/// <returns>The unsigned integer for the High Word.</returns>
public static uint HiWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL);
@ -26,10 +27,10 @@ namespace SystemTrayMenu.Helper
}
/// <summary>
/// Retrieves the Low Word of a WParam of a WindowMessage
/// Retrieves the Low Word of a WParam of a WindowMessage.
/// </summary>
/// <param name="ptr">The pointer to the WParam</param>
/// <returns>The unsigned integer for the Low Word</returns>
/// <param name="ptr">The pointer to the WParam.</param>
/// <returns>The unsigned integer for the Low Word.</returns>
public static uint LoWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL);

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.UserInterface
{
using System.Drawing;
using System.Windows.Forms;
public partial class TaskbarForm : Form
{
public TaskbarForm()
@ -22,8 +23,9 @@ namespace SystemTrayMenu.UserInterface
private void SetLocation()
{
Screen screen = Screen.PrimaryScreen;
Location = new Point(screen.Bounds.Right - Size.Width,
screen.Bounds.Bottom + 80); //Hide below taskbar
Location = new Point(
screen.Bounds.Right - Size.Width,
screen.Bounds.Bottom + 80); // Hide below taskbar
}
}
}

View file

@ -8,6 +8,7 @@ namespace SystemTrayMenu.Utilities
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
internal class AppRestart
{
public static event EventHandlerEmpty BeforeRestarting;

View file

@ -12,9 +12,9 @@ namespace SystemTrayMenu.Utilities
internal static class DataGridViewExtensions
{
/// <summary>
/// dgv.AutoResizeColumns() was too slow ~45ms
/// dgv.AutoResizeColumns() was too slow ~45ms.
/// </summary>
/// <param name="dgv"></param>
/// <param name="dgv">datagridview.</param>
internal static void FastAutoSizeColumns(this DataGridView dgv)
{
System.Collections.Generic.IEnumerable<DataGridViewRow> rows =
@ -27,8 +27,8 @@ namespace SystemTrayMenu.Utilities
{
float checkWidth = gfx.MeasureString(
row.Cells[i].Value.ToString() + "_",
dgv.RowTemplate.DefaultCellStyle.Font
).Width * Scaling.Factor;
dgv.RowTemplate.DefaultCellStyle.Font)
.Width * Scaling.Factor;
if (checkWidth > widthMax)
{
widthMax = checkWidth;
@ -47,7 +47,7 @@ namespace SystemTrayMenu.Utilities
float width0 = gfx.MeasureString(
stringWithWidthLikeIcon,
#pragma warning restore CA1303 // Do not pass literals as localized parameters
dgv.RowTemplate.DefaultCellStyle.Font).Width * Scaling.Factor;
dgv.RowTemplate.DefaultCellStyle.Font).Width * Scaling.Factor;
dgv.Columns[0].Width = (int)width0;
}
}

View file

@ -1,4 +1,8 @@
namespace SystemTrayMenu.Utilities
// <copyright file="EventHandlerEmpty.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
public delegate void EventHandlerEmpty();
}

View file

@ -7,9 +7,11 @@ namespace SystemTrayMenu.Utilities
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class FileIni
{
private readonly Dictionary<string, string> values;
public FileIni(string path)
{
values = File.ReadLines(path)

View file

@ -1,4 +1,8 @@
namespace SystemTrayMenu.Utilities
// <copyright file="FileLnk.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using Shell32;
using System;
@ -30,7 +34,6 @@
return resolvedFilename;
}
private static string GetShortcutFileNamePath(object shortcutFilename)
{
string resolvedFilename = string.Empty;

View file

@ -9,6 +9,7 @@ namespace SystemTrayMenu.Utilities
public static class FileUrl
{
private static string browserPath = string.Empty;
public static string GetDefaultBrowserPath()
{
string urlAssociation = @"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http";
@ -19,16 +20,16 @@ namespace SystemTrayMenu.Utilities
if (string.IsNullOrEmpty(browserPath))
{
//Read default browser path from userChoiceLKey
// Read default browser path from userChoiceLKey
userChoiceKey = Registry.CurrentUser.OpenSubKey(urlAssociation + @"\UserChoice", false);
//If user choice was not found, try machine default
// If user choice was not found, try machine default
if (userChoiceKey == null)
{
//Read default browser path from Win XP registry key
// Read default browser path from Win XP registry key
RegistryKey browserKey = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command", false);
//If browser path wasnt found, try Win Vista (and newer) registry key
// If browser path wasnt found, try Win Vista (and newer) registry key
if (browserKey == null)
{
browserKey =

View file

@ -23,8 +23,9 @@ namespace SystemTrayMenu.Utilities
/// </example>
public static class IconReader
{
private static readonly ConcurrentDictionary<string, Icon> dictIconCache = new ConcurrentDictionary<string, Icon>();
private static readonly object readIcon = new object();
private static readonly ConcurrentDictionary<string, Icon> DictIconCache = new ConcurrentDictionary<string, Icon>();
private static readonly object ReadIcon = new object();
public enum IconSize
{
Large = 0, // 32x32 pixels
@ -39,7 +40,7 @@ namespace SystemTrayMenu.Utilities
public static void Dispose()
{
foreach (Icon icon in dictIconCache.Values)
foreach (Icon icon in DictIconCache.Values)
{
icon?.Dispose();
}
@ -49,11 +50,11 @@ namespace SystemTrayMenu.Utilities
{
Icon icon = null;
string extension = Path.GetExtension(filePath);
lock (readIcon)
lock (ReadIcon)
{
if (IsExtensionWitSameIcon(extension))
{
icon = dictIconCache.GetOrAdd(extension, GetIcon);
icon = DictIconCache.GetOrAdd(extension, GetIcon);
Icon GetIcon(string keyExtension)
{
return GetFileIcon(filePath, linkOverlay, size);
@ -84,7 +85,7 @@ namespace SystemTrayMenu.Utilities
private static Icon GetFileIcon(string filePath, bool linkOverlay, IconSize size = IconSize.Small)
{
Icon icon = null;
DllImports.NativeMethods.SHFILEINFO shfi = new DllImports.NativeMethods.SHFILEINFO();
DllImports.NativeMethods.SHFILEINFO shfi = default;
uint flags = DllImports.NativeMethods.ShgfiIcon | DllImports.NativeMethods.ShgfiSYSICONINDEX;
if (linkOverlay)
@ -102,12 +103,13 @@ namespace SystemTrayMenu.Utilities
flags += DllImports.NativeMethods.ShgfiLARGEICON;
}
IntPtr hImageList = DllImports.NativeMethods.Shell32SHGetFileInfo(filePath,
IntPtr hImageList = DllImports.NativeMethods.Shell32SHGetFileInfo(
filePath,
DllImports.NativeMethods.FileAttributeNormal,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
if (hImageList != IntPtr.Zero) // got valid handle?
if (hImageList != IntPtr.Zero)
{
IntPtr hIcon;
if (linkOverlay)
@ -178,13 +180,14 @@ namespace SystemTrayMenu.Utilities
}
// Get the folder icon
DllImports.NativeMethods.SHFILEINFO shfi = new DllImports.NativeMethods.SHFILEINFO();
IntPtr Success = DllImports.NativeMethods.Shell32SHGetFileInfo(directoryPath,
DllImports.NativeMethods.SHFILEINFO shfi = default;
IntPtr success = DllImports.NativeMethods.Shell32SHGetFileInfo(
directoryPath,
DllImports.NativeMethods.FileAttributeDirectory,
ref shfi,
(uint)Marshal.SizeOf(shfi),
flags);
if (Success != IntPtr.Zero) // got valid handle?
if (success != IntPtr.Zero)
{
try
{

View file

@ -9,6 +9,7 @@ namespace SystemTrayMenu.Utilities
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
internal static class FolderOptions
{
private static bool hideHiddenEntries = false;

View file

@ -11,9 +11,11 @@ namespace SystemTrayMenu.Utilities
using System.IO;
using System.Reflection;
using System.Windows.Forms;
internal static class Log
{
private static readonly Logger log = new Logger(string.Empty);
private static readonly Logger LogValue = new Logger(string.Empty);
internal static void Initialize()
{
Logger.Start(new FileInfo(GetLogFilePath()));
@ -21,25 +23,25 @@ namespace SystemTrayMenu.Utilities
internal static void Info(string message)
{
log.Info(message);
LogValue.Info(message);
}
internal static void Warn(string message, Exception ex)
{
log.Warn($"{message}{Environment.NewLine}{ex}");
LogValue.Warn($"{message}{Environment.NewLine}{ex}");
}
internal static void Error(string message, Exception ex)
{
log.Error($"{message}{Environment.NewLine}" +
LogValue.Error($"{message}{Environment.NewLine}" +
$"{ex}");
}
internal static string GetLogFilePath()
{
return Path.Combine(Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location),
$"log-{Environment.MachineName}.txt");
return Path.Combine(
Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location), $"log-{Environment.MachineName}.txt");
}
internal static void OpenLogFile()
@ -50,7 +52,7 @@ namespace SystemTrayMenu.Utilities
internal static void WriteApplicationRuns()
{
Assembly assembly = Assembly.GetExecutingAssembly();
log.Info($"Application Start " +
LogValue.Info($"Application Start " +
assembly.ManifestModule.Name + " | " +
assembly.GetName().Version.ToString() + " | " +
$"ScalingFactor={Scaling.Factor}");
@ -80,7 +82,7 @@ namespace SystemTrayMenu.Utilities
{
Arguments = arguments,
UseShellExecute = true,
}
},
};
p.Start();
}

View file

@ -6,6 +6,7 @@ namespace SystemTrayMenu.Utilities
{
using System;
using System.Drawing;
internal static class Scaling
{
internal static float Factor = 1;
@ -33,11 +34,11 @@ namespace SystemTrayMenu.Utilities
{
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = DllImports.NativeMethods.Gdi32GetDeviceCaps(
int logicalScreenHeight = DllImports.NativeMethods.Gdi32GetDeviceCaps(
desktop, (int)DeviceCap.VERTRES);
int PhysicalScreenHeight = DllImports.NativeMethods.Gdi32GetDeviceCaps(
int physicalScreenHeight = DllImports.NativeMethods.Gdi32GetDeviceCaps(
desktop, (int)DeviceCap.DESKTOPVERTRES);
Factor = PhysicalScreenHeight / (float)LogicalScreenHeight;
Factor = physicalScreenHeight / (float)logicalScreenHeight;
}
}
}

View file

@ -8,6 +8,7 @@ namespace SystemTrayMenu.Utilities
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
internal static class SingleAppInstance
{
internal static void Initialize()

View file

@ -11,7 +11,7 @@ namespace SystemTrayMenu.Utilities
internal static class Translator
{
internal static CultureInfo Culture;
private static CultureInfo culture;
internal static void Initialize()
{
@ -22,7 +22,7 @@ namespace SystemTrayMenu.Utilities
Settings.Default.Save();
}
Culture = CultureInfo.CreateSpecificCulture(
culture = CultureInfo.CreateSpecificCulture(
Settings.Default.CurrentCultureInfoName);
}
@ -31,13 +31,14 @@ namespace SystemTrayMenu.Utilities
ResourceManager rm = new ResourceManager(
"SystemTrayMenu.Resources.lang",
typeof(Menu).Assembly);
return rm.GetString(id, Culture);
return rm.GetString(id, culture);
}
}
public class Language
{
public string Name { get; set; }
public string Value { get; set; }
}
}