Lock keyboard and mouse in C #, but keeping the execution of a method

3

I need to block the use of the keyboard and mouse in form while it will execute a certain function of the system, in which I am putting the call of the lock method in the event of Load of the form, in which it is actually blocking the keyboard and the mouse, but does not execute the method that is just after your call. Here is a test code I'm doing to test this:

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 System.Runtime.InteropServices;

namespace GSD
{
    public partial class FormTeste : Form
    {
        public FormTeste()
        {
            InitializeComponent();
        }

        private void FormTeste_Load(object sender, EventArgs e)
        {
            SetHookMouse();
            SetHookTeclado();

            Teste();
        }


        private void Teste()
        {
            //Implementação do método            
        }


        //------------------------------------------------------------------------------------------------------------------------------------
        //
        //Raliza o Bloqueio do Mouse
        //
        //-------------------------------------------------------------------

        // Importa as funções que serão usadas
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookExMouse(int idHook,
            LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookExMouse(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookExMouse(IntPtr idHook, int code, int wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibraryMouse(string lpFileName);

        private delegate IntPtr LowLevelMouseProc(int code, IntPtr wParam, IntPtr lParam);

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        const int WH_MOUSE_LL = 14; // Tipo de hook que será usado

        private LowLevelMouseProc hookMouse = hookProcMouse;
        private static IntPtr hhookMouse = IntPtr.Zero;

        public void SetHookMouse()
        {
            IntPtr hInstance = LoadLibraryMouse("User32");
            hhookMouse = SetWindowsHookExMouse(WH_MOUSE_LL, hookMouse, hInstance, 0); // Instala o hook para a interceptação dos eventos do mouse
        }

        public static void UnHookMouse()
        {
            UnhookWindowsHookExMouse(hhookMouse); // Remove o hook instalado
        }

        public static IntPtr hookProcMouse(int code, IntPtr wParam, IntPtr lParam)
        {
            // Se a mensagem recebida for > 0 e o clique do mouse for do botão esquerdo ou direito
            if (code >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
            {
                return (IntPtr)1; // Inibe o clique
            }
            else
                return CallNextHookExMouse(hhookMouse, code, (int)wParam, lParam); // Passa para o próximo evento
        }

        //------------------------------------------------------------------------------------------------------------------------------------
        //
        //Raliza o Bloqueio do Teclado
        //
        //-------------------------------------------------------------------

        // Importa as funções que serão usadas
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookExTeclado(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookExTeclado(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookExTeclado(IntPtr idHook, int code, int wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibraryTeclado(string lpFileName);

        private delegate IntPtr LowLevelKeyboardProc(int code, IntPtr wParam, IntPtr lParam);

        const int WH_KEYBOARD_LL = 13; // Tipo de hook que será usado
        const int WM_KEYDOWN = 0x100;  // Messagem usada para quando uma tecla for pressionada

        private LowLevelKeyboardProc hookTeclado = hookProcTeclado;
        private static IntPtr hhookTeclado = IntPtr.Zero;

        public void SetHookTeclado()
        {
            IntPtr hInstance = LoadLibraryTeclado("User32");
            hhookTeclado = SetWindowsHookExTeclado(WH_KEYBOARD_LL, hookTeclado, hInstance, 0); // Instala o hook para o teclado
        }

        public static void UnHookTeclado()
        {
            UnhookWindowsHookExTeclado(hhookTeclado);
        }

        public static IntPtr hookProcTeclado(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            { // Quando uma tecla for pressionada
                return (IntPtr)1; // Inibe o funcionamento
            }
            else
                return CallNextHookExTeclado(hhookTeclado, code, (int)wParam, lParam); // Passa para o próximo evento
        }

        private void FormTeste_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnHookMouse();

            UnHookTeclado();
        }
    }
}

I have tried to use this code as an alternative but it does not really block actually blocking the events generated by the mouse, then with a while the application starts to appear the message that the system has stopped responding. Remembering that all of these code is based on the examples that are available in: Lock keyboard and mouse or prevent user leaving window in C #

     [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            public static extern void BlockInput([In, MarshalAs(UnmanagedType.Bool)]bool fBlockIt);

  private void FormTeste_Load(object sender, EventArgs e)
            {
                BlockInput(true);

                Teste();
            }
    
asked by anonymous 18.01.2016 / 22:01

1 answer

2

Separate the execution thread from the form (thread) form of the execution thread of your method. The application hangs and looks like it is not responding because by default the form thread is used to run the events (methods) of your form. So either he updates or performs, got it?

To solve, you can simply place your method on another thread and lock the form's controls until the thread is finished. There are several ways to do this, but each has some implications.

Use a delegate for a method that runs at the end of the thread. As you may know, a delegate is a "pointer" to a method and can be called in event-driven runs. Generally, when you click a button and declare a method, when you look at the properties, it verifies that that method is "assigned" to the on_click event of the button. In fact, you have a delegate pointing to your method and this delegate is called when someone clicks.

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker(HandleThreadDone);

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone()
    {
        // As before - just a simple example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();

            Thread thread2 = new Thread(worker.Run);
            thread2.Start(HandleThreadDone);

            _count++;
        }
    }

    class ThreadWorker
    {
        // Switch to your favourite Action<T> or Func<T>
        public void Run(object state)
        {
            // Do a task

            Action completeAction = (Action)state;
            completeAction.Invoke();
        }
    }
}

Use an event. You can trigger an event at the end of a tread's work (remember the explanation above). See the example:

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();
        worker.ThreadDone += HandleThreadDone;

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone(object sender, EventArgs e)
    {
        // You should get the idea this is just an example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;

            Thread thread2 = new Thread(worker.Run);
            thread2.Start();

            _count++;
        }
    }

    class ThreadWorker
    {
        public event EventHandler ThreadDone;

        public void Run()
        {
            // Do a task

            if (ThreadDone != null)
                ThreadDone(this, EventArgs.Empty);
        }
    }
}

The differences are subtle, but, you should be able to understand the concept. In your particular case, you'll need 2 more methods, one to block form controls and one to enable controls. In the initial state, you trigger your task and block the controls and when you finish the thread, execute the method to unlock.

The screen will be updated (blocked), but will no longer display the non-responding message.

    
20.01.2016 / 06:31