2009-03-05 16 views
7

Tengo una aplicación que llama a otra aplicación de utilidad para establecer algunas configuraciones para un dispositivo en particular. Esa aplicación de utilidad se llama utilizando ShellExecuteEx.¿Cómo puedo hacer que una ventana de proceso hijo aparezca modal en mi proceso?

Para no confundir al usuario, sería mejor hacer la ventana de la aplicación de utilidad modal a mi ventana principal. ¿Cómo hace uno esto?

cosas I han intentado:

  1. WaitForSingleObjectEx en el proceso después de ShellExecuteEx, infinito TIMEOUT - ventana es modal, pero la aplicación principal no volver a pintar
  2. WaitForSingleObjectEx (porque está esperando a que el único objeto!) en el proceso después de ShellExecuteEx, un pequeño tiempo de espera, luego llama Peekmessage y DispatchMessage - repaint ahora funciona, pero la aplicación de utilidad ya no es "modal". La aplicación principal responde a clics del mouse, clics de botón, etc.
  3. EnableWindow (FALSE), luego haga el método # 2, luego EnableWindow (TRUE) - ¡FUNCIONA!, Pero después de esto, cambió el orden z de mi aplicación. (ahora está debajo de alguna otra ventana). ¡¿por qué?!
+0

Edición solicitada: cambio de título a "¿Cómo puedo hacer que una ventana de proceso hijo aparezca modal en mi proceso?". Su título actual no refleja la diferencia entre hacer una ventana hija modal e inyectar su ventana a otro proceso (vea SetParent()) –

Respuesta

3

La respuesta corta es que no hay forma de hacer una ventana en el hilo B modal para una ventana en el hilo A, aunque los hilos estén en el mismo proceso. Si posee el código para ambas ventanas, puede acercarse, pero en ese caso obtendrá resultados mucho mejores para el esfuerzo al poner toda su UI en un hilo.

Si intentas sugerir al usuario que la ventana de la secuencia B es modal para la cadena A, hay muchos comportamientos sutiles de orden Z y de activación que tienes que corregir (como habrás notado) para que no sufras un extraño -Valor efecto de tipo, donde está claro para el usuario que la ventana del hilo B está tratando de ser algo que no es y, por lo tanto, parece estar roto.

Para evitar eso, me gustaría tener este enfoque:

  1. El usuario hace clic en "inspección de la FDA" en la ventana principal de canner.exe. canner.exe muestra un cuadro de diálogo modal que indica que está abriendo un programa externo ("Abrir configuración de botulismo ..."). Esto desactiva la ventana principal, etc. para que el usuario sepa que se está llevando a cabo una interacción modal.
  2. canner.exe llama al ShellExecuteEx() para iniciar botulism.exe.
  3. canner.exe llama a WaitForInputIdle() en el identificador devuelto por ShellExecuteEx(). WaitForInputIdle() volverá (aproximadamente, pero normalmente lo suficientemente cerca) cuando botulsim.exe esté listo para la interacción del usuario. Si botulism.exe normalmente demora cinco segundos o más para mostrar su UI, puedo usar un breve tiempo de espera con WaitforInputIdle() en un bucle y ocasionalmente procesar cualquier mensaje pendiente con PeekMessage()/ProcessMessage().
  4. canner.exe cambia su texto de diálogo para reflejar que está esperando que el usuario cierre botulism.exe ("Cerrar configuración de botulismo para continuar ...").
  5. canner.exe llama a MsgWaitForMultipleObjects() en un bucle para esperar hasta que se cierre botulsim.exe. MsgWaitForMultipleObjects() volverá cuando se señalen los identificadores pasados ​​o cuando haya mensajes esperando en la cola del subproceso.
  6. Si el usuario hace clic en el cuadro de cierre en el cuadro de diálogo modal de canner.exe mientras canner.exe está esperando, canner.exe le indica al usuario que botulism.exe todavía se está ejecutando ("¿La configuración de Botulismo aún está abierta? ¿Continuar de todos modos?", Sí, lo sé "o" No, no he terminado "). Si se confirma, canner.exe cierra el cuadro de diálogo y cancela la inspección original de la FDA iniciada en el paso 1 y vuelve al ciclo de mensajes de la ventana principal.
  7. Cuando MsgWaitForMultipleObjects() indica que botulism.exe ha terminado, canner.exe cierra el diálogo y continúa normalmente con la inspección de la FDA inició en el paso 1.

De esta manera, si todo transcurre con normalidad y rapidez, el la interacción puede ser perfecta, pero si algo sale mal con el proceso secundario o se cambia el orden Z, etc. quedará claro por qué el proceso principal está esperando y qué debe hacer el usuario para cancelar o continuar con el proceso. tarea que comenzó.

+0

Usted omitió la intención declarada del PO. Él quiere que esto sea perfecto, quiere que las aplicaciones twp aparezcan como una sola. Esta solución expone la plomería. Usando su terminología, el usuario final no debería tener que saber sobre "botulismo.exe". – jdigital

+0

Desafortunadamente, el modelo de Windows, y ciertamente el administrador de diálogos, que es el agente normal de la modalidad, no son integrales a través de los límites del proceso. Y si tengo que hacer una costura, prefiero una costura fuerte y visible a una costura oculta que se abre si tropiezo. –

+0

Tiene razón en que no hay una manera directa/directa de hacerlo. Sin embargo, es casi ciertamente factible. La pregunta es si vale la pena los 150 puntos. generosidad para pasar el tiempo resolviendo los detalles.Eso es mucho menos que la tarifa de consultoría habitual ;-) – jdigital

0

Echemos un vistazo a su enfoque # 3, que está muy cerca de lo que desea. Sospecho que el problema es que cuando la aplicación secundaria se cierra, Windows decide que no quiere restaurar el foco a una ventana deshabilitada. Podría intentar reactivar su ventana antes de que eso ocurra, pero es probable que sea complicado (y no valga la pena el esfuerzo).

En lugar de deshabilitar la ventana directamente, intente deshabilitarla simplemente ignorando la entrada del usuario. Entonces, en lugar de llamar a EnableWindow, cambie su ciclo de mensajes para filtrar los mensajes de entrada. En particular, si

msg >= WM_KEYFIRST || msg <= WM_KEYLAST || msg >= WM_MOUSEFIRST || msg <= WM_MOUSELAST 

deseche el mensaje; de lo contrario, páselo al bucle de envío normal. Lo que estás haciendo es crear tu propia ventana deshabilitada, pero Windows no lo sabe.

4

Tiene dos cosas para simular: propiedad y modalidad.

Para simular la propiedad: Debe configurar el propietario de su nueva ventana de proceso secundario en su ventana. Esto debería aliviar cualquier problema de orden z. Aunque no sé si esto funciona desde otro proceso. Si no es así, es posible que tenga que adjuntar las colas de entrada de subprocesos y luego llamarlo. O use alguna otra técnica de inyección de código.

SetWindowLong <target window handle>, GWL_HWNDPARENT, <new owner handle> 

Para simular modalidad, creo que usted está en el camino correcto con EnableWindow y la WaitForSingleObjectEx.

+3

SetWindowLong GWL_HWNDPARENT funciona en todos los procesos, se une a las colas de entrada para usted. –

2

EnableWindow es correcto, esto es generalmente cómo lo hacen los cuadros de mensaje y otras ventanas "modales". En cuanto al cambio de zorder, puede interceptar el mensaje WM_WINDOWPOSCHANGING y establecer el indicador SWP_NOZORDER para evitar el cambio de zorder. Asegúrese de hacer esto solo mientras configura EnableWindow (false).

1

sugerencia Sólo lógica,
Tal vez usted puede crear formulario modal invisible, y de él utilizar el método 1 #.

+0

voy a intentar esto ahora. – moogs

Cuestiones relacionadas