c++ - WaitForInputIdle no funciona para iniciar mspaint mediante programación
winapi mfc (1)
WaitForInputIdle funciona, pero no de la forma en que supone que lo hace. Esto se debe principalmente a que la documentación es engañosa (o al menos no tan explícita como debería ser):
Espera hasta que el proceso especificado haya terminado de procesar su entrada inicial y esté esperando la entrada del usuario sin ninguna entrada pendiente, o hasta que haya transcurrido el intervalo de tiempo de espera.
Esto es casi criminalmente inexacto.
Si bien la sección de
Observaciones
señala que
WaitForInputIdle
espera como máximo una vez por proceso, nunca menciona detalles significativos.
Específicamente:
-
WaitForInputIdle
regresa, tan pronto como el inicio inicial ha llegado a un punto, donde cualquier hilo en el proceso está listo para procesar mensajes. Esos mensajes no necesitan ser ingresados por el usuario. -
WaitForInputIdle
se inventó para permitir que un proceso se comunique con un proceso secundario mediante un protocolo basado en mensajes. El escenario específico abordado fue DDE , que nadie 1) usa más.
WaitForInputIdle
no se puede usar como una solución confiable a su problema: Esperar a que aparezca la interfaz de usuario de un proceso secundario.
Realmente debes esperar a que aparezca la interfaz de usuario.
El sistema ofrece dos soluciones que puede usar:
-
Un
HCBT_CREATEWND
CBT global y espere laHCBT_CREATEWND
llamadaHCBT_CREATEWND
. Puede inspeccionar los CREATESTRUCT lpszClass y / o lpszName de CREATESTRUCT para filtrar la ventana que le interesa. -
Use
WinEvents
y responda al
event
EVENT_OBJECT_CREATE
.
Se llama al gancho CBT global, cada vez que se va a crear una ventana.
Las estructuras de kernel a las que hace referencia
HWND
se han poblado por completo, pero el cliente que llama a
CreateWindow[Ex]
aún puede finalizar la creación de la ventana.
Por el contrario, el WinEvent se emite, después de que la ventana se ha construido completamente, y está lista para la interacción.
En general, se usa una solución basada en un enlace CBT, cuando una aplicación necesita actualizar ciertos aspectos de una ventana antes de que la persona que llama a
CreateWindowEx
vea el
HWND
por primera vez.
WinEvents, en cambio, suele ser la herramienta de elección cuando se implementan soluciones de accesibilidad o automatización de la interfaz de usuario.
Recursos adicionales:
- WaitForInputIdle realmente debería llamarse WaitForProcessStartupComplete
- WaitForInputIdle espera cualquier hilo, que podría no ser el hilo que le interesa
1) Sí, lo sé, algunas aplicaciones aún pueden usar DDE. Pero si Raymond Chen sugirió en 2007, que deberíamos sentirnos libres de dejar de usar DDE , lo pasaré como una guía autorizada.
Estoy tratando de abrir "mspaint" y encontrar el identificador justo después de que se haya inicializado.
Pero
FindWindow
devuelve
NULL
si llamo
WaitForInputIdle
.
Si intento usar la función
Sleep(1000)
funciona.
Pero no creo que sea una forma correcta de esperar a que el programa esté listo.
¿Hay una solución para este código?
CString strWindowDirectory;
GetSystemDirectory(strWindowDirectory.GetBuffer(MAX_PATH), MAX_PATH);
SHELLEXECUTEINFO sei = { 0 };
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = L"open";
sei.lpFile = L"mspaint";
sei.lpDirectory = strWindowDirectory;
sei.nShow = SW_SHOWNORMAL;
HWND hPaint = NULL;
if(ShellExecuteEx(&sei))
{
int r = ::WaitForInputIdle(sei.hProcess, INFINITE);
ATLTRACE(L"WaitForInputIdle %d/n", r);
if (sei.hProcess == NULL) return;
hPaint = ::FindWindow(L"MSPaintApp", NULL);
ATLTRACE(L"Handle %d/n", hPaint);
if (!hPaint) return;
}
else
{
MessageBox(L"Couldn''t find mspaint program");
return;
}