/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.UnmanagedHelpers; using log4net; using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; namespace GreenshotPlugin.Core { /// /// Description of PluginUtils. /// public static class PluginUtils { private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; private static readonly IDictionary ExeIconCache = new Dictionary(); static PluginUtils() { CoreConfig.PropertyChanged += OnIconSizeChanged; } /// /// Simple global property to get the Greenshot host /// public static IGreenshotHost Host { get; set; } /// /// Clear icon cache /// /// /// private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "IconSize") { List cachedImages = new List(); lock (ExeIconCache) { foreach (string key in ExeIconCache.Keys) { cachedImages.Add(ExeIconCache[key]); } ExeIconCache.Clear(); } foreach (Image cachedImage in cachedImages) { cachedImage?.Dispose(); } } } /// /// Get the path of an executable /// /// e.g. cmd.exe /// Path to file public static string GetExePath(string exeName) { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) { if (key != null) { // "" is the default key, which should point to the requested location return (string)key.GetValue(""); } } foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(';')) { try { string path = pathEntry.Trim(); if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) { return Path.GetFullPath(path); } } catch (Exception) { Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); } } return null; } /// /// Get icon from resource files, from the cache. /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ /// /// path to the exe or dll /// index of the icon /// Bitmap with the icon or null if something happended public static Image GetCachedExeIcon(string path, int index) { string cacheKey = $"{path}:{index}"; Image returnValue; lock (ExeIconCache) { if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) { return returnValue; } lock (ExeIconCache) { if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) { return returnValue; } returnValue = GetExeIcon(path, index); if (returnValue != null) { ExeIconCache.Add(cacheKey, returnValue); } } } return returnValue; } /// /// Get icon for executable /// /// path to the exe or dll /// index of the icon /// Bitmap with the icon or null if something happended private static Bitmap GetExeIcon(string path, int index) { if (!File.Exists(path)) { return null; } try { using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) { if (appIcon != null) { return appIcon.ToBitmap(); } } using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) { if (appIcon != null) { return appIcon.ToBitmap(); } } } catch (Exception exIcon) { Log.Error("error retrieving icon: ", exIcon); } return null; } /// /// Helper method to add a MenuItem to the File MenuItem of an ImageEditor /// /// /// Image to display in the menu /// Text to display in the menu /// The TAG value /// Keys which can be used as shortcut /// The onclick handler public static void AddToFileMenu(IImageEditor imageEditor, Image image, string text, object tag, Keys? shortcutKeys, EventHandler handler) { var item = new ToolStripMenuItem { Image = image, Text = text, Tag = tag }; if (shortcutKeys.HasValue) { item.ShortcutKeys = shortcutKeys.Value; } item.Click += handler; AddToFileMenu(imageEditor, item); } /// /// Helper method to add a MenuItem to the File MenuItem of an ImageEditor /// /// /// public static void AddToFileMenu(IImageEditor imageEditor, ToolStripMenuItem item) { ToolStripMenuItem toolStripMenuItem = imageEditor.GetFileMenuItem(); bool added = false; for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) { if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) { toolStripMenuItem.DropDownItems.Insert(i, item); added = true; break; } } if (!added) { toolStripMenuItem.DropDownItems.Add(item); } } /// /// Helper method to add a MenuItem to the Plugin MenuItem of an ImageEditor /// /// /// public static void AddToPluginMenu(IImageEditor imageEditor, ToolStripMenuItem item) { ToolStripMenuItem toolStripMenuItem = imageEditor.GetPluginMenuItem(); bool added = false; for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) { if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) { toolStripMenuItem.DropDownItems.Insert(i, item); added = true; break; } } if (!added) { toolStripMenuItem.DropDownItems.Add(item); } } /// /// Helper method to add a plugin MenuItem to the Greenshot context menu /// /// IGreenshotHost /// ToolStripMenuItem public static void AddToContextMenu(IGreenshotHost host, ToolStripMenuItem item) { // Here we can hang ourselves to the main context menu! ContextMenuStrip contextMenu = host.MainMenu; bool addedItem = false; // Try to find a separator, so we insert ourselves after it for(int i=0; i < contextMenu.Items.Count; i++) { if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) { // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) { var separator = new ToolStripSeparator { Tag = "PluginsAreAddedAfter", Size = new Size(305, 6) }; contextMenu.Items.Insert(i, separator); } else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) { continue; } contextMenu.Items.Insert(i + 1, item); addedItem = true; break; } } // If we didn't insert the item, we just add it... if (!addedItem) { contextMenu.Items.Add(item); } } } }