Pregunta

¿Cómo puedo determinar mediante programación (en C #), si OTRA aplicación extranjera (nativa, java, .NET o lo que sea ...) exige actualmente la entrada del usuario? ¿Se puede hacer esto completamente en código administrado?

Lo que estoy buscando es la implementación de:

static Boolean IsWaitingForUserInput(String processName)
{
    ???
}

Al exigir la entrada del usuario, quiero decir cuando una aplicación le pide al usuario que ingrese algunos datos o salga de un mensaje de error (cuadros de diálogo modales) y ya no puede realizar sus tareas normales. Aquí no se entiende una aplicación de dibujo que esté esperando que el usuario dibuje algo.

PD: Después de editar para reflejar los comentarios en la parte inferior y aclarar la preocupación, algunos comentarios y respuestas pueden no ser 100% consistentes con la pregunta. Tenga esto en cuenta al evaluar las respuestas y comentarios.

¿Fue útil?

Solución

En general es imposible. Tomemos, por ejemplo, un tipo común de aplicación, un procesador de textos. Hoy en día se ejecutarán correcciones ortográficas en segundo plano, periódicamente guarda automáticamente su documento, etc. Sin embargo, desde la perspectiva de los usuarios, está esperando información todo el tiempo.

Otro caso común sería un visor de diapositivas. En cualquier momento, puede presionar una tecla para avanzar una diapositiva. Sin embargo, su usuario típico no vería esto como "esperando la entrada".

Para resumir: " esperando entrada '' es un estado subjetivo y, por lo tanto, no se puede determinar mediante programación.

Otros consejos

¿Cómo te gusta esto?

Se me ocurrió una solución que parece funcionar, notifíqueme en caso de problemas con este código para que también me beneficie con las mejoras. Funciona para Excel por lo que probé. El único problema que no me gusta es que tuve que usar llamadas no administradas. También maneja el caso cuando una aplicación se basa en un diálogo como para MFC, derivado de CDialog.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace Util
{
    public class ModalChecker
    {
        public static Boolean IsWaitingForUserInput(String processName)
        {
            Process[] processes = Process.GetProcessesByName(processName);
            if (processes.Length == 0)
                throw new Exception("No process found matching the search criteria");
            if (processes.Length > 1)
                throw new Exception("More than one process found matching the search criteria");
            // for thread safety
            ModalChecker checker = new ModalChecker(processes[0]);
            return checker.WaitingForUserInput;
        }

        #region Native Windows Stuff
        private const int WS_EX_DLGMODALFRAME = 0x00000001;
        private const int GWL_EXSTYLE = (-20);
        private delegate int EnumWindowsProc(IntPtr hWnd, int lParam);
        [DllImport("user32")]
        private extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
        [DllImport("user32", CharSet = CharSet.Auto)]
        private extern static uint GetWindowLong(IntPtr hWnd, int nIndex);
        [DllImport("user32")]
        private extern static uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
        #endregion

        // The process we want the info from
        private Process _process;
        private Boolean _waiting;

        private ModalChecker(Process process)
        {
            _process = process;
            _waiting = false; //default
        }

        private Boolean WaitingForUserInput
        {
            get
            {
                EnumWindows(new EnumWindowsProc(this.WindowEnum), 0);
                return _waiting;
            }
        }

        private int WindowEnum(IntPtr hWnd, int lParam)
        {
            if (hWnd == _process.MainWindowHandle)
                return 1;
            IntPtr processId;
            GetWindowThreadProcessId(hWnd, out processId);
            if (processId.ToInt32() != _process.Id)
                return 1;
            uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
            if ((style & WS_EX_DLGMODALFRAME) != 0)
            {
                _waiting = true;
                return 0; // stop searching further
            }
            return 1;
        }
    }
}

Si te entiendo bien, puedes intentar enumerar los hilos del proceso y verificar sus estados. El Administrador de tareas de Windows hace algo similar. Sin embargo, esto requerirá funciones de Win32 (Thread32First y Thread32Next entre otras), pero puede lograrlo con el uso más simple de P / Invoke en C #:

    [DllImport("Executor.dll")]
    public static extern bool Thread32First(IntPtr handle, IntPtr threadEntry32);

(La firma precisa puede diferir).

EDITAR: Ok, hay funciones correspondientes en la biblioteca .NET.

Si es posible, reescriba el otro código para que sea un procesador de entrada concurrente (similar al algoritmo para un servidor web concurrente):

Wait for input
Fork process
  Parent: Repeat
  Child: (Worker) handle input

Por supuesto, aún podría tener su función:

static Boolean IsWaitingForUserInput(String processName) {
    return true;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top