diff --git a/Switcheroo/AppWindow.cs b/Switcheroo/AppWindow.cs index 70acbfab..5162d343 100644 --- a/Switcheroo/AppWindow.cs +++ b/Switcheroo/AppWindow.cs @@ -19,10 +19,13 @@ using System; using System.ComponentModel; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.Caching; +using System.Runtime.InteropServices; +using System.Text; using System.Windows.Media.Imaging; using ManagedWinapi.Windows; @@ -90,13 +93,16 @@ private BitmapImage ExtractIcon() Icon extractAssociatedIcon = null; try { - extractAssociatedIcon = Icon.ExtractAssociatedIcon(Process.MainModule.FileName); + extractAssociatedIcon = Icon.ExtractAssociatedIcon(GetExecutablePath(Process)); } catch (Win32Exception) { - // no access to process + // Could not extract icon + } + if (extractAssociatedIcon == null) + { + return null; } - if (extractAssociatedIcon == null) return null; using (var memory = new MemoryStream()) { @@ -112,6 +118,39 @@ private BitmapImage ExtractIcon() } } + private static string GetExecutablePath(Process process) + { + // If Vista or later + if (Environment.OSVersion.Version.Major >= 6) + { + return GetExecutablePathAboveVista(process.Id); + } + + return process.MainModule.FileName; + } + + private static string GetExecutablePathAboveVista(int processId) + { + var buffer = new StringBuilder(1024); + var hprocess = WinApi.OpenProcess(WinApi.ProcessAccess.QueryLimitedInformation, false, processId); + if (hprocess == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error()); + + try + { + // ReSharper disable once RedundantAssignment + var size = buffer.Capacity; + if (WinApi.QueryFullProcessImageName(hprocess, 0, buffer, out size)) + { + return buffer.ToString(); + } + } + finally + { + WinApi.CloseHandle(hprocess); + } + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + public AppWindow(IntPtr HWnd) : base(HWnd) { } /// diff --git a/Switcheroo/winapi.cs b/Switcheroo/winapi.cs index 22c0cfe5..217b2cb2 100644 --- a/Switcheroo/winapi.cs +++ b/Switcheroo/winapi.cs @@ -67,5 +67,113 @@ public enum GetAncestorFlags [DllImport("user32.dll")] public static extern IntPtr GetLastActivePopup(IntPtr hWnd); + + [Flags] + public enum ProcessAccess + { + /// + /// Required to create a thread. + /// + CreateThread = 0x0002, + + /// + /// + /// + SetSessionId = 0x0004, + + /// + /// Required to perform an operation on the address space of a process + /// + VmOperation = 0x0008, + + /// + /// Required to read memory in a process using ReadProcessMemory. + /// + VmRead = 0x0010, + + /// + /// Required to write to memory in a process using WriteProcessMemory. + /// + VmWrite = 0x0020, + + /// + /// Required to duplicate a handle using DuplicateHandle. + /// + DupHandle = 0x0040, + + /// + /// Required to create a process. + /// + CreateProcess = 0x0080, + + /// + /// Required to set memory limits using SetProcessWorkingSetSize. + /// + SetQuota = 0x0100, + + /// + /// Required to set certain information about a process, such as its priority class (see SetPriorityClass). + /// + SetInformation = 0x0200, + + /// + /// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken). + /// + QueryInformation = 0x0400, + + /// + /// Required to suspend or resume a process. + /// + SuspendResume = 0x0800, + + /// + /// Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob, QueryFullProcessImageName). + /// A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. + /// + QueryLimitedInformation = 0x1000, + + /// + /// Required to wait for the process to terminate using the wait functions. + /// + Synchronize = 0x100000, + + /// + /// Required to delete the object. + /// + Delete = 0x00010000, + + /// + /// Required to read information in the security descriptor for the object, not including the information in the SACL. + /// To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right. + /// + ReadControl = 0x00020000, + + /// + /// Required to modify the DACL in the security descriptor for the object. + /// + WriteDac = 0x00040000, + + /// + /// Required to change the owner in the security descriptor for the object. + /// + WriteOwner = 0x00080000, + + StandardRightsRequired = 0x000F0000, + + /// + /// All possible access rights for a process object. + /// + AllAccess = StandardRightsRequired | Synchronize | 0xFFFF + } + + + [DllImport("kernel32.dll")] + public static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags, StringBuilder lpExeName, out int size); + + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hHandle); } } \ No newline at end of file