Implementación de Windows Normal en Delphi
Resumen En la biblioteca VCL de Delphi, para la comodidad del uso e implementación, la aplicación del objeto de aplicación crea una ventana oculta para el procesamiento de respuestas de mensajes. Es esta ventana la que hace que los programas desarrollados con VCL parezcan estar algo deformados, como no poder organizar y mosaico normalmente con otras ventanas. A través del análisis en profundidad de VCL, este artículo proporciona una solución que puede resolver el problema al modificar solo 3 líneas de código al archivo del proyecto de aplicación, sin ningún cambio en el método de programación original.
Palabra clave VCL, ventana normal, normalización
1 Introducción
Las aplicaciones de Windows escritas en la biblioteca de clases VCL proporcionada por Delphi tienen una característica distinta que obviamente es diferente de la ventana de Windows estándar: el menú del sistema de la ventana principal es diferente del menú del sistema en la barra de tareas. En términos generales, el menú del sistema en la ventana principal tiene seis elementos del menú, mientras que el menú del sistema de la barra de tareas tiene solo tres elementos del menú. En uso real, encontramos que los programas desarrollados con VCL tienen la siguiente vergüenza:
1) No es lo suficientemente hermoso. Esto es cierto, si no coincide con los estándares, naturalmente aparecerá un poco deformado.
2) No hay efecto de animación cuando se minimiza la ventana principal.
3) La ventana no se puede organizar y los mosaicos normalmente con otras ventanas.
4) El menú del sistema de la barra de tareas tiene la más alta prioridad. En presencia de una ventana modal, todo el programa aún se puede minimizar, contrario al diseño de la ventana modal.
El problema de minimizar los efectos de animación en la ventana principal ha sido resuelta por la función showwinnoanimado en las formaciones. Aunque esto no tendrá ningún impacto en la aplicación en la mayoría de los casos, es inaceptable en algunas situaciones donde se persiguen los efectos profesionales. Dado que C ++ Builder y Delphi usan el mismo conjunto de bibliotecas de clase, los problemas anteriores también existen en las aplicaciones de Windows escritas con C ++ Builder.
He discutido este tema en artículos anteriores (se puede encontrar en la casa de Forrest Gump), y la narración en ese momento parecía básicamente un truco, y encontré ese método por casualidad. La tarea de este artículo es analizar la biblioteca de clases VCL para explicar el principio de hacer esto, y luego dar un método que solo use 3 líneas de código para resolver completamente el problema de esta "ventana anormal" en Delphi.
2 Principios
2.1 Proceso de creación de aplicaciones
Aquí hay una aplicación típica del proyecto del proyecto Delphi.
Proyecto del programa1 ;
usos
Formularios,
Unidad1 en 'unit1.pas' {form1};
{$ R *.res}
Comenzar
Aplicación.initialize;
Application.CreateForm (TForm1, Form1);
Aplicación.run;
fin .
La ventana oculta es creada por el objeto de aplicación, entonces, entonces, ¿de dónde proviene el objeto de aplicación? Mantenga presionada CTRL en la ventana de edición de código de Delphi y haga clic en la aplicación, encontrará que el objeto de aplicación es uno de varios objetos globales definidos en la unidad form.pas. Esto no es suficiente, lo que queremos saber es dónde se creó el objeto de aplicación, porque una instancia de la clase de Tapplication debe crearse con éxito antes de que podamos referirnos a él.
Piénselo, ¿hay algún código que se ejecute antes de la aplicación. Por cierto, es el código en el segmento de código de inicialización. Después de depurar cuidadosamente el código fuente de VCL, puede saber que muchas unidades en VCL tienen segmentos de código de inicialización. Todas las acciones de inicialización.
Buscando en el directorio de código fuente de VCL con la palabra clave "Tapplication.create", encontramos el código para crear el objeto de aplicación en la unidad Controls.pas. En el segmento de código de inicialización de la unidad Controls.pas, hay una llamada al procedimiento de initControls, y la implementación de initControls es la siguiente:
Controles de la unidad ;
…
Inicialización
...
InitControls;
procedimiento initControls;
Comenzar
...
Mouse: = tmouse.create;
Pantalla: = tscreen.create ( nil );
Aplicación: = TAPPLICATION.Create ( nil );
...
fin ;
Ok, en este punto, nuestro análisis ha completado el primer paso, porque para resolver el problema de las ventanas anormales, debemos hacer una cosa antes de inicializar el objeto de aplicación, por lo que es muy importante comprender el proceso de inicialización de la aplicación.
2.2 variables islibrary
La variable islibrary es una de las variables de indicador global definidas en la unidad System.PAS. Si el valor de IsLibrary es verdadero, significa que el módulo del programa es una biblioteca de enlaces dinámicos, de lo contrario es un programa ejecutable. Algunos procesos en la biblioteca de clases VCL completan diferentes acciones basadas en diferentes valores de esta variable de indicador. Es decir, esta variable juega un papel clave en la resolución del problema anormal de la ventana de Delphi.
Como se mencionó anteriormente, por conveniencia, se creó una ventana invisible cuando se inicializó el objeto de aplicación (es decir, la ventana con "Tapplication" como el nombre de clase visto con herramientas como Spy ++), pero también se debe a esta invisible la ventana que hace la ventana. Los programas desarrollados con Delphi muestran muchas anormalidades. Ok, si podemos eliminar esta ventana invisible (y eliminar el menú del sistema de la barra de tareas al mismo tiempo) y reemplazarlo con nuestra ventana principal de aplicación, ¿no se resolverían todos los problemas?
Es simple decirlo, pero ¿requiere una cirugía mayor para implementar el código fuente de VCL? ¿No sería un poco poner el carro delante del caballo? Por supuesto, la respuesta es no, de lo contrario, este artículo no habría estado disponible. Lo que quiero decir aquí es que en el próximo análisis, veremos que el llamado "la forma de programación se encuentra en una sola mente", la práctica de la siembra de sauce involuntaria en el diseño de Tapplication en realidad nos deja con la solución a este problema . Si no realiza el análisis del código fuente, es posible que tenga que ir en círculos, pero de hecho veremos que el diseño genio no nos deja sin más o menos, justo.
Abra la creación del constructor de la clase Tapplication y encontraremos tal línea de código.
constructor tapplication.create (Alowner: tcomponent);
Comenzar
...
Si no es islibrary , creehandle;
...
fin ;
Lo que se dice aquí es que si el módulo del programa no es una biblioteca de enlaces dinámico, ejecute CreateHandle, y el trabajo realizado por CreateHandle es el siguiente en la ayuda: "Si no hay una ventana de aplicación, cree un programa de aplicación", aquí " Ventana "es la ventana invisible mencionada anteriormente, que es el culpable. En la clase de Tapplication, la variable fhandle se usa para guardar su mango de ventana. Esto es para completar diferentes acciones de acuerdo con el valor de Islibrary, porque en las bibliotecas de enlaces dinámicos, los bucles de mensajes generalmente no son necesarios, pero para usar objetos de aplicación para desarrollar bibliotecas de enlaces dinámicos con VCL, por lo que aquí está el diseño. Ok, solo necesitamos engañar al objeto de aplicación, asignar islibrary a True antes de que se cree, y filtrar la ejecución de CreateHandle y eliminar esta molesta ventana.
El código asignado a Islibrary obviamente debe colocarse en el segmento de código de inicialización de una determinada unidad. El objeto de aplicación se crea, en el archivo del proyecto, debemos colocar la unidad que contiene el código de asignación antes de la unidad de formularios, de la siguiente manera (suponiendo que la unidad se denomina unitdllexe.pas):
plantilla de programa ;
usos
Unitdllexe en 'unitdllexe.pas',
Formularios,
Formmain en 'formmain.pas' {mainform},
...
La lista de códigos unitdllexe.pas es la siguiente:
Unidad unitdllexe;
interfaz
Implementación
Inicialización
Islibrary: = verdadero;
// Dígale al objeto Applciation que esta es una biblioteca de enlaces dinámicos y que no necesita crear ventanas ocultas.
fin .
Bien, compilarlo y ejecutarlo. Windows. Pero el problema es que la ventana no se puede minimizar. ¿Qué está sucediendo? Sigue siendo la antigua forma, síguelo.
2.3 Minimización de la ventana principal
La minimización pertenece a los comandos del sistema y, en última instancia, debe llamarse la función API DefwindowProc para minimizar la ventana, por lo que encontramos que la función WMSYSCOMMAND en tcustomform que responde al mensaje WM_SYSCOMMAND sin ninguna dificultad, lo que claramente redirige el mensaje minimizado a la aplicación .WNDProc para manejar:
procedimiento tcustomform.wmsysCommand (mensaje var : twmsysCommand);
Comenzar
con mensaje hacer
Comenzar
if (cmdtype y $ fff0 = sc_minimize) y (application.mainform = self) entonces
Application.WNDProc (TMessage (Mensaje))
...
fin ;
fin ;
En Application.WNDProc, se llama al método de minimización de aplicación en respuesta al mensaje minimizado, por lo que el quid del problema debe estar en el proceso de minimización.
procedimiento TAPPLICATION.WNDPROC (Mensaje var : TMessage);
...
Comenzar
...
con mensaje hacer
Mensaje de caso de
WM_SYSCOMMAND:
Case Wparam y $ FFF0 de
Sc_minimize: minimizar;
Sc_restore: restaurar;
demás
Por defecto;
...
fin ;
Finalmente, encuentre Tapplication. Minimice y lo comprenderá todo. La llamada a la función defwindowproc aquí no produce ningún efecto, ¿por qué? Dado que engañamos el objeto de aplicación antes, filtramos la llamada de CreateHandle y no creamos la ventana necesaria para responder al mensaje del objeto de aplicación, el mango fhandle es 0 y, por supuesto, la llamada no tiene éxito. Si puede señalar fhandle a nuestra ventana de aplicación principal, resolverá el problema.
procedimiento TAPPLICACIÓN. Minimizar;
Comenzar
...
Defwindowproc (fhandle, wm_syscommand, sc_minimize, 0);
// El valor fhandle aquí es 0
...
fin ;
3 implementación
El diseño involuntario de los genios de Borland una vez más nos permitió resolver el problema. Del análisis anterior, sabemos que en la biblioteca de enlaces dinámicos desarrollados con VCL, no hay una ventana oculta para recibir mensajes de Windows (CrearHandle no se ejecuta), pero en la biblioteca de enlaces dinámicos, si desea mostrar la ventana, necesita una ventana de los padres. ¿Cómo resolver este problema? El diseñador de VCL diseña la variable FHANDLE que contiene los manijas de la ventana invisible como escritura, por lo que en realidad podemos simplemente asignar un valor a fhandle para proporcionar una ventana principal para la ventana infantil que debe mostrarse. Por ejemplo, en un complemento de la biblioteca de enlaces dinámicos para mostrar un formulario, generalmente pasamos el mango del objeto de aplicación a través de una función de la biblioteca de enlaces dinámicos en el archivo ejecutable del módulo principal y lo asignamos a la aplicación.handle de la dinámica Biblioteca de enlace en el archivo ejecutable del módulo principal y asignarla a la aplicación. Handle de la biblioteca de enlace dinámico en la aplicación.
Procedimiento SetApplicationHandle (MainAppwnd: HWND)
Comenzar
Application.Handle: = MainAppWnd;
fin ;
OK, dado que Aplication.Handle es en realidad solo un mango de la ventana que se usa internamente para responder a los mensajes, y la ventana invisible que debería haber sido creada ha sido eliminada por nosotros, solo necesitamos dar un mango de ventana para reemplazar eso ¿Es suficiente ocultar el mango de la ventana innecesaria originalmente? ¿Dónde puedo encontrar esa ventana? La ventana principal de la aplicación es la mejor opción, por lo que el siguiente código está disponible.
plantilla de programa ;
usos
Unitdllexe en 'unitdllexe.pas',
Formularios,
FormMain en 'FormMain.pas' {mainform};
{$ R *.res}
Comenzar
Aplicación.initialize;
Application.CreateForm (tFormMain, FormMain);
Application.Handle: = FormMain.handle;
Aplicación.run;
fin .
Entonces, todos los problemas fueron resueltos. No necesita hacer ninguna modificación al código fuente de VCL, y no necesita hacer ninguna modificación al programa original. De tres líneas de código para hacer que su ventana de aplicación sea exactamente tan normal como cualquier ventana estándar de Windows.
1) La barra de tareas y la barra de título de la ventana tienen menús de sistema consistentes.
2) Hay un efecto de animación cuando se minimiza la ventana principal.
3) La ventana se puede organizar y amortiguar normalmente con otras ventanas.
4) Cuando hay una ventana modal, no puede funcionar en su ventana principal.
El código de implementación anterior se utiliza en todas las versiones de Delphi.