c++ winapi mfc atl

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:

  1. Un HCBT_CREATEWND CBT global y espere la HCBT_CREATEWND llamada HCBT_CREATEWND . Puede inspeccionar los CREATESTRUCT lpszClass y / o lpszName de CREATESTRUCT para filtrar la ventana que le interesa.
  2. 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:

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; }