mirror of
https://github.com/greenshot/greenshot
synced 2025-07-16 10:03:44 -07:00
Enhanced the external command plug-in to capture the first Uri in the output, and places this on the clipboard. Additionally the Uri is linked in the notify bubble or when started from the editor. The behaviour can only be modified via the greenshot.ini and is for all commands.
This commit is contained in:
parent
2b0f828b86
commit
7d28b6a3a5
8 changed files with 319 additions and 54 deletions
|
@ -316,6 +316,7 @@ namespace Greenshot {
|
||||||
fileStripMenuItem.DropDownItems.Add(closeToolStripMenuItem);
|
fileStripMenuItem.DropDownItems.Add(closeToolStripMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private delegate void SurfaceMessageReceivedThreadSafeDelegate(object sender, SurfaceMessageEventArgs eventArgs);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the SufraceMessageEvent receiver which display a message in the status bar if the
|
/// This is the SufraceMessageEvent receiver which display a message in the status bar if the
|
||||||
/// surface is exported. It also updates the title to represent the filename, if there is one.
|
/// surface is exported. It also updates the title to represent the filename, if there is one.
|
||||||
|
@ -323,22 +324,26 @@ namespace Greenshot {
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) {
|
private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) {
|
||||||
string dateTime = DateTime.Now.ToLongTimeString();
|
if (InvokeRequired) {
|
||||||
// TODO: Fix that we only open files, like in the tooltip
|
this.Invoke(new SurfaceMessageReceivedThreadSafeDelegate(SurfaceMessageReceived), new object[] { sender, eventArgs });
|
||||||
switch (eventArgs.MessageType) {
|
} else {
|
||||||
case SurfaceMessageTyp.FileSaved:
|
string dateTime = DateTime.Now.ToLongTimeString();
|
||||||
// Put the event message on the status label and attach the context menu
|
// TODO: Fix that we only open files, like in the tooltip
|
||||||
updateStatusLabel(dateTime + " - " + eventArgs.Message, fileSavedStatusContextMenu);
|
switch (eventArgs.MessageType) {
|
||||||
// Change title
|
case SurfaceMessageTyp.FileSaved:
|
||||||
Text = eventArgs.Surface.LastSaveFullPath + " - " + Language.GetString(LangKey.editor_title);
|
// Put the event message on the status label and attach the context menu
|
||||||
break;
|
updateStatusLabel(dateTime + " - " + eventArgs.Message, fileSavedStatusContextMenu);
|
||||||
case SurfaceMessageTyp.Error:
|
// Change title
|
||||||
case SurfaceMessageTyp.Info:
|
Text = eventArgs.Surface.LastSaveFullPath + " - " + Language.GetString(LangKey.editor_title);
|
||||||
case SurfaceMessageTyp.UploadedUri:
|
break;
|
||||||
default:
|
case SurfaceMessageTyp.Error:
|
||||||
// Put the event message on the status label
|
case SurfaceMessageTyp.Info:
|
||||||
updateStatusLabel(dateTime + " - " + eventArgs.Message);
|
case SurfaceMessageTyp.UploadedUri:
|
||||||
break;
|
default:
|
||||||
|
// Put the event message on the status label
|
||||||
|
updateStatusLabel(dateTime + " - " + eventArgs.Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ Features:
|
||||||
* Editor: a settings window for the torn-edge effect has been added.
|
* Editor: a settings window for the torn-edge effect has been added.
|
||||||
* Editor: a settings window for the drop shadow effect has been added.
|
* Editor: a settings window for the drop shadow effect has been added.
|
||||||
* OneNote: Enabled and enhanced the OneNote destination, so we can test this and see if it's worth releasing.
|
* OneNote: Enabled and enhanced the OneNote destination, so we can test this and see if it's worth releasing.
|
||||||
|
* External command: If a command outputs an URI this will be captured and placed on the clipboard, the behaviour currently can only be modified in the greenshot.ini
|
||||||
|
|
||||||
Bugs resolved:
|
Bugs resolved:
|
||||||
* BUG-1559, BUG-1643: Repeating hotkeys are now prevented.
|
* BUG-1559, BUG-1643: Repeating hotkeys are now prevented.
|
||||||
|
|
|
@ -32,9 +32,24 @@ namespace ExternalCommand {
|
||||||
public class ExternalCommandConfiguration : IniSection {
|
public class ExternalCommandConfiguration : IniSection {
|
||||||
[IniProperty("Commands", Description="The commands that are available.")]
|
[IniProperty("Commands", Description="The commands that are available.")]
|
||||||
public List<string> commands;
|
public List<string> commands;
|
||||||
|
|
||||||
[IniProperty("DoNotRedirect", Description="Skip redirect of standard output", DefaultValue="false")]
|
[IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.", DefaultValue = "true")]
|
||||||
public bool DoNotRedirect;
|
public bool RedirectStandardError;
|
||||||
|
|
||||||
|
[IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).", DefaultValue = "true")]
|
||||||
|
public bool RedirectStandardOutput;
|
||||||
|
|
||||||
|
[IniProperty("ShowStandardOutputInLog", Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.", DefaultValue = "false")]
|
||||||
|
public bool ShowStandardOutputInLog;
|
||||||
|
|
||||||
|
[IniProperty("ParseForUri", Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.", DefaultValue = "true")]
|
||||||
|
public bool ParseOutputForUri;
|
||||||
|
|
||||||
|
[IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")]
|
||||||
|
public bool OutputToClipboard;
|
||||||
|
|
||||||
|
[IniProperty("UriToClipboard", Description = "Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)", DefaultValue = "true")]
|
||||||
|
public bool UriToClipboard;
|
||||||
|
|
||||||
[IniProperty("Commandline", Description="The commandline for the output command.")]
|
[IniProperty("Commandline", Description="The commandline for the output command.")]
|
||||||
public Dictionary<string, string> commandlines;
|
public Dictionary<string, string> commandlines;
|
||||||
|
|
|
@ -27,6 +27,7 @@ using Greenshot.IniFile;
|
||||||
using Greenshot.Plugin;
|
using Greenshot.Plugin;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ExternalCommand {
|
namespace ExternalCommand {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -34,6 +35,7 @@ namespace ExternalCommand {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ExternalCommandDestination : AbstractDestination {
|
public class ExternalCommandDestination : AbstractDestination {
|
||||||
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination));
|
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination));
|
||||||
|
private static Regex URI_REGEXP = new Regex(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)");
|
||||||
private static ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>();
|
private static ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>();
|
||||||
private string presetCommand;
|
private string presetCommand;
|
||||||
|
|
||||||
|
@ -78,39 +80,81 @@ namespace ExternalCommand {
|
||||||
fullPath = ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings);
|
fullPath = ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
string output = null;
|
string output;
|
||||||
|
string error;
|
||||||
if (runInBackground) {
|
if (runInBackground) {
|
||||||
Thread commandThread = new Thread(delegate() {
|
Thread commandThread = new Thread(delegate() {
|
||||||
CallExternalCommand(presetCommand, fullPath, out output);
|
CallExternalCommand(exportInformation, presetCommand, fullPath, out output, out error);
|
||||||
|
ProcessExport(exportInformation, surface);
|
||||||
});
|
});
|
||||||
commandThread.Name = "Running " + presetCommand;
|
commandThread.Name = "Running " + presetCommand;
|
||||||
commandThread.IsBackground = true;
|
commandThread.IsBackground = true;
|
||||||
|
commandThread.SetApartmentState(ApartmentState.STA);
|
||||||
commandThread.Start();
|
commandThread.Start();
|
||||||
exportInformation.ExportMade = true;
|
exportInformation.ExportMade = true;
|
||||||
} else {
|
} else {
|
||||||
try {
|
CallExternalCommand(exportInformation, presetCommand, fullPath, out output, out error);
|
||||||
if (CallExternalCommand(presetCommand, fullPath, out output) == 0) {
|
ProcessExport(exportInformation, surface);
|
||||||
exportInformation.ExportMade = true;
|
|
||||||
} else {
|
|
||||||
exportInformation.ErrorMessage = output;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
exportInformation.ErrorMessage = ex.Message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//exportInformation.Uri = "file://" + fullPath;
|
|
||||||
}
|
}
|
||||||
ProcessExport(exportInformation, surface);
|
|
||||||
return exportInformation;
|
return exportInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CallExternalCommand(string commando, string fullPath, out string output) {
|
/// <summary>
|
||||||
|
/// Wrapper method for the background and normal call, this does all the logic:
|
||||||
|
/// Call the external command, parse for URI, place to clipboard and set the export information
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exportInformation"></param>
|
||||||
|
/// <param name="commando"></param>
|
||||||
|
/// <param name="fullPath"></param>
|
||||||
|
/// <param name="output"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
|
private void CallExternalCommand(ExportInformation exportInformation, string commando, string fullPath, out string output, out string error) {
|
||||||
|
output = null;
|
||||||
|
error = null;
|
||||||
try {
|
try {
|
||||||
return CallExternalCommand(commando, fullPath, null, out output);
|
if (CallExternalCommand(presetCommand, fullPath, out output, out error) == 0) {
|
||||||
|
exportInformation.ExportMade = true;
|
||||||
|
if (!string.IsNullOrEmpty(output)) {
|
||||||
|
MatchCollection uriMatches = URI_REGEXP.Matches(output);
|
||||||
|
// Place output on the clipboard before the URI, so if one is found this overwrites
|
||||||
|
if (config.OutputToClipboard) {
|
||||||
|
ClipboardHelper.SetClipboardData(output);
|
||||||
|
}
|
||||||
|
if (uriMatches != null && uriMatches.Count >= 0) {
|
||||||
|
exportInformation.Uri = uriMatches[0].Groups[1].Value;
|
||||||
|
LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri);
|
||||||
|
if (config.UriToClipboard) {
|
||||||
|
ClipboardHelper.SetClipboardData(exportInformation.Uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.WarnFormat("Error calling external command: {0} ", output);
|
||||||
|
exportInformation.ExportMade = false;
|
||||||
|
exportInformation.ErrorMessage = error;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage);
|
||||||
|
exportInformation.ExportMade = false;
|
||||||
|
exportInformation.ErrorMessage = ex.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper to retry with a runas
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commando"></param>
|
||||||
|
/// <param name="fullPath"></param>
|
||||||
|
/// <param name="output"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private int CallExternalCommand(string commando, string fullPath, out string output, out string error) {
|
||||||
|
try {
|
||||||
|
return CallExternalCommand(commando, fullPath, null, out output, out error);
|
||||||
} catch (Win32Exception w32ex) {
|
} catch (Win32Exception w32ex) {
|
||||||
try {
|
try {
|
||||||
return CallExternalCommand(commando, fullPath, "runas", out output);
|
return CallExternalCommand(commando, fullPath, "runas", out output, out error);
|
||||||
} catch {
|
} catch {
|
||||||
w32ex.Data.Add("commandline", config.commandlines[presetCommand]);
|
w32ex.Data.Add("commandline", config.commandlines[presetCommand]);
|
||||||
w32ex.Data.Add("arguments", config.arguments[presetCommand]);
|
w32ex.Data.Add("arguments", config.arguments[presetCommand]);
|
||||||
|
@ -123,32 +167,51 @@ namespace ExternalCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CallExternalCommand(string commando, string fullPath, string verb, out string output) {
|
/// <summary>
|
||||||
|
/// The actual executing code for the external command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commando"></param>
|
||||||
|
/// <param name="fullPath"></param>
|
||||||
|
/// <param name="verb"></param>
|
||||||
|
/// <param name="output"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) {
|
||||||
string commandline = config.commandlines[commando];
|
string commandline = config.commandlines[commando];
|
||||||
string arguments = config.arguments[commando];
|
string arguments = config.arguments[commando];
|
||||||
output = null;
|
output = null;
|
||||||
|
error = null;
|
||||||
if (!string.IsNullOrEmpty(commandline)) {
|
if (!string.IsNullOrEmpty(commandline)) {
|
||||||
using (Process p = new Process()) {
|
using (Process process = new Process()) {
|
||||||
p.StartInfo.FileName = commandline;
|
process.StartInfo.FileName = commandline;
|
||||||
p.StartInfo.Arguments = String.Format(arguments, fullPath);
|
process.StartInfo.Arguments = String.Format(arguments, fullPath);
|
||||||
p.StartInfo.UseShellExecute = false;
|
process.StartInfo.UseShellExecute = false;
|
||||||
if (!config.DoNotRedirect) {
|
if (config.RedirectStandardOutput) {
|
||||||
p.StartInfo.RedirectStandardOutput = true;
|
process.StartInfo.RedirectStandardOutput = true;
|
||||||
|
}
|
||||||
|
if (config.RedirectStandardError) {
|
||||||
|
process.StartInfo.RedirectStandardError = true;
|
||||||
}
|
}
|
||||||
if (verb != null) {
|
if (verb != null) {
|
||||||
p.StartInfo.Verb = verb;
|
process.StartInfo.Verb = verb;
|
||||||
}
|
}
|
||||||
LOG.Info("Starting : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments);
|
LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
p.Start();
|
process.Start();
|
||||||
p.WaitForExit();
|
process.WaitForExit();
|
||||||
if (!config.DoNotRedirect) {
|
if (config.RedirectStandardOutput) {
|
||||||
output = p.StandardOutput.ReadToEnd();
|
output = process.StandardOutput.ReadToEnd();
|
||||||
if (output != null && output.Trim().Length > 0) {
|
if (config.ShowStandardOutputInLog && output != null && output.Trim().Length > 0) {
|
||||||
LOG.Info("Output:\n" + output);
|
LOG.InfoFormat("Output:\n{0}", output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (config.RedirectStandardError) {
|
||||||
|
error = process.StandardError.ReadToEnd();
|
||||||
|
if (error != null && error.Trim().Length > 0) {
|
||||||
|
LOG.WarnFormat("Error:\n{0}", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LOG.Info("Finished : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments);
|
LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
return p.ExitCode;
|
return process.ExitCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -130,7 +130,7 @@ EndSelection:<<<<<<<4
|
||||||
/// <param name="copy"></param>
|
/// <param name="copy"></param>
|
||||||
private static void SetDataObject(IDataObject ido, bool copy) {
|
private static void SetDataObject(IDataObject ido, bool copy) {
|
||||||
lock (clipboardLockObject) {
|
lock (clipboardLockObject) {
|
||||||
int retryCount = 2;
|
int retryCount = 5;
|
||||||
while (retryCount >= 0) {
|
while (retryCount >= 0) {
|
||||||
try {
|
try {
|
||||||
Clipboard.SetDataObject(ido, copy);
|
Clipboard.SetDataObject(ido, copy);
|
||||||
|
|
|
@ -25,6 +25,7 @@ using System.Windows.Forms;
|
||||||
using Greenshot.Plugin;
|
using Greenshot.Plugin;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using GreenshotPlugin.UnmanagedHelpers;
|
||||||
|
|
||||||
namespace GreenshotPlugin.Core {
|
namespace GreenshotPlugin.Core {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -83,6 +84,11 @@ namespace GreenshotPlugin.Core {
|
||||||
return appIcon.ToBitmap();
|
return appIcon.ToBitmap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
using (Icon appIcon = Shell32.GetFileIcon(path, Shell32.IconSize.Small, false)) {
|
||||||
|
if (appIcon != null) {
|
||||||
|
return appIcon.ToBitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception exIcon) {
|
} catch (Exception exIcon) {
|
||||||
LOG.Error("error retrieving icon: ", exIcon);
|
LOG.Error("error retrieving icon: ", exIcon);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,9 @@ namespace Greenshot.Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set to true to specify if the export worked.
|
||||||
|
/// </summary>
|
||||||
public bool ExportMade {
|
public bool ExportMade {
|
||||||
get {
|
get {
|
||||||
return exportMade;
|
return exportMade;
|
||||||
|
|
|
@ -33,6 +33,178 @@ namespace GreenshotPlugin.UnmanagedHelpers {
|
||||||
public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
|
public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
|
||||||
[DllImport("shell32", CharSet = CharSet.Unicode)]
|
[DllImport("shell32", CharSet = CharSet.Unicode)]
|
||||||
internal static extern IntPtr ExtractAssociatedIcon(HandleRef hInst, StringBuilder iconPath, ref int index);
|
internal static extern IntPtr ExtractAssociatedIcon(HandleRef hInst, StringBuilder iconPath, ref int index);
|
||||||
|
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
|
||||||
|
|
||||||
|
#region Structs
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct SHITEMID {
|
||||||
|
public ushort cb;
|
||||||
|
[MarshalAs(UnmanagedType.LPArray)]
|
||||||
|
public byte[] abID;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct ITEMIDLIST {
|
||||||
|
public SHITEMID mkid;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct BROWSEINFO {
|
||||||
|
public IntPtr hwndOwner;
|
||||||
|
public IntPtr pidlRoot;
|
||||||
|
public IntPtr pszDisplayName;
|
||||||
|
[MarshalAs(UnmanagedType.LPTStr)]
|
||||||
|
public string lpszTitle;
|
||||||
|
public uint ulFlags;
|
||||||
|
public IntPtr lpfn;
|
||||||
|
public int lParam;
|
||||||
|
public IntPtr iImage;
|
||||||
|
}
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct SHFILEINFO {
|
||||||
|
public IntPtr hIcon;
|
||||||
|
public int iIcon;
|
||||||
|
public uint dwAttributes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||||
|
public string szDisplayName;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
||||||
|
public string szTypeName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constants
|
||||||
|
// Browsing for directory.
|
||||||
|
private const uint BIF_RETURNONLYFSDIRS = 0x0001;
|
||||||
|
private const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
|
||||||
|
private const uint BIF_STATUSTEXT = 0x0004;
|
||||||
|
private const uint BIF_RETURNFSANCESTORS = 0x0008;
|
||||||
|
private const uint BIF_EDITBOX = 0x0010;
|
||||||
|
private const uint BIF_VALIDATE = 0x0020;
|
||||||
|
private const uint BIF_NEWDIALOGSTYLE = 0x0040;
|
||||||
|
private const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
|
||||||
|
private const uint BIF_BROWSEINCLUDEURLS = 0x0080;
|
||||||
|
private const uint BIF_BROWSEFORCOMPUTER = 0x1000;
|
||||||
|
private const uint BIF_BROWSEFORPRINTER = 0x2000;
|
||||||
|
private const uint BIF_BROWSEINCLUDEFILES = 0x4000;
|
||||||
|
private const uint BIF_SHAREABLE = 0x8000;
|
||||||
|
|
||||||
|
private const uint SHGFI_ICON = 0x000000100; // get icon
|
||||||
|
private const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
|
||||||
|
private const uint SHGFI_TYPENAME = 0x000000400; // get type name
|
||||||
|
private const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes
|
||||||
|
private const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location
|
||||||
|
private const uint SHGFI_EXETYPE = 0x000002000; // return exe type
|
||||||
|
private const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index
|
||||||
|
private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon
|
||||||
|
private const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state
|
||||||
|
private const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes
|
||||||
|
private const uint SHGFI_LARGEICON = 0x000000000; // get large icon
|
||||||
|
private const uint SHGFI_SMALLICON = 0x000000001; // get small icon
|
||||||
|
private const uint SHGFI_OPENICON = 0x000000002; // get open icon
|
||||||
|
private const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon
|
||||||
|
private const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
|
||||||
|
private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
|
||||||
|
private const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays
|
||||||
|
private const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay
|
||||||
|
|
||||||
|
private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||||
|
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Options to specify the size of icons to return.
|
||||||
|
/// </summary>
|
||||||
|
public enum IconSize {
|
||||||
|
/// <summary>
|
||||||
|
/// Specify large icon - 32 pixels by 32 pixels.
|
||||||
|
/// </summary>
|
||||||
|
Large = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Specify small icon - 16 pixels by 16 pixels.
|
||||||
|
/// </summary>
|
||||||
|
Small = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Options to specify whether folders should be in the open or closed state.
|
||||||
|
/// </summary>
|
||||||
|
public enum FolderType {
|
||||||
|
/// <summary>
|
||||||
|
/// Specify open folder.
|
||||||
|
/// </summary>
|
||||||
|
Open = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Specify closed folder.
|
||||||
|
/// </summary>
|
||||||
|
Closed = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an icon for a given file - indicated by the name parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Pathname for file.</param>
|
||||||
|
/// <param name="size">Large or small</param>
|
||||||
|
/// <param name="linkOverlay">Whether to include the link icon</param>
|
||||||
|
/// <returns>System.Drawing.Icon</returns>
|
||||||
|
public static Icon GetFileIcon(string name, IconSize size, bool linkOverlay) {
|
||||||
|
SHFILEINFO shfi = new SHFILEINFO();
|
||||||
|
uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;
|
||||||
|
|
||||||
|
if (true == linkOverlay) {
|
||||||
|
flags += Shell32.SHGFI_LINKOVERLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the size specified for return. */
|
||||||
|
if (IconSize.Small == size) {
|
||||||
|
flags += Shell32.SHGFI_SMALLICON;
|
||||||
|
} else {
|
||||||
|
flags += Shell32.SHGFI_LARGEICON;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHGetFileInfo(name, Shell32.FILE_ATTRIBUTE_NORMAL, ref shfi, (uint)Marshal.SizeOf(shfi), flags);
|
||||||
|
|
||||||
|
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
|
||||||
|
Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
|
||||||
|
// Cleanup
|
||||||
|
User32.DestroyIcon(shfi.hIcon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to access system folder icons.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">Specify large or small icons.</param>
|
||||||
|
/// <param name="folderType">Specify open or closed FolderType.</param>
|
||||||
|
/// <returns>System.Drawing.Icon</returns>
|
||||||
|
public static Icon GetFolderIcon(IconSize size, FolderType folderType) {
|
||||||
|
// Need to add size check, although errors generated at present!
|
||||||
|
uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
|
||||||
|
|
||||||
|
if (FolderType.Open == folderType) {
|
||||||
|
flags += SHGFI_OPENICON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IconSize.Small == size) {
|
||||||
|
flags += SHGFI_SMALLICON;
|
||||||
|
} else {
|
||||||
|
flags += SHGFI_LARGEICON;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the folder icon
|
||||||
|
SHFILEINFO shfi = new SHFILEINFO();
|
||||||
|
SHGetFileInfo(null, FILE_ATTRIBUTE_DIRECTORY, ref shfi, (uint)Marshal.SizeOf(shfi), flags);
|
||||||
|
|
||||||
|
//Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle
|
||||||
|
// Now clone the icon, so that it can be successfully stored in an ImageList
|
||||||
|
Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
User32.DestroyIcon(shfi.hIcon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an icon representation of an image contained in the specified file.
|
/// Returns an icon representation of an image contained in the specified file.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue