Solved

Suppress alt-tab when app is running

Posted on 2010-11-20
20
984 Views
Last Modified: 2012-05-10
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?
0
Comment
Question by:BlearyEye
20 Comments
 
LVL 3

Assisted Solution

by:abdkhlaif
abdkhlaif earned 100 total points
ID: 34179834
0
 
LVL 44

Assisted Solution

by:AndyAinscow
AndyAinscow earned 50 total points
ID: 34179917
>>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.
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34180024
ok. I'll wait around for a while to see if anyone else weighs in.
0
 
LVL 4

Expert Comment

by:ricovox
ID: 34232212
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.
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34234303
ricovox: if you don't mind sending me your code, I'll compare it to the link that abdkhlaif sent ...
0
 
LVL 4

Accepted Solution

by:
ricovox earned 350 total points
ID: 34240742
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
0
 
LVL 4

Expert Comment

by:ricovox
ID: 34240771
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".
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34241214
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.
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34242041
Hmmm ... when I click Install Hook, I get
  Win32Exception was unhandled: The parameter is incorrect
in method Hook() ...

0
 
LVL 4

Expert Comment

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

Thanks
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 4

Expert Comment

by:ricovox
ID: 34242130
And what version of VS are you using?
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34242229
Vista 32 bit
Visual Studio 2010
0
 
LVL 4

Assisted Solution

by:ricovox
ricovox earned 350 total points
ID: 34242310
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

0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34242693
Hmm ... same problem this time.
0
 
LVL 4

Expert Comment

by:ricovox
ID: 34243437
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!
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34243808
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
0
 
LVL 4

Expert Comment

by:ricovox
ID: 34249479
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).
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34259120
Yes, it works fine, thanks.
0
 
LVL 1

Author Closing Comment

by:BlearyEye
ID: 34259155
Note that ricovox sent two versions of KeyboardHook class. Be sure to use the second one.
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34262377
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.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now