Mantenga la ventana en la parte superior y robe el foco en WinForms

Me doy cuenta de que esto sería TOTALMENTE una mala práctica en situaciones normales, pero esto es solo para una aplicación de prueba que necesita recibir información de un escáner de código de barras (emulando un teclado). El problema es que necesito iniciar algunas secuencias de comandos durante el escaneo, por lo que necesito que la ventana recupere el foco directamente después de hacer clic en la secuencia de comandos para ejecutarla. He intentado usar Activate (), BringToFront (), Focus (), así como algunas llamadas de Win32 como SetForegroundWindow (), Setcapture () y SetActiveWindow () … sin embargo, lo mejor que puedo hacer con cualquiera de ellos es hacer que el elemento de la barra de tareas comience a parpadear para decirme que quiere tener foco, pero algo lo está deteniendo. Por cierto, estoy ejecutando esto en XP SP2 y usando .NET 2.0.

es posible?

Editar: para aclarar, estoy ejecutando las secuencias de comandos haciendo doble clic en ellas en el explorador. Así que necesito robar el foco del explorador y la aplicación de prueba.

Visibilidad

Convierta la ventana en la ventana “Top-Most”. Esta es la forma en que el Administrador de tareas puede permanecer encima de otras ventanas. Esta es una propiedad de un Form y usted crea el formulario en la parte superior (flotando sobre otras ventanas) estableciendo el valor en true .

No debería necesitar anular el comportamiento de “Ventana activa” con la configuración más alta.

Atención

Hice una pregunta similar previamente aquí en StackOverflow y la respuesta resolvería su problema. Puede hacer que la aplicación use un gancho de entrada de bajo nivel y reciba una notificación de los códigos de tecla provenientes del escáner. De esta forma, su aplicación siempre obtiene estas claves aunque la aplicación no tenga foco.

Es posible que necesite mejorar la solución para aplastar los códigos clave para que no se transmitan a la aplicación “enfocada” (por ejemplo, el bloc de notas).

Desde Windows 2000, no existe un mecanismo oficial para que una aplicación capte el foco sin la intervención directa del usuario. Mirar a través de los enrutadores de entrada a través del enganche RawInputDevices es la única forma sensata de hacerlo.

Varios artículos pueden ayudar (implementaciones de C #)

  • Artículo de RawInput en CodeProject
  • Documentación de MSDN de RawInput

Luché con un problema similar por bastante tiempo. Después de mucha experimentación y adivinanzas, así es como lo resolví:

 // Get the window to the front. this.TopMost = true; this.TopMost = false; // 'Steal' the focus. this.Activate(); 

Tuve un problema similar y encontré lo siguiente para hacer el truco. Adaptado a C # desde aquí

  // force window to have focus uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero); uint appThread = GetCurrentThreadId(); const uint SW_SHOW = 5; if (foreThread != appThread) { AttachThreadInput(foreThread, appThread, true); BringWindowToTop(form.Handle); ShowWindow(form.Handle, SW_SHOW); AttachThreadInput(foreThread, appThread, false); } else { BringWindowToTop(form.Handle); ShowWindow(form.Handle, SW_SHOW); } form.Activate(); 

EDITAR: Aquí están las definiciones de PInvoke necesarias para C #:

 [DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); // When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("kernel32.dll")] static extern uint GetCurrentThreadId(); /// The GetForegroundWindow function returns a handle to the foreground window. [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); [DllImport("user32.dll", SetLastError = true)] static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] static extern bool BringWindowToTop(HandleRef hWnd); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow); 

La forma en que me acerqué a este problema fue para generar otro hilo cuyo único propósito era asegurar que el Formulario sea TopMost y tenga enfoque en todo momento. Este código hará que todas las demás aplicaciones no se puedan utilizar mientras se está ejecutando, que es lo que necesitaba para mis aplicaciones específicas. Puede agregar un modo de suspensión en keepFocus o hacer que otro evento lo active.

 using System.Threading; // be sure to include the System.Threading namespace //Delegates for safe multi-threading. delegate void DelegateGetFocus(); private DelegateGetFocus m_getFocus; //Constructor. myForm() { m_getFocus = new DelegateGetFocus(this.getFocus); // initialise getFocus InitializeComponent(); spawnThread(keepFocus); // call spawnThread method } //Spawns a new Thread. private void spawnThread(ThreadStart ts) { try { Thread newThread = new Thread(ts); newThread.IsBackground = true; newThread.Start(); } catch(Exception e) { MessageBox.Show(e.Message, "Exception!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } //Continuously call getFocus. private void keepFocus() { while(true) { getFocus(); } } //Keeps Form on top and gives focus. private void getFocus() { //If we need to invoke this call from another thread. if (this.InvokeRequired) { try { this.Invoke(m_getFocus, new object[] { }); } catch (System.ObjectDisposedException e) { // Window was destroyed. No problem but terminate application. Application.Exit(); } } //Otherwise, we're safe. else { this.TopMost = true; this.Activate(); } } } 

Puede tratar de enfocarse en una entrada específica, o probar la propiedad .TopMost a true (y luego volver a desactivarlo).

Pero sospecho que su problema es que todos estos métodos simplemente colocan mensajes en la cola de eventos de Windows, y su progtwig tiene que esperar a que todos los eventos existentes terminen de procesarse antes de manejarlos y enfocar la aplicación.