diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs index bc3b401b0..41162f690 100644 --- a/Greenshot/Destinations/EmailDestination.cs +++ b/Greenshot/Destinations/EmailDestination.cs @@ -72,6 +72,7 @@ namespace Greenshot.Destinations { exePath = GetExePath("OUTLOOK.EXE"); if (exePath != null && File.Exists(exePath)) { applicationIcon = GetExeIcon(exePath, 0); + WindowDetails.AddProcessToExcludeFromFreeze("outlook"); if (conf.OutlookAllowExportInMeetings) { meetingIcon = GetExeIcon(exePath, 2); } diff --git a/Greenshot/Destinations/ExcelDestination.cs b/Greenshot/Destinations/ExcelDestination.cs index 6f6bd929e..5cd87b4eb 100644 --- a/Greenshot/Destinations/ExcelDestination.cs +++ b/Greenshot/Destinations/ExcelDestination.cs @@ -48,6 +48,7 @@ namespace Greenshot.Destinations { if (exePath != null && File.Exists(exePath)) { applicationIcon = GetExeIcon(exePath, 0); workbookIcon = GetExeIcon(exePath, 1); + WindowDetails.AddProcessToExcludeFromFreeze("excel"); } else { exePath = null; } diff --git a/Greenshot/Destinations/OneNoteDestination.cs b/Greenshot/Destinations/OneNoteDestination.cs index 1fdbda61c..96a6c04be 100644 --- a/Greenshot/Destinations/OneNoteDestination.cs +++ b/Greenshot/Destinations/OneNoteDestination.cs @@ -47,6 +47,7 @@ namespace Greenshot.Destinations { if (exePath != null && File.Exists(exePath)) { applicationIcon = GetExeIcon(exePath, 0); notebookIcon = GetExeIcon(exePath, 0); + WindowDetails.AddProcessToExcludeFromFreeze("onenote"); } else { exePath = null; } diff --git a/Greenshot/Destinations/PowerpointDestination.cs b/Greenshot/Destinations/PowerpointDestination.cs index e99f6e89c..cd0d842c3 100644 --- a/Greenshot/Destinations/PowerpointDestination.cs +++ b/Greenshot/Destinations/PowerpointDestination.cs @@ -48,6 +48,7 @@ namespace Greenshot.Destinations { if (exePath != null && File.Exists(exePath)) { applicationIcon = GetExeIcon(exePath, 0); presentationIcon = GetExeIcon(exePath, 1); + WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); } else { exePath = null; } diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index 4a8b3404f..c402aeb91 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -107,7 +107,10 @@ namespace Greenshot.Forms { // Make sure we never capture the captureform WindowDetails.RegisterIgnoreHandle(this.Handle); - // TODO: Need to call unregister at close + // Unregister at close + this.FormClosing += delegate { + WindowDetails.UnregisterIgnoreHandle(this.Handle); + }; // set cursor location cursorPos = WindowCapture.GetCursorLocation(); diff --git a/Greenshot/Helpers/Log4NET.cs b/Greenshot/Helpers/Log4NET.cs deleted file mode 100644 index 91a0be796..000000000 --- a/Greenshot/Helpers/Log4NET.cs +++ /dev/null @@ -1,19 +0,0 @@ -/* - * User: Robin - * Date: 05.04.2010 - */ -using System; -using System.IO; -using log4net.Util; - -namespace Greenshot.Helpers { - /// - /// Description of Log4NET. - /// - public class SpecialFolderPatternConverter : PatternConverter { - override protected void Convert(TextWriter writer, object state) { - Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), base.Option, true); - writer.Write(Environment.GetFolderPath(specialFolder)); - } - } -} diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs index 8b6e1235f..af0b065bf 100644 --- a/GreenshotPlugin/Core/WindowsHelper.cs +++ b/GreenshotPlugin/Core/WindowsHelper.cs @@ -166,7 +166,14 @@ namespace GreenshotPlugin.Core { private static CoreConfiguration conf = IniConfig.GetIniSection(); private static List ignoreHandles = new List(); private static Dictionary iconCache = new Dictionary(); - + private static List excludeProcessesFromFreeze = new List(); + + public static void AddProcessToExcludeFromFreeze(string processname) { + if (!excludeProcessesFromFreeze.Contains(processname)) { + excludeProcessesFromFreeze.Add(processname); + } + } + internal static bool isIgnoreHandle(IntPtr handle) { return ignoreHandles.Contains(handle); } @@ -223,13 +230,67 @@ namespace GreenshotPlugin.Core { frozen = false; } + public string ProcessPath { + get { + if (Handle == IntPtr.Zero) { + // not a valid window handle + return string.Empty; + } + StringBuilder _PathBuffer = new StringBuilder(512); + // Get the process id + uint processid; + User32.GetWindowThreadProcessId(Handle, out processid); + + // Try the GetModuleFileName method first since it's the fastest. + // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. + // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. + IntPtr hprocess = Kernel32.OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); + if (hprocess != IntPtr.Zero) { + try { + if (Kernel32.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { + return _PathBuffer.ToString(); + } + } finally { + Kernel32.CloseHandle(hprocess); + } + } + + hprocess = Kernel32.OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); + if (hprocess != IntPtr.Zero) { + try { + // Try this method for Vista or higher operating systems + uint size = (uint)_PathBuffer.Capacity; + if ((Environment.OSVersion.Version.Major >= 6) && (Kernel32.QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) { + return _PathBuffer.ToString(); + } + + // Try the GetProcessImageFileName method + if (Kernel32.GetProcessImageFileName(hprocess, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { + string dospath = _PathBuffer.ToString(); + foreach (string drive in Environment.GetLogicalDrives()) { + if (Kernel32.QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { + if (dospath.StartsWith(_PathBuffer.ToString())) { + return drive + dospath.Remove(0, _PathBuffer.Length); + } + } + } + } + } finally { + Kernel32.CloseHandle(hprocess); + } + } + + return string.Empty; + } + } + /// /// Get the icon belonging to the process /// public Image DisplayIcon { get { try { - string filename = Process.MainModule.FileName; + string filename = ProcessPath; if (!iconCache.ContainsKey(filename)) { Image icon = null; if (File.Exists(filename)) { @@ -244,6 +305,7 @@ namespace GreenshotPlugin.Core { return iconCache[filename]; } catch (Exception ex) { LOG.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); + LOG.Warn(ex); } return null; } @@ -1211,26 +1273,38 @@ namespace GreenshotPlugin.Core { User32.SendMessage(Handle, (int)WindowsMessages.WM_VSCROLL, ptrWparam, ptrLparam); } + private bool CanFreezeOrUnfreeze(string titleOrProcessname) { + if (string.IsNullOrEmpty(titleOrProcessname)) { + return false; + } + if (titleOrProcessname.ToLower().Contains("greenshot")) { + return false; + } + + foreach (string excludeProcess in excludeProcessesFromFreeze) { + if (titleOrProcessname.ToLower().Contains(excludeProcess)) { + return false; + } + } + return true; + } + /// /// Freezes the process belonging to the window /// Warning: Use only if no other way!! /// private void FreezeWindow() { Process proc = Process.GetProcessById(this.ProcessId.ToInt32()); - - if (proc.ProcessName == string.Empty){ + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) { + LOG.DebugFormat("Not freezing {0}", processName); return; } - if (proc.ProcessName.ToLower().Contains("greenshot")) { - LOG.DebugFormat("Not freezing ourselves, process was: {0}", proc.ProcessName); + if (!CanFreezeOrUnfreeze(Text)) { + LOG.DebugFormat("Not freezing {0}", processName); return; } - // TODO: Check Outlook, Office etc? - if (proc.ProcessName.ToLower().Contains("outlook")) { - LOG.DebugFormat("Not freezing outlook due to Destinations, process was: {0}", proc.ProcessName); - return; - } - LOG.DebugFormat("Freezing process: {0}", proc.ProcessName); + LOG.DebugFormat("Freezing process: {0}", processName); foreach (ProcessThread pT in proc.Threads) { IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); @@ -1248,15 +1322,17 @@ namespace GreenshotPlugin.Core { /// public void UnfreezeWindow() { Process proc = Process.GetProcessById(this.ProcessId.ToInt32()); - - if (proc.ProcessName == string.Empty) { + + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) { + LOG.DebugFormat("Not unfreezing {0}", processName); return; } - if (proc.ProcessName.ToLower().Contains("greenshot")) { - LOG.DebugFormat("Not unfreezing ourselves, process was: {0}", proc.ProcessName); + if (!CanFreezeOrUnfreeze(Text)) { + LOG.DebugFormat("Not unfreezing {0}", processName); return; } - LOG.DebugFormat("Unfreezing process: {0}", proc.ProcessName); + LOG.DebugFormat("Unfreezing process: {0}", processName); foreach (ProcessThread pT in proc.Threads) { IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); diff --git a/GreenshotPlugin/UnmanagedHelpers/Enumerations.cs b/GreenshotPlugin/UnmanagedHelpers/Enumerations.cs index c2a432366..364eedfb2 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enumerations.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enumerations.cs @@ -926,4 +926,18 @@ namespace GreenshotPlugin.UnmanagedHelpers { SMTO_ABORTIFHUNG = 0x2, SMTO_NOTIMEOUTIFNOTHUNG = 0x8 } + + [Flags] + public enum ProcessAccessFlags : uint { + All = 0x001F0FFF, + Terminate = 0x00000001, + CreateThread = 0x00000002, + VMOperation = 0x00000008, + VMRead = 0x00000010, + VMWrite = 0x00000020, + DupHandle = 0x00000040, + SetInformation = 0x00000200, + QueryInformation = 0x00000400, + Synchronize = 0x00100000 + } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs index e824edd72..0b0351209 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs @@ -20,6 +20,7 @@ */ using System; using System.Runtime.InteropServices; +using System.Text; namespace GreenshotPlugin.UnmanagedHelpers { [Flags] @@ -48,11 +49,28 @@ namespace GreenshotPlugin.UnmanagedHelpers { [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AllocConsole(); - [DllImport("kernel32")] + [DllImport("kernel32", SetLastError = true)] public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - [DllImport("kernel32")] + [DllImport("kernel32", SetLastError = true)] public static extern uint SuspendThread(IntPtr hThread); - [DllImport("kernel32")] + [DllImport("kernel32", SetLastError = true)] public static extern int ResumeThread(IntPtr hThread); + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, uint dwProcessId); + [DllImport("kernel32", SetLastError = true)] + public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); + [DllImport("kernel32", SetLastError = true)] + public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr GetModuleHandle(string lpModuleName); + [DllImport("kernel32", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); + + // TODO: Move to PSAPI.cs ?? + [DllImport("psapi", SetLastError = true)] + public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); + [DllImport("psapi", SetLastError = true)] + public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); + } }