Skip to content

Instantly share code, notes, and snippets.

@rubyu
Created November 1, 2012 09:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubyu/3992720 to your computer and use it in GitHub Desktop.
Save rubyu/3992720 to your computer and use it in GitHub Desktop.
SoftAltTab
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SoftAltTab
{
class Window
{
private const int GW_HWNDNEXT = 2;
private const int GW_HWNDPREV = 3;
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetTopWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
private static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
extern static bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool AllowSetForegroundWindow(int dwProcessId);
private const int SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
private const int SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
private const int SPIF_SENDCHANGE = 2;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
public void SoftAltTab(IntPtr hwnd)
{
var list = Windows();
RemoveBeforeForeground(list);
int i = 0;
foreach (IntPtr _hwnd in list)
{
if (IsWindowVisible(_hwnd))
{
string title = GetText(_hwnd);
Process proc = GetProcess(_hwnd);
if ((Process.GetCurrentProcess().Id == proc.Id) ||
(title == "Program Manager" && proc.ProcessName == "explorer") ||
(title == "" && proc.ProcessName == "explorer"))
{
Console.Write("black list: ");
dump(_hwnd);
continue;
}
i++;
Console.Write("index={0}, ", i);
dump(_hwnd);
if (i == 2)
{
SetForeground(hwnd, _hwnd);
break;
}
}
else
{
Console.Write("invisible: ");
dump(_hwnd);
}
}
}
private void RemoveBeforeForeground(List<IntPtr> list)
{
IntPtr fore = GetForegroundWindow();
int pos = list.IndexOf(fore);
if (pos > -1)
{
list.RemoveRange(0, pos);
}
}
private List<IntPtr> Windows()
{
List<IntPtr> list = new List<IntPtr>();
IntPtr hwnd = GetTopWindow((IntPtr)null);
while (hwnd != IntPtr.Zero)
{
list.Add(hwnd);
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
}
return list;
}
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int HWND_TOP = 0;
private void SetForeground(IntPtr hwnd, IntPtr _hwnd)
{
IntPtr spTime = IntPtr.Zero;
uint foreThread = GetThreadId(GetForegroundWindow());
uint thisThread = GetThreadId(hwnd);
bool ret = true;
if (foreThread != thisThread)
{
ret = AttachThreadInput(thisThread, foreThread, true);
Console.WriteLine("Attach Foreground Thread->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, spTime, 0);
Console.WriteLine("SystemParametersInfo->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, SPIF_SENDCHANGE);
Console.WriteLine("SystemParametersInfo->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = AllowSetForegroundWindow(GetProcessId(_hwnd));
Console.WriteLine("AllowSetForegroundWindow->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
}
ret = BringWindowToTop(_hwnd);
Console.WriteLine("BringWindowToTop->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = SetWindowPos(_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
Console.WriteLine("SetWindowPos->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = SetForegroundWindow(_hwnd);
Console.WriteLine("SetForegroundWindow->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
if (foreThread != thisThread)
{
ret = SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, spTime, SPIF_SENDCHANGE);
Console.WriteLine("SystemParametersInfo->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
ret = AttachThreadInput(thisThread, foreThread, false);
Console.WriteLine("Dettach Foreground Thread->{0}", ret);
if (ret == false) DumpWin32ErrorCode();
}
}
private void DumpWin32ErrorCode()
{
Console.WriteLine("ErrorCode: {0}", Marshal.GetLastWin32Error());
}
private string GetText(IntPtr hwnd)
{
StringBuilder sb = new StringBuilder(0x1024);
GetWindowText(hwnd, sb, sb.Capacity);
return sb.ToString();
}
private uint GetThreadId(IntPtr hwnd)
{
int pid;
return GetWindowThreadProcessId(hwnd, out pid);
}
private int GetProcessId(IntPtr hwnd)
{
int pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
private Process GetProcess(IntPtr hwnd)
{
return Process.GetProcessById(GetProcessId(hwnd));
}
private void dump(IntPtr hwnd)
{
Process p = GetProcess(hwnd);
Console.WriteLine("hwnd={0}, title={1}, id={2}, name={3}", hwnd, GetText(hwnd), p.Id, p.ProcessName);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment