Suppress alt-tab when app is running

I'm using C# 4.0. I want to suppress alt-tab while a certain application is running and enable it when it's not. The re-enablement should happen when the app stops for any reason, including a crash.

IMessaageFilter doesn't seem to be the right way to do it since, as I understand it, alt-tab is Windows level and isn't passed in to the app.

I guess one way to do it would be to set a system-wide hook to suppress alt-tab. Then I could launch a separate process that checks periodically to see whether my app is running or not; if not, it would re-enable alt-tab and then exit.

But this seems really complicated. Is there an easier way?
LVL 1
BlearyEyeAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

abdkhlaifCommented:
AndyAinscowFreelance programmer / ConsultantCommented:
>>But this seems really complicated. Is there an easier way?

I doubt it - as you said yourself the ALT-TAB is processed at system level not at app level.
BlearyEyeAuthor Commented:
ok. I'll wait around for a while to see if anyone else weighs in.
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

ricovoxCommented:
Hi,

I think the Keyboard hook IS the best option.
I have already written some good code for keyboard hooks, and you don't need any additional hook DLLs or anything -- just pure C# (managed and Pinvoke).

I can put a sample C# application together if you want, so you can see how easy it is.
BlearyEyeAuthor Commented:
ricovox: if you don't mind sending me your code, I'll compare it to the link that abdkhlaif sent ...
ricovoxCommented:
Ok, I put together a quick test program so you can see how easy it is to get this to work.

It is based on the Global Keyboard Hook. All the code is C#, but it includes P/Invoke (e.g. windows API calls).

The project includes one main form. When you check "Install Hook", any keys you press will be logged to the listbox (newer items are added to the TOP of the list for convenience).
When you check "Suppress Alt+Tab", you will notice that pressing Alt+Tab will NOT cause focus to switch to another window.
 Keyboard Test Main FormThe basic idea is this:

The keyboard hook reports all KeyUp/KeyDown events (these are global, system-wide keyboard events--not just when the focus is in our window)

Whenever the TAB KeyDown event occurs, we check to see if ALT is also down. If so we simply tell Windows to ignore the Tab KeyDown event (by setting the keydown's Handled property to true).

That's it. Very simple.

One minor complication is that the code for the Keyboard event handler must be in a separate module (dll). This can still be a .Net/C# dll in a separate project (that you reference from your application), as I have shown in the example code project.

For the convenience of others, I will post the relevant code for the Form itself below.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Utility; //the keyboardhook class

namespace KeyHookTest {
	public partial class HookTestForm : Form {
		private KeyboardHook _hook = null;

		//keep track of whether or not we had to supress the Tab key
		private bool _wasTabKeyHandled = false;

		private bool _filterKeys = false;

		public HookTestForm() {
			InitializeComponent();
			_hook = new KeyboardHook();
			_hook.KeyDown += new KeyEventHandler(Hook_KeyDown);
			_hook.KeyUp += new KeyEventHandler(Hook_KeyUp);
		}

		void Hook_KeyUp(object sender, KeyEventArgs e) {
			Log("KeyUp: {1}{0}", e.KeyCode, e.Modifiers == Keys.None ? "" : e.Modifiers + "+");
			if (!_filterKeys) return;

			//if we previously suppressed the tab keydown, 
			// then we must also suppress the tab keyup for consistency.
			if (e.KeyCode == Keys.Tab & _wasTabKeyHandled) {
				e.Handled = true; 
				Log("Suppressed Tab KeyUp");
			}
		}

		void Hook_KeyDown(object sender, KeyEventArgs e) {
			Log("KeyDown: {1}{0}", e.KeyCode, e.Modifiers == Keys.None ? "" : e.Modifiers + "+");
			if (!_filterKeys) return;

			//if the user presses TAB while ALT is down:
			if (e.KeyCode == Keys.Tab & e.Alt) {
				//suppress the tab keydown. 
				//and set a flag to suppress keyup later for consistency
				_wasTabKeyHandled = true;

				//mark the keydown event as Handled. this will stop it from propagating.
				e.Handled = true; 
				Log("Suppressed Tab KeyDown");
			}
		}

		private void chkHook_CheckedChanged(object sender, EventArgs e) {
			if ((sender as CheckBox).Checked)
				_hook.Hook();
			else {
				_hook.Unhook();
				chkFilter.Checked = false; //we cannot filter the keys unless the hook is installed.
			}
		}

		private void chkFilter_CheckedChanged(object sender, EventArgs e) {
			bool enable = (sender as CheckBox).Checked;
			
			//make sure the Hook is installed.
			if (enable && chkHook.Checked == false)
				chkHook.Checked = true;

			_filterKeys = enable;
		}

		protected override void OnClosing(CancelEventArgs e) {
			if (_hook.HookActive)
				_hook.Unhook();
			base.OnClosing(e);
		}

		private void Log(string s, params object[] args) { Log(string.Format(s, args));}
		private void Log(string s) {
			lstKeys.Items.Add(DateTime.Now.ToString("hh:mm:ss.ff") + " " + s);
			lstKeys.TopIndex = lstKeys.Items.Count - 1;
		}
	}
}

Open in new window


And here is the global keyboard hook code:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.ComponentModel;

namespace Utility {
	/// <summary>
	/// Helper class for global (system-wide) keyboard hooks.
	/// </summary>        
	public class KeyboardHook : IDisposable {
		/// <summary>
		/// Represents the method called when a hook catches a monitored event.
		protected delegate int HookProc(int nCode, int wParam, IntPtr lParam);

		/// <summary>
		/// Value indicating if hook is active.
		/// </summary>
		bool _bHookActive;

		/// <summary>
		/// Stored hook handle returned by SetWindowsHookEx
		/// </summary>
		int hHook;

		/// <summary>
		/// Stored reference to the HookProc delegate (to prevent delegate from beeing collected by GC!)
		/// </summary>
		protected HookProc _hookproc;

		#region Events
		/// <summary>
		/// Occurs when a key is pressed.
		/// </summary>
		public event KeyEventHandler KeyDown;
		/// <summary>
		/// Occurs when a key is released.
		/// </summary>
		public event KeyEventHandler KeyUp;
		/// <summary>
		/// Occurs when a character key is pressed.
		/// </summary>
		public event KeyPressEventHandler KeyPress;
		#endregion //Events

		#region Public properties

		/// <summary>
		/// Gets a value indicating if hook is active.
		/// </summary>
		public bool HookActive {
			get { return _bHookActive; }
		}

		#endregion // Public properties

		#region Public (& Interface) Methods
		/// <summary>
		/// Disposable
		/// </summary>
		void IDisposable.Dispose() {
			Unhook();
		}

		/// <summary>
		/// Install the global hook.
		/// </summary>
		/// <returns> True if hook was successful, otherwise false. </returns>
		public bool Hook() {
			if (!_bHookActive) {
				_hookproc = new HookProc(HookCallbackProcedure);

				//IntPtr hInstance = Process.GetCurrentProcess().Handle;
				IntPtr hInstance = Marshal.GetHINSTANCE(typeof(KeyboardHook).Assembly.GetModules()[0]);
				//.Module

				hHook = SetWindowsHookEx(
					WH_KEYBOARD_LL,
					_hookproc,
					hInstance,
					0);

				if (hHook == 0)
					throw new Win32Exception(Marshal.GetLastWin32Error());

				_bHookActive = true;
			}
			return _bHookActive;
		}

		/// <summary>
		/// Uninstall the global hook.
		/// </summary>
		public void Unhook() {
			if (_bHookActive) {
				UnhookWindowsHookEx(hHook);
				_bHookActive = false;
			}
		}

		#endregion // public methods

		#region Private Event Methods & Handlers

		/// <summary>
		/// Raises the KeyDown event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyDown(KeyEventArgs kea) {
			if (KeyDown != null)
				KeyDown(this, kea);
		}

		/// <summary>
		/// Raises the KeyUp event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyUp(KeyEventArgs kea) {
			if (KeyUp != null)
				KeyUp(this, kea);
		}

		/// <summary>
		/// Raises the KeyPress event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyPress(KeyPressEventArgs kpea) {
			if (KeyPress != null)
				KeyPress(this, kpea);
		}

		/// <summary>
		/// Called when hook is active and a key was pressed.
		/// </summary>
		int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam) {
			bool bHandled = false;

			if (nCode > -1 && (KeyDown != null || KeyUp != null || KeyPress != null)) {
				// Get keyboard data
				KeyboardEventInfo khs = (KeyboardEventInfo)Marshal.PtrToStructure(lParam, typeof(KeyboardEventInfo));

				bool bCapslock = (GetKeyState(VK_CAPITAL) != 0); //used for KeyPress event


				//we can use GetKeyState(VK...) for this, but it is just as good to use the static Control.ModifierKeys property.
				Keys modifiers =  Control.ModifierKeys;

				// Create KeyEventArgs 
				KeyEventArgs kea = new KeyEventArgs((Keys)khs.vkCode | modifiers);

				// Raise KeyDown/KeyUp events
				if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
					OnKeyDown(kea);
					bHandled = kea.Handled;
				} else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
					OnKeyUp(kea);
					bHandled = kea.Handled;
				}

				// Raise KeyPress event
				if (wParam == WM_KEYDOWN && !bHandled && !kea.SuppressKeyPress && this.KeyPress != null) {
					byte[] abyKeyState = new byte[256];
					byte[] abyInBuffer = new byte[2];
					GetKeyboardState(abyKeyState);

					if (ToAscii(khs.vkCode, khs.scanCode, abyKeyState, abyInBuffer, khs.flags) == 1) {
						char chKey = (char)abyInBuffer[0];
						bool bShift = (modifiers & Keys.Shift) != 0;
						if ((bCapslock ^ bShift) && Char.IsLetter(chKey))
							chKey = Char.ToUpper(chKey);
						KeyPressEventArgs kpea = new KeyPressEventArgs(chKey);
						OnKeyPress(kpea);
						bHandled = kpea.Handled;
					}
				}
			}

			if (bHandled)
				return 1;
			else
				return CallNextHookEx(hHook, nCode, wParam, lParam);
		}

		#endregion // event handlers

		#region PInvoke

		const int WH_KEYBOARD_LL = 13,
				WH_KEYBOARD = 2;

		const int WM_KEYDOWN = 0x100,
				WM_KEYUP = 0x101,
				WM_SYSKEYDOWN = 0x104,
				WM_SYSKEYUP = 0x105;

		const byte VK_SHIFT = 0x10,
				VK_CAPITAL = 0x14,
				VK_NUMLOCK = 0x90;

		const byte VK_LSHIFT = 0xA0,
				VK_RSHIFT = 0xA1,
				VK_LCONTROL = 0xA2,
				VK_RCONTROL = 0x3,
				VK_LALT = 0xA4,
				VK_RALT = 0xA5;

		/// <summary>
		/// Windows-API KBDLLHOOKSTRUCT
		/// Contains information about a low-level keyboard input event.
		/// </summary>
		[StructLayout(LayoutKind.Sequential)]
		protected struct KeyboardEventInfo {
			public int vkCode;
			public int scanCode;
			public int flags;
			public int time;
			public int dwExtraInfo;
		}

		// const byte LLKHF_ALTDOWN = 0x20; // not used

		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);

		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int UnhookWindowsHookEx(int idHook);

		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);

		[DllImport("user32.dll")]
		private static extern int GetKeyboardState(byte[] pbKeyState);

		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		private static extern short GetKeyState(int vKey);

		[DllImport("user32.dll")]
		private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);

		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		private static extern IntPtr GetModuleHandle(string lpModuleName);

		#endregion //PInvoke
	}
}

Open in new window


Interested users can download the full source code from the zip attachment.


KeyHookTest.zip

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ricovoxCommented:
BTW, I should point out that it is important to follow standard conventions when using such powerful techniques as global keyboard hooks. Please don't disable Alt+Tab or alter standard processes unless you have extreme circumstances (such as you are developing a POS system etc). Otherwise your users may get very mad that you are not using proper programming "etiquette".
BlearyEyeAuthor Commented:
Thanks. I'll give it a try (on a test machine). It looks like it has everything I need to set and unset the hook. With that I can write a process that checks to see if my application is running, setting or unsetting the hook as appropriate.

The application, btw, is being run in a kiosk-like environment so they don't expect normal PC behavior.
BlearyEyeAuthor Commented:
Hmmm ... when I click Install Hook, I get
  Win32Exception was unhandled: The parameter is incorrect
in method Hook() ...

ricovoxCommented:
hmm. that is strange.
Can you tell me more about your OS? What version? 32bit or 64bit?

Thanks
ricovoxCommented:
And what version of VS are you using?
BlearyEyeAuthor Commented:
Vista 32 bit
Visual Studio 2010
ricovoxCommented:
I'm using Windows 7 64-bit and VS 2008, so it is quite possible that there are some differences that are causing problems.
But I have made some significant changes to the code for the hook. I realized the PInvoke definitions I had were wrong in several places. I thought I got them from a reliable source, but it turns out they were not.

Anyway, please try to replace the full "KeyboardHook.cs" file with the following code and see if that helps:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.ComponentModel;

namespace Utility {
	/// <summary>
	/// Helper class for global (system-wide) keyboard hooks.
	/// </summary>        
	public class KeyboardHook : IDisposable {
		/// <summary>
		/// Represents the method called when a hook catches a monitored event.
		protected delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

		/// <summary>
		/// Value indicating if hook is active.
		/// </summary>
		bool _bHookActive;

		/// <summary>
		/// Stored hook handle returned by SetWindowsHookEx
		/// </summary>
		int hHook;

		/// <summary>
		/// Stored reference to the HookProc delegate (to prevent delegate from beeing collected by GC!)
		/// </summary>
		protected HookProc _hookproc;

		#region Events
		/// <summary>
		/// Occurs when a key is pressed.
		/// </summary>
		public event KeyEventHandler KeyDown;
		/// <summary>
		/// Occurs when a key is released.
		/// </summary>
		public event KeyEventHandler KeyUp;
		/// <summary>
		/// Occurs when a character key is pressed.
		/// </summary>
		public event KeyPressEventHandler KeyPress;
		#endregion //Events

		#region Public properties

		/// <summary>
		/// Gets a value indicating if hook is active.
		/// </summary>
		public bool HookActive {
			get { return _bHookActive; }
		}

		#endregion // Public properties

		#region Public (& Interface) Methods
		/// <summary>
		/// Disposable
		/// </summary>
		void IDisposable.Dispose() {
			Unhook();
		}

		/// <summary>
		/// Install the global hook.
		/// </summary>
		/// <returns> True if hook was successful, otherwise false. </returns>
		public bool Hook() {
			if (!_bHookActive) {
				_hookproc = new HookProc(HookCallbackProcedure);

				IntPtr hInstance = Marshal.GetHINSTANCE(typeof(KeyboardHook).Module);

				hHook = SetWindowsHookEx(
					HookType.WH_KEYBOARD_LL,
					_hookproc,
					hInstance,
					0);

				if (hHook == 0)
					throw new Win32Exception(Marshal.GetLastWin32Error());

				_bHookActive = true;
			}
			return _bHookActive;
		}

		/// <summary>
		/// Uninstall the global hook.
		/// </summary>
		public void Unhook() {
			if (_bHookActive) {
				UnhookWindowsHookEx(hHook);
				_bHookActive = false;
			}
		}

		#endregion // public methods

		#region Private Event Methods & Handlers

		/// <summary>
		/// Raises the KeyDown event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyDown(KeyEventArgs kea) {
			if (KeyDown != null)
				KeyDown(this, kea);
		}

		/// <summary>
		/// Raises the KeyUp event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyUp(KeyEventArgs kea) {
			if (KeyUp != null)
				KeyUp(this, kea);
		}

		/// <summary>
		/// Raises the KeyPress event.
		/// </summary>
		/// <param name="kea"> KeyEventArgs </param>
		protected virtual void OnKeyPress(KeyPressEventArgs kpea) {
			if (KeyPress != null)
				KeyPress(this, kpea);
		}

		/// <summary>
		/// Called when hook is active and a key was pressed.
		/// </summary>
		int HookCallbackProcedure(int nCode, IntPtr wParam, IntPtr lParam) {
			bool bHandled = false;

			if (nCode > -1 && (KeyDown != null || KeyUp != null || KeyPress != null)) {
				// Get keyboard data
				KBDLLHOOKSTRUCT khs = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

				bool bCapslock = (GetKeyState(VK_CAPITAL) != 0); //used for KeyPress event


				//we can use GetKeyState(VK...) for this, but it is just as good to use the static Control.ModifierKeys property.
				Keys modifiers = Control.ModifierKeys;

				// Create KeyEventArgs 
				KeyEventArgs kea = new KeyEventArgs((Keys)khs.vkCode | modifiers);

				int keyInfo = wParam.ToInt32();

				// Raise KeyDown/KeyUp events
				if (keyInfo == WM_KEYDOWN || keyInfo == WM_SYSKEYDOWN) {
					OnKeyDown(kea);
					bHandled = kea.Handled;
				} else if (keyInfo == WM_KEYUP || keyInfo == WM_SYSKEYUP) {
					OnKeyUp(kea);
					bHandled = kea.Handled;
				}

				// Raise KeyPress event
				if (keyInfo == WM_KEYDOWN && !bHandled && !kea.SuppressKeyPress && this.KeyPress != null) {
					byte[] abyKeyState = new byte[256];
					byte[] abyInBuffer = new byte[2];
					GetKeyboardState(abyKeyState);

					if (ToAscii(khs.vkCode, khs.scanCode, abyKeyState, abyInBuffer, (uint)khs.flags) == 1) {
						char chKey = (char)abyInBuffer[0];
						bool bShift = (modifiers & Keys.Shift) != 0;
						if ((bCapslock ^ bShift) && Char.IsLetter(chKey))
							chKey = Char.ToUpper(chKey);
						KeyPressEventArgs kpea = new KeyPressEventArgs(chKey);
						OnKeyPress(kpea);
						bHandled = kpea.Handled;
					}
				}
			}

			if (bHandled)
				return 1;
			else
				return CallNextHookEx(hHook, nCode, wParam, lParam);
		}

		#endregion // event handlers

		#region PInvoke

		const int WM_KEYDOWN = 0x100,
				WM_KEYUP = 0x101,
				WM_SYSKEYDOWN = 0x104,
				WM_SYSKEYUP = 0x105;

		const byte VK_SHIFT = 0x10,
				VK_CAPITAL = 0x14,
				VK_NUMLOCK = 0x90;

		const byte VK_LSHIFT = 0xA0,
				VK_RSHIFT = 0xA1,
				VK_LCONTROL = 0xA2,
				VK_RCONTROL = 0x3,
				VK_LALT = 0xA4,
				VK_RALT = 0xA5;

		/// <summary>
		/// Windows-API KBDLLHOOKSTRUCT
		/// Contains information about a low-level keyboard input event.
		/// </summary>
		[StructLayout(LayoutKind.Sequential)]
		public class KBDLLHOOKSTRUCT {
			public uint vkCode;
			public uint scanCode;
			public ExtendedKeyFlags flags;
			public uint time;
			public UIntPtr dwExtraInfo;
		}

		[Flags()]
		public enum ExtendedKeyFlags : uint {
			LLKHF_EXTENDED = 0x01,
			LLKHF_INJECTED = 0x10,
			LLKHF_ALTDOWN = 0x20,
			LLKHF_UP = 0x80,
		}

		public enum HookType : int {
			WH_JOURNALRECORD = 0,
			WH_JOURNALPLAYBACK = 1,
			WH_KEYBOARD = 2,
			WH_GETMESSAGE = 3,
			WH_CALLWNDPROC = 4,
			WH_CBT = 5,
			WH_SYSMSGFILTER = 6,
			WH_MOUSE = 7,
			WH_HARDWARE = 8,
			WH_DEBUG = 9,
			WH_SHELL = 10,
			WH_FOREGROUNDIDLE = 11,
			WH_CALLWNDPROCRET = 12,
			WH_KEYBOARD_LL = 13,
			WH_MOUSE_LL = 14
		}

		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int SetWindowsHookEx(HookType idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int UnhookWindowsHookEx(int idHook);

		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		private static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

		[DllImport("user32.dll")]
		private static extern int GetKeyboardState(byte[] pbKeyState);

		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		private static extern short GetKeyState(int vKey);

		[DllImport("user32.dll")]
		private static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[] lpKeyState, byte[] lpwTransKey, uint fuState);

		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		private static extern IntPtr GetModuleHandle(string lpModuleName);

		#endregion //PInvoke
	}
}

Open in new window

BlearyEyeAuthor Commented:
Hmm ... same problem this time.
ricovoxCommented:
Sorry, BlearyEye. I was hoping those corrections would help clear up the problem.

Apparently there is something wrong with the call to SetWindowsHookEx.
I will try to look into this further, but unfortunately I can't duplicate the problem you are having (even when I run in x86 mode).
I will try on a WinXP 32 bit machine later tonight.

Can you do some troubleshooting for me? See if any of the following work

1) Try to run the exe from the bin folder (outside of visual studio)

2) Try to run the exe AS ADMINISTRATOR (probably UAC is causing problems)

3) Place a breakpoint on the line that says

IntPtr hInstance = Marshal.GetHINSTANCE(typeof(KeyboardHook).Module);

Make sure that when the code goes through that line that hInstance has a value other than 0.

Then make sure that after the call to "SetWindowsHookEx", that hHook does equal 0 (just to make sure that the error is in that line).


Thanks!
BlearyEyeAuthor Commented:
Running .exe directly (outside of VS) works. How odd ...

I am running VS as admin. I've also disabled UAC.

Running from VS and setting checkpoint, hInstance = 26083328 and it bombs

Running .exe directly, attaching VS to process, hInstance = 2949120 and it succeeds
ricovoxCommented:
well I'm not surprised the hInstance is different. That will probably be different each time you run the application.

But it IS surprising that it works outside of VS but not inside. Maybe something to do with the VS2010 host. Like I said it works fine in VS2008 for me.

Anyway, are you pleased with the ability of the program to suppress Alt+Tab?

You mentioned before that you would need to write a separate program to detect when your main program is running and install the keyboard hook when it is running. But if your main program is also written in C# (or another .net language), then why don't you just put the keyboard hook logic in it and simply install the keyboard hook on startup and unhook it on close? Obviously you should do whatever you feel is best for your application. I just wanted to point out that there is no restriction in terms of which application installs the keyboard hook. It can be in your main application or wherever you want.

BTW, if the fact that it crashes during hosting is a major problem, perhaps you can ask a question about why that might happen (in a separate "question", since it is somewhat unrelated to your original question).
BlearyEyeAuthor Commented:
Yes, it works fine, thanks.
BlearyEyeAuthor Commented:
Note that ricovox sent two versions of KeyboardHook class. Be sure to use the second one.
BlearyEyeAuthor Commented:
btw, the reason I want this to run as a separate process is that the application can bomb. In that case, I want alt-tab to be automatically restored. If I do it in the application, alt-tab will be left suppressed.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.