delphi delphi-5 design-rationale

Delphi: ¿Qué es Application.Handle?



delphi-5 design-rationale (3)

¿Qué es TApplication.Handle ?

  • ¿De dónde viene?
  • ¿Por qué existe?
  • Y lo más importante: ¿por qué todos los formularios lo tienen como su manejador de ventana principal?

La ayuda de Delphi dice:

TApplication.Handle

Proporciona acceso al identificador de ventana del formulario principal (ventana) de la aplicación.

property Handle: HWND;

Descripción

Use Handle cuando llame a funciones de API de Windows que requieren un identificador de ventana principal. Por ejemplo, una DLL que muestra sus propias ventanas emergentes de nivel superior necesita una ventana principal para mostrar sus ventanas en la aplicación. El uso de la propiedad Handle hace que dichas ventanas sean parte de la aplicación, de modo que se minimicen, restauren, activen y deshabiliten con la aplicación.

Si me concentro en las palabras " el identificador de ventana del formulario principal de la aplicación ", y lo tomo como el manejador de ventana del formulario principal de la aplicación , entonces puedo comparar:

  • "el identificador de ventana de la forma principal de la aplicación", con
  • el identificador de ventana del MainForm de la Application

Pero no son los mismos:

Application.MainForm.Handle: 11473728 Application.Handle: 11079574

Entonces, ¿qué es Application.Handle ?

  • ¿De dónde viene?
  • ¿Qué manejador de ventana de Windows® es?
  • Si es el identificador de ventana de Windows® del MainForm de la Application , ¿por qué no coinciden?
  • Si no es el identificador de ventana del MainForm de la Application , ¿qué es?
  • Más importante aún: ¿por qué es el principal padre de todas las formas?
  • Y lo más importante: ¿por qué todo se descompone si trato de que un formulario no esté presente (para que pueda aparecer en la Barra de tareas), o trato de usar algo como IProgressDialog?

Realmente lo que estoy preguntando es: ¿Cuál es la lógica de diseño que hace que Application.Handle exista? Si puedo entender el por qué, cómo debería ser obvio.

Actualización Comprensión a través de un juego de veinte preguntas:

Al hablar sobre la solución de hacer aparecer una ventana en la barra de tareas al hacer que su propietario sea null , Peter Below en 2000 dijo :

Esto puede causar algunos problemas con las formas modales que se muestran en las formas secundarias.

Si el usuario se desconecta de la aplicación mientras el formulario modal está activo y vuelve al formulario que lo mostró, el formulario modal puede ocultarse debajo del formulario. Es posible tratar esto asegurándose de que el formulario modal esté emparentado con el formulario que lo mostró (usando `params.WndParent`` como se indicó anteriormente)

Pero esto no es posible con los diálogos estándar de la unidad Dialogs y las excepciones , que requieren más esfuerzo para que funcionen correctamente (básicamente manejando Application.OnActivate , buscando formularios modales para Application a través de GetLastActivePopup y llevándolos a la parte superior del Z-orden a través de SetWindowPos ).

  • ¿Por qué una forma modal termina atrapada detrás de otras formas?
  • ¿Qué mecanismo normalmente trae una forma modal al frente, y por qué no funciona aquí?
  • Windows® es responsable de mostrar las ventanas apiladas. ¿Qué salió mal de que Windows® no muestre las ventanas correctas?

También habló sobre el uso del nuevo estilo extendido de Windows que fuerza a una ventana a aparecer en la barra de tareas (cuando las reglas normales para hacerlo no propietario son insuficientes, poco prácticas o no deseables), al agregar el estilo extendido WS_EX_APPWINDOW :

procedure TForm2.CreateParams(var Params: TCreateParams); begin inherited CreateParams( params ); Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; end;

Pero luego advierte:

Si hace clic en un botón de la barra de tareas de formularios secundarios mientras otra aplicación está activa, esto todavía traerá todos los formularios de las solicitudes al frente. Si no quieres eso, hay una opción

¿Quién está llevando todos los formularios al frente cuando el propietario del formulario sigue siendo Application.Handle ? ¿La aplicación está haciendo esto? ¿Por qué está haciendo esto? En lugar de hacer esto, ¿no debería estar haciendo esto? ¿Cuál es la desventaja de no hacer esto? Veo la desventaja de hacerlo (los menús del sistema no funcionan correctamente, las miniaturas de los botones de la barra de tareas son imprecisas, el shell de Windows® no puede minimizar las ventanas.

En otra publicación que trata sobre la Application , Mike Edenfield dice que la ventana principal envía a otras ventanas su minimizar, maximizar y restaurar mensajes :

Esto agregará el botón de la barra de tareas para su formulario, pero hay algunos otros detalles menores que manejar. Lo más obvio es que su formulario aún recibe minimizar / maximizar que se envía al formulario principal (el formulario principal de la aplicación). Para evitar esto, puede instalar un controlador de mensajes para WM_SYSCOMMAND agregando una línea como:

procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND; procedure TParentForm.WMSysCommand(var Msg: TMessage); begin if Msg.wParam = SC_MINIMIZE then begin // Send child windows message, don''t // send to windows with a taskbar button. end; end;

Tenga en cuenta que este controlador va en el formulario PARENT del que desea que se comporte independientemente del resto de la aplicación, a fin de evitar transmitir el mensaje de minimizar. Puede agregar un código similar para SC_MAXIMIZE, SC_RESTORE, etc.

¿Cómo es que minimizar / maximizar / restaurar mensajes para mis ventanas de Windows® no va a mi ventana? ¿Esto se debe a que Windows® envía los mensajes destinados a una ventana al propietario de la ventana? ¿Y en este caso todos los formularios de una aplicación Delphi son "propiedad" de la Application ? ¿Eso no significa que el propietario sea nulo?

procedure TForm2.CreateParams(var Params: TCreateParams); begin inherited; Params.WndParent := 0; //NULL end;

eliminará Application y su Window Handle de interferir con mi formulario, y Windows debería enviarme mis mensajes mimimize / maximize / restore?

Quizás si comparamos y contrastamos ahora una aplicación Windows "normal" hace las cosas, con la forma en que Borland diseñó inicialmente las aplicaciones Delphi para hacer cosas, con respecto a este objeto Application y su ciclo principal.

  • ¿Qué solución solucionó el objeto Application ?
  • ¿Qué cambio se realizó con las versiones posteriores de Delphi para que estos mismos problemas no existan?
  • ¿El cambio en las versiones posteriores de Delphi no introdujo otros problemas que el diseño inicial de la aplicación intentó resolver tan difícilmente?
  • ¿Cómo pueden funcionar esas aplicaciones más nuevas sin que la Aplicación las interfiera?

Obviamente Borland se dio cuenta de la falla en su diseño inicial. ¿Cuál fue su diseño inicial, qué problema resolvió, cuál es el defecto, qué fue el rediseño y cómo lo solucionó?


Al mirar la fuente en forms.pas (Delphi 2009), parece que crean una ventana "maestra" en las aplicaciones win32 gui para permitir llamadas a

  • TApplication.Minimize
  • TApplication.Restore
  • etc

Parece que los mensajes pasados ​​a Application.Handle se reenvían según corresponda a MainForm , si existe. Esto permitiría que la aplicación responda para minimizar, etc. si la ventana principal no se ha creado. Al modificar la fuente del proyecto, puede crear una aplicación delphi sin una ventana principal.

En este caso, los métodos de TApplication seguirán funcionando, incluso si no ha creado una ventana principal. No estoy seguro de si entiendo todos los propósitos, pero no tengo tiempo para revisar todo el código de la aplicación.

Por sus preguntas:

  • ¿De dónde viene? Es el identificador de una ventana creada en TApplication.Create

  • ¿Qué ventanas manejan es? una ventana falsa que requiere cada aplicación gui delphi como parte de la abstracción de TApplication

  • ¿Es el identificador de Windows del formulario principal de la aplicación? No

  • Si no es el manejo de la forma principal de la aplicación, entonces ¿qué es? Véase más arriba

  • más importante: ¿por qué es el principal padre de todas las formas? asumiendo que tienes razón de que es el padre principal, supongo que es así porque hace que sea fácil encontrar todos los formularios en tu aplicación (enumerando los hijos de este formulario "maestro").

  • y lo más importante: ¿por qué todo se vuelve loco si trato de que un formulario no esté presente? Creo que porque el formulario oculto "maestro" está recibiendo mensajes del sistema que debería pasar a sus hijos y / o la forma principal, pero no puede encontrar la forma no registrada.

De todos modos, ese es mi punto de vista. Probablemente pueda obtener más información mirando la declaración y el código de forms.pas en forms.pas . La conclusión de lo que veo es que es una abstracción conveniente.

Atentamente,

Don


El motivo de la ventana de la aplicación tiene un poco de historia sórdida. Al desarrollar Delphi 1, sabíamos que queríamos usar el modelo de interfaz de usuario "SDI" (ventanas dispersas por todo el escritorio) para IDE. También sabíamos que Windows apestaba (y todavía lo hace) en ese modelo. Sin embargo, también notamos que Visual Basic en ese momento empleaba ese modelo y parecía funcionar bien. Tras un examen más detenido, encontramos que VB usó una ventana de estacionamiento "oculta" especial que se usó como el "propietario" (Windows difumina la noción de padre y propietario a veces, pero la distinción es similar a VCL) para todas las demás ventanas visibles .

Así es como resolvimos el "problema" donde las ventanas que contenían el menú principal rara vez se enfocaban, así que procesar Alt-F para el menú Archivo simplemente no funcionaría. Al utilizar esta ventana de estacionamiento central como intermediario, podríamos realizar un seguimiento y enrutar más fácilmente los mensajes a las ventanas apropiadas.

Esta disposición también resolvió otro problema donde normalmente múltiples ventanas de nivel superior eran completamente independientes. Al hacer que la aplicación manejara al "propietario" de todas estas ventanas, todas se comportarían en concierto. Por ejemplo, puede haber notado que cuando selecciona cualquiera de las ventanas de la aplicación, todas las ventanas de la aplicación se mueven al frente y mantienen su orden z relativa entre sí. Esto también haría que la aplicación se minimice y restaure como una agrupación funcional.

Esa es una consecuencia del uso de este modelo. Podríamos haber hecho manualmente todo este trabajo para mantener las cosas en orden, pero la filosofía del diseño era no reinventar Windows, sino aprovecharlo donde pudiéramos. Esa es también la razón por la cual un TButton o un TEdit es realmente un BUTTON de Windows "Usuario" y una clase y estilo de ventana EDIT, respectivamente.

A medida que Windows evolucionó, ese modelo "SDI" comenzó a perder popularidad. De hecho, Windows mismo comenzó a volverse "hostil" a ese estilo de aplicación. Comenzando con Windows Vista y continuando hasta 7, el shell del usuario no parece funcionar bien con una aplicación que utiliza una ventana de estacionamiento. Entonces, nos dispusimos a mezclar las cosas en VCL para eliminar la ventana de estacionamiento y mover su función a la forma principal. Esto presentó varios problemas de "huevo y gallina" por los cuales necesitamos tener la ventana de estacionamiento disponible lo suficientemente temprano en la inicialización de la aplicación para que otras ventanas puedan "adherirse" a ella, pero la forma principal en sí misma puede no construirse lo suficientemente pronto. La aplicación tiene que saltar unos pocos aros para que esto funcione, y ha habido algunos casos sutiles que han causado problemas, pero la mayoría de los problemas se han solucionado. Sin embargo, para cualquier aplicación que avance, seguirá usando el modelo anterior de ventanas de estacionamiento.


Todas las aplicaciones de VCL tienen una ventana de nivel superior "oculta" llamada Aplicación. Esto se crea automáticamente al inicio de la aplicación. Entre otras cosas, es el controlador principal de mensajes de Windows para VCL, de ahí Application.ProcessMessages.

Tener oculta la ventana del nivel superior de las aplicaciones causa algunas cosas extrañas, notablemente el menú del sistema incompleto que se muestra en la barra de tareas, y las ventanas incorrectas de la uña del pulgar en Vista. Las versiones posteriores de Delphi corrigen esto.

Sin embargo, no todas las ventanas deben tenerlo como principal, Windows simplemente tiende a funcionar mejor si es así. Sin embargo, cualquier formulario creado con Application.CreateForm lo tendrá como principal, y también será propiedad del objeto Aplicación. Como son propiedad, serán liberados una vez que se libere la aplicación. Esto sucede detrás de las escenas en Forms.DoneApplication