none
Prevent user from switching to other windows RRS feed

  • Question

  • I want to allow my user to work with only a few predefined list of applications during a certain time. I'm using a C# Windows Service that will run in the background and check the active window during a specific time period to verify that the active application is in the list of allowed apps. I have done some homework and it looks like I need to capture "window switch" event through SetWinEventHook() and then call SwitchToThisWindow() or SetActiveWindow() to switch back in case the new window is not allowed. But this doesn't really work. I'm still able to switch to other windows. What am I doing wrong, or even if I'm taking the correct approach?
    Wednesday, February 1, 2012 6:41 AM

Answers


  • OK. Yes, you could use SetWinEventHook() resp. UnhookWinEvent() to do something like: 

    static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
        if (eventType == EVENT_SYSTEM_FOREGROUND) {
            if(hwnd != ApplicationForm.Handle) {
                ActivateApplication();
            }
        }
    }
    

    And you also could use AttachThreadInput() to attach the input processing mechanism of "unwanted" threads to that of your application's thread.

    But I also have another suggestion for you. You could switch to a new (empty) desktop when the windows switch denial condition is met. You can find a downloadable demo here:

    http://stackoverflow.com/questions/1170738/how-to-make-form-system-modal-using-c

    Warning: the stackoverflow code disables the task manager by writing a value of "DisableTaskMgr" = 1 to the HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System key. To enable it back simply delete the value. But since source code is available, you can also modify LockForm.cs and delete/change the locking code.

    Marcel

     

    • Edited by Marcel Roma Wednesday, February 1, 2012 3:05 PM Warning
    • Marked as answer by Paul Zhou Thursday, February 16, 2012 8:54 AM
    Wednesday, February 1, 2012 1:05 PM

All replies

  • Thanks TechMish, but as I have mentioned before, this monitoring will be in effect during a specific span of time. As user enters this time span, he may have multiple processes already running. Terminating these processes forcefully can result in data loss and other undesired side-effects. I simply want him to work with a particular application or a small set of allowed applications during this time-period. As soon as the time period ends, he'll be free to work with all apps.
    Wednesday, February 1, 2012 11:02 AM
  • Hi,

    You sure don't want to hook up every window in your system. That would incur quite some performance issues. But using a timer in your application to monitor window activation, could prove helpfull:

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    
    namespace PreventWindowSwitchDemo
    {
        public partial class Form1 : Form
        {
            Timer timer = new Timer();
            List<IntPtr> allowedWindowHandles = new List<IntPtr>();
    
            public Form1() {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e) {
                this.timer.Interval = 250;
                this.timer.Tick += OnTimerTick;
                this.allowedWindowHandles.Add(this.Handle);
            }
    
            private void OnTimerTick(object sender, EventArgs e) {
                IntPtr foregroundWindowHandle = NativeAPI.GetForegroundWindowHandle();
    
                if (!allowedWindowHandles.Contains(foregroundWindowHandle))
                    this.Activate();
            }
    
            private void checkBox1_CheckedChanged(object sender, EventArgs e) {
                timer.Enabled = checkBoxEnableTimer.Checked;
            }
        }
    
        class NativeAPI {
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            private static extern IntPtr GetForegroundWindow();
    
            public static IntPtr GetForegroundWindowHandle() {
                return GetForegroundWindow();
            }
        }
    }
    
    


     Marcel

    Wednesday, February 1, 2012 12:42 PM
  • Thanks Marcel. That's at least in the right direction. Can we capture some system-level activate/deactivate event instead of using a timer, to make it even less of a burden for the system? I'll try to mix it with SetWinEventHook() and see what happens. Let me know if you have any thoughts.

    Thanks again.

    Wednesday, February 1, 2012 12:54 PM

  • OK. Yes, you could use SetWinEventHook() resp. UnhookWinEvent() to do something like: 

    static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
        if (eventType == EVENT_SYSTEM_FOREGROUND) {
            if(hwnd != ApplicationForm.Handle) {
                ActivateApplication();
            }
        }
    }
    

    And you also could use AttachThreadInput() to attach the input processing mechanism of "unwanted" threads to that of your application's thread.

    But I also have another suggestion for you. You could switch to a new (empty) desktop when the windows switch denial condition is met. You can find a downloadable demo here:

    http://stackoverflow.com/questions/1170738/how-to-make-form-system-modal-using-c

    Warning: the stackoverflow code disables the task manager by writing a value of "DisableTaskMgr" = 1 to the HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System key. To enable it back simply delete the value. But since source code is available, you can also modify LockForm.cs and delete/change the locking code.

    Marcel

     

    • Edited by Marcel Roma Wednesday, February 1, 2012 3:05 PM Warning
    • Marked as answer by Paul Zhou Thursday, February 16, 2012 8:54 AM
    Wednesday, February 1, 2012 1:05 PM