diff --git a/Core/AppWindow.cs b/Core/AppWindow.cs
index 056f01d3..e59fd4aa 100644
--- a/Core/AppWindow.cs
+++ b/Core/AppWindow.cs
@@ -21,24 +21,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Diagnostics;
using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
using System.Linq;
using System.Runtime.Caching;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Media.Imaging;
using ManagedWinapi.Windows;
+using Microsoft.Win32;
namespace Switcheroo.Core
{
-
///
/// This class is a wrapper around the Win32 api window handles
///
- public class AppWindow : ManagedWinapi.Windows.SystemWindow
+ public class AppWindow : SystemWindow
{
public string FormattedTitle { get; set; }
@@ -59,82 +56,21 @@ public string ProcessTitle
public string FormattedProcessTitle { get; set; }
- public BitmapImage IconImage
- {
- get
- {
- var key = "IconImage-" + HWnd;
- var iconImage = MemoryCache.Default.Get(key) as BitmapImage;
- if (iconImage == null)
- {
- iconImage = ExtractIcon() ?? new BitmapImage();
- MemoryCache.Default.Add(key, iconImage, DateTimeOffset.Now.AddHours(1));
- }
- return iconImage;
- }
- }
- private BitmapImage ExtractIcon()
- {
- Icon extractAssociatedIcon = null;
- try
- {
- extractAssociatedIcon = Icon.ExtractAssociatedIcon(GetExecutablePath(Process));
- }
- catch (Win32Exception)
- {
- // Could not extract icon
- }
- if (extractAssociatedIcon == null)
- {
- return null;
- }
- using (var memory = new MemoryStream())
- {
- var bitmap = extractAssociatedIcon.ToBitmap();
- bitmap.Save(memory, ImageFormat.Png);
- memory.Position = 0;
- var bitmapImage = new BitmapImage();
- bitmapImage.BeginInit();
- bitmapImage.StreamSource = memory;
- bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
- bitmapImage.EndInit();
- return bitmapImage;
- }
+ public Icon LargeWindowIcon
+ {
+ get { return new WindowIconFinder().Find(this, WindowIconSize.Large); }
}
- private static string GetExecutablePath(Process process)
+ public Icon SmallWindowIcon
{
- // If Vista or later
- if (Environment.OSVersion.Version.Major >= 6)
- {
- return GetExecutablePathAboveVista(process.Id);
- }
-
- return process.MainModule.FileName;
+ get { return new WindowIconFinder().Find(this, WindowIconSize.Small); }
}
- private static string GetExecutablePathAboveVista(int processId)
+ public string ExecutablePath
{
- 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());
+ get { return GetExecutablePath(Process.Id); }
}
public AppWindow(IntPtr HWnd) : base(HWnd) { }
@@ -182,7 +118,7 @@ public bool IsAltTabWindow()
private bool HasWindowTitle()
{
- return Title.Length > 0;
+ return !string.IsNullOrEmpty(Title);
}
private bool IsToolWindow()
@@ -223,5 +159,28 @@ private bool IsOwnerOrOwnerNotVisible()
{
return Owner == null || !Owner.Visible;
}
+
+ // This method only works on Windows >= Windows Vista
+ private static string GetExecutablePath(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());
+ }
}
}
diff --git a/Core/Core.csproj b/Core/Core.csproj
index 7928c716..c5b82740 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -59,6 +59,7 @@
+
diff --git a/Core/WinApi.cs b/Core/WinApi.cs
index dc2f9992..a58e4f07 100644
--- a/Core/WinApi.cs
+++ b/Core/WinApi.cs
@@ -246,5 +246,59 @@ public enum MapVirtualKeyMapTypes : uint
///
MAPVK_VK_TO_VSC_EX = 0x04
}
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr SendMessage(IntPtr hwnd, int message, int wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr DefWindowProc(IntPtr hWnd, int message, int wParam, IntPtr lParam);
+
+ public enum ClassLongFlags
+ {
+ GCLP_MENUNAME = -8,
+ GCLP_HBRBACKGROUND = -10,
+ GCLP_HCURSOR = -12,
+ GCLP_HICON = -14,
+ GCLP_HMODULE = -16,
+ GCL_CBWNDEXTRA = -18,
+ GCL_CBCLSEXTRA = -20,
+ GCLP_WNDPROC = -24,
+ GCL_STYLE = -26,
+ GCLP_HICONSM = -34,
+ GCW_ATOM = -32
+ }
+
+ public static IntPtr GetClassLongPtr(IntPtr hWnd, ClassLongFlags flags)
+ {
+ return IntPtr.Size > 4 ? GetClassLongPtr64(hWnd, flags) : new IntPtr(GetClassLongPtr32(hWnd, flags));
+ }
+
+ [DllImport("user32.dll", EntryPoint = "GetClassLong")]
+ public static extern uint GetClassLongPtr32(IntPtr hWnd, ClassLongFlags flags);
+
+ [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")]
+ public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, ClassLongFlags flags);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern uint RegisterWindowMessage(string lpString);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr SendMessageTimeout(
+ IntPtr hWnd,
+ uint Msg,
+ IntPtr wParam,
+ IntPtr lParam,
+ SendMessageTimeoutFlags fuFlags,
+ uint uTimeout,
+ out IntPtr lpdwResult);
+
+ [Flags]
+ public enum SendMessageTimeoutFlags : uint
+ {
+ SMTO_NORMAL = 0x0,
+ SMTO_BLOCK = 0x1,
+ SMTO_ABORTIFHUNG = 0x2,
+ SMTO_NOTIMEOUTIFNOTHUNG = 0x8
+ }
}
}
\ No newline at end of file
diff --git a/Core/WindowIconFinder.cs b/Core/WindowIconFinder.cs
new file mode 100644
index 00000000..c9f4be63
--- /dev/null
+++ b/Core/WindowIconFinder.cs
@@ -0,0 +1,68 @@
+/*
+ * Switcheroo - The incremental-search task switcher for Windows.
+ * http://www.switcheroo.io/
+ * Copyright 2009, 2010 James Sulak
+ * Copyright 2014 Regin Larsen
+ *
+ * Switcheroo 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Switcheroo 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 Switcheroo. If not, see .
+ */
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+
+namespace Switcheroo.Core
+{
+ public enum WindowIconSize
+ {
+ Small,
+ Large
+ }
+
+ public class WindowIconFinder
+ {
+ public Icon Find(AppWindow window, WindowIconSize size)
+ {
+ Icon icon = null;
+ try
+ {
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms632625(v=vs.85).aspx
+ IntPtr response;
+ var outvalue = WinApi.SendMessageTimeout(window.HWnd, 0x007F, size == WindowIconSize.Small ? new IntPtr(2) : new IntPtr(1),
+ IntPtr.Zero, WinApi.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 100, out response);
+
+ if (outvalue == IntPtr.Zero || response == IntPtr.Zero)
+ {
+ response = WinApi.GetClassLongPtr(window.HWnd,
+ size == WindowIconSize.Small ? WinApi.ClassLongFlags.GCLP_HICONSM : WinApi.ClassLongFlags.GCLP_HICON);
+ }
+
+ if (response != IntPtr.Zero)
+ {
+ icon = Icon.FromHandle(response);
+ }
+ else
+ {
+ var executablePath = window.ExecutablePath;
+ icon = Icon.ExtractAssociatedIcon(executablePath);
+ }
+ }
+ catch (Win32Exception)
+ {
+ // Could not extract icon
+ }
+ return icon;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Switcheroo.sln b/Switcheroo.sln
index 03030f39..655f80be 100644
--- a/Switcheroo.sln
+++ b/Switcheroo.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
-VisualStudioVersion = 12.0.30110.0
+VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Switcheroo", "Switcheroo\Switcheroo.csproj", "{B28E183B-0E38-48A8-8A4E-B4AB7B23CE93}"
ProjectSection(ProjectDependencies) = postProject
diff --git a/Switcheroo/IconToBitmapConverter.cs b/Switcheroo/IconToBitmapConverter.cs
new file mode 100644
index 00000000..6e4d3781
--- /dev/null
+++ b/Switcheroo/IconToBitmapConverter.cs
@@ -0,0 +1,51 @@
+/*
+ * Switcheroo - The incremental-search task switcher for Windows.
+ * http://www.switcheroo.io/
+ * Copyright 2009, 2010 James Sulak
+ * Copyright 2014 Regin Larsen
+ *
+ * Switcheroo 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Switcheroo 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 Switcheroo. If not, see .
+ */
+
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Windows.Media.Imaging;
+
+namespace Switcheroo
+{
+ public class IconToBitmapImageConverter
+ {
+ public BitmapImage Convert(Icon icon)
+ {
+ if (icon == null)
+ {
+ return null;
+ }
+
+ using (var memory = new MemoryStream())
+ {
+ var bitmap = icon.ToBitmap();
+ bitmap.Save(memory, ImageFormat.Png);
+ memory.Position = 0;
+ var bitmapImage = new BitmapImage();
+ bitmapImage.BeginInit();
+ bitmapImage.StreamSource = memory;
+ bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
+ bitmapImage.EndInit();
+ return bitmapImage;
+ }
+ }
+ }
+}
diff --git a/Switcheroo/MainWindow.xaml b/Switcheroo/MainWindow.xaml
index 636ab302..a040055f 100644
--- a/Switcheroo/MainWindow.xaml
+++ b/Switcheroo/MainWindow.xaml
@@ -24,9 +24,14 @@
-
-
-
+
+
+
+
+
+
+
+
@@ -51,7 +56,14 @@
-
+
+
+
+
+
+
+
+
MSBuild:Compile
Designer
+
+
+
Designer
MSBuild:Compile
diff --git a/Switcheroo/WindowHandleToCachedIconConverter.cs b/Switcheroo/WindowHandleToCachedIconConverter.cs
new file mode 100644
index 00000000..6bfd2b4b
--- /dev/null
+++ b/Switcheroo/WindowHandleToCachedIconConverter.cs
@@ -0,0 +1,42 @@
+/*
+ * Switcheroo - The incremental-search task switcher for Windows.
+ * http://www.switcheroo.io/
+ * Copyright 2009, 2010 James Sulak
+ * Copyright 2014 Regin Larsen
+ *
+ * Switcheroo 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Switcheroo 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 Switcheroo. If not, see .
+ */
+
+using System;
+using System.Globalization;
+using System.Runtime.Caching;
+using System.Windows.Data;
+using System.Windows.Media.Imaging;
+
+namespace Switcheroo
+{
+ public class WindowHandleToCachedIconConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var key = "IconImage-" + value + "-longCache";
+ return MemoryCache.Default.Get(key) as BitmapImage;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Switcheroo/WindowHandleToIconConverter.cs b/Switcheroo/WindowHandleToIconConverter.cs
new file mode 100644
index 00000000..4dd24f46
--- /dev/null
+++ b/Switcheroo/WindowHandleToIconConverter.cs
@@ -0,0 +1,94 @@
+/*
+ * Switcheroo - The incremental-search task switcher for Windows.
+ * http://www.switcheroo.io/
+ * Copyright 2009, 2010 James Sulak
+ * Copyright 2014 Regin Larsen
+ *
+ * Switcheroo 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Switcheroo 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 Switcheroo. If not, see .
+ */
+
+using System;
+using System.Globalization;
+using System.Runtime.Caching;
+using System.Windows.Data;
+using System.Windows.Media.Imaging;
+using Microsoft.Win32;
+using Switcheroo.Core;
+
+namespace Switcheroo
+{
+ public class WindowHandleToIconConverter : IValueConverter
+ {
+ private readonly IconToBitmapImageConverter _iconToBitmapConverter;
+
+ public WindowHandleToIconConverter()
+ {
+ _iconToBitmapConverter = new IconToBitmapImageConverter();
+ }
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var handle = (IntPtr)value;
+ var key = "IconImage-" + handle;
+ var shortCacheKey = key + "-shortCache";
+ var longCacheKey = key + "-longCache";
+ var iconImage = MemoryCache.Default.Get(shortCacheKey) as BitmapImage;
+ if (iconImage == null)
+ {
+ var window = new AppWindow(handle);
+ var icon = ShouldUseSmallTaskbarIcons() ? window.SmallWindowIcon : window.LargeWindowIcon;
+ iconImage = _iconToBitmapConverter.Convert(icon) ?? new BitmapImage();
+ MemoryCache.Default.Add(shortCacheKey, iconImage, DateTimeOffset.Now.AddSeconds(5));
+ MemoryCache.Default.Add(longCacheKey, iconImage, DateTimeOffset.Now.AddMinutes(120));
+ }
+ return iconImage;
+ }
+
+ private static bool ShouldUseSmallTaskbarIcons()
+ {
+ var cacheKey = "SmallTaskbarIcons";
+
+ var cachedSetting = MemoryCache.Default.Get(cacheKey) as bool?;
+ if (cachedSetting != null)
+ {
+ return cachedSetting.Value;
+ }
+
+ using (var registryKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"))
+ {
+ if (registryKey == null)
+ {
+ return false;
+ }
+
+ var value = registryKey.GetValue("TaskbarSmallIcons");
+ if (value == null)
+ {
+ return false;
+ }
+
+ int intValue;
+ int.TryParse(value.ToString(), out intValue);
+ var smallTaskbarIcons = intValue == 1;
+ MemoryCache.Default.Set(cacheKey, smallTaskbarIcons, DateTimeOffset.Now.AddMinutes(120));
+ return smallTaskbarIcons;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file