51 votes

Delphi : Qu'est-ce que Application.Handle ?

Qu'est-ce que TApplication.Handle ?

  • D'où vient-il ?
  • Pourquoi existe-t-il ?
  • Et le plus important : pourquoi tous les formulaires ont-ils cette poignée comme poignée de fenêtre parent ?

L'aide de Delphi dit :

TApplication.Handle

Permet d'accéder à la poignée de fenêtre du formulaire principal (fenêtre) de l'application l'application.

property Handle: HWND;

Description

Utilisez Handle lorsque vous appelez des fonctions de l'API Windows qui nécessitent une fenêtre parent poignée. Par exemple, une DLL qui affiche sa propre fenêtre pop-up de niveau supérieur supérieure a besoin d'une fenêtre parent pour afficher ses fenêtres dans l'application l'application. L'utilisation de la propriété Handle permet à ces fenêtres de faire partie de l'application l'application, de sorte qu'elles sont réduites, restaurées, activées et désactivées avec l'application.

Si je me concentre sur les mots " le handle de la fenêtre du formulaire principal de l'application ", et j'en déduis que cela signifie le handle de la fenêtre du formulaire principal de l'application alors je pourrai comparer :

  • "l'identifiant de la fenêtre du formulaire principal de l'application".
  • la poignée de fenêtre de la MainForm de la Application

mais ils ne sont pas les mêmes :

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

Alors, qu'est-ce que Application.Handle ?

  • D'où vient-il ?
  • De quelle poignée de fenêtre Windows® s'agit-il ?
  • Si elle es la poignée de fenêtre Windows® de la Application 's MainForm alors pourquoi ne correspondent-ils pas ?
  • Si c'est no la poignée de fenêtre de la Application 's MainForm alors qu'est-ce que c'est ?
  • Plus important encore : Pourquoi est-ce l'ultime parent propriétaire de chaque forme ?
  • Et le plus important : pourquoi tout se détraque-t-il si j'essaie de faire en sorte qu'un formulaire soit sans parents non propriétaire (pour qu'il puisse apparaître dans la barre des tâches), ou essayez d'utiliser quelque chose comme IProgressDialog ?

Ce que je demande vraiment c'est : Quel est le raisonnement de conception qui fait que Application.Handle exister ? Si je peux comprendre le pourquoi, le comment devrait devenir évident.


Mise à jour La compréhension à travers un jeu de vingt questions :

En parlant de la solution consistant à faire apparaître une fenêtre dans la barre des tâches en faisant en sorte que son propriétaire null , Peter Below a déclaré en 2000 :

Cela peut causer des problèmes avec les formulaires modaux affichés à partir de formes secondaires.

Si l'utilisateur quitte l'application pendant qu'un formulaire modal est affichée, puis revient au formulaire qui l'a affichée, le formulaire modal peut être se cacher sous le formulaire. Il est possible de résoudre ce problème en s'assurant que le formulaire modal est parenté [sic ; il voulait dire possédé] au formulaire qui l'a affiché (en utilisant params.WndParent comme ci-dessus)

Mais cela n'est pas possible avec les de l'interface Dialogs et exceptions qui nécessitent plus d'efforts pour pour qu'ils fonctionnent correctement (essentiellement la manipulation Application.OnActivate , recherche des formulaires modaux dont le parent est Application via GetLastActivePopup et les amener au sommet de l'ordre Z via SetWindowPos ).

  • Pourquoi un formulaire modal se retrouve-t-il coincé derrière d'autres formulaires ?
  • Quel mécanisme amène normalement une forme modale à l'avant, et pourquoi n'est-il pas fonctionnel ici ?
  • Windows® est responsable de l'affichage de Windows empilé. Qu'est-ce qui s'est passé pour que Windows® n'affiche pas les bonnes fenêtres ?

Il a également parlé de l'utilisation du nouveau style étendu de Windows qui force une fenêtre à apparaître dans la barre des tâches (lorsque les règles normales qui consistent à la rendre non propriétaire sont insuffisantes, peu pratiques ou indésirables), en ajoutant l'attribut WS_EX_APPWINDOW style étendu :

procedure TForm2.CreateParams(var Params: TCreateParams); 
begin 
   inherited CreateParams( params ); 

   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 
end; 

Mais il met en garde :

Si vous cliquez sur un bouton de la barre des tâches pour les formulaires secondaires alors qu'une autre application est active, tous les formulaires de l'application seront mis en avant. active, tous les formulaires de l'application seront mis en avant. Si vous ne voulez pas cela, il existe une option

Qui apporte tous les formulaires à l'avant alors que le propriétaire du formulaire est toujours Application.Handle . Est Application fait ça ? Pourquoi fait-il cela ? Plutôt que de faire ça, ne devrait-il pas no faire cela ? Quel est l'inconvénient de no faire cela ; je vois l'inconvénient de en faisant (les menus système ne fonctionnent pas correctement, les vignettes des boutons de la barre des tâches sont inexactes, le shell Windows® ne peut pas minimiser Windows.


Dans un autre billet traitant de la Application , Mike Edenfield dit que la fenêtre parent envoie aux autres fenêtres leurs messages de minimisation, d'agrandissement et de restauration. :

Cela ajoutera le bouton de la barre des tâches pour votre formulaire, mais il y a quelques autres détails mineurs à gérer. Le plus évident est que votre formulaire reçoit toujours des minimisations/maximisations qui sont envoyées au formulaire parent (le formulaire principal de l'application). (le formulaire principal de l'application). Afin d'éviter cela, vous pouvez installer un gestionnaire de message pour WM_SYSCOMMAND en ajoutant une ligne telle que :

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; 

Notez que ce gestionnaire est placé dans la section PARENT de celui que vous souhaitez voir se comporter indépendamment du > reste de l'application, afin d'éviter de transmettre le message de minimisation. Vous pouvez ajouter un code similaire pour SC_MAXIMIZE, SC_RESTORE, etc.

Comment se fait-il que les messages de minimisation/maximisation/restauration de mon Windows® ne parviennent pas à ma fenêtre ? Est-ce parce que les messages destinés à une fenêtre sont envoyés, par Windows®, au propriétaire de la fenêtre ? Et dans ce cas, tous les formulaires d'une application Delphi sont "propriétaires" de Application ? Cela ne signifie-t-il pas que rendre le propriétaire nul :

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

supprimera Application et sa poignée de fenêtre d'interférer avec mon formulaire, et Windows devrait à nouveau envoyer moi mes messages de mimimisation/maximisation/restauration ?


Peut-être que si nous comparions et contrastons la façon dont une application Windows "normale" fait les choses, avec la façon dont Borland a initialement conçu les applications Delphi pour qu'elles fassent les choses - en ce qui concerne ceci Application et sa boucle principale.

  • quelle solution était la Application la résolution d'objets ?
  • Quelles modifications ont été apportées aux versions ultérieures de Delphi pour que ces mêmes problèmes n'existent plus ?
  • Les modifications apportées aux versions ultérieures de Delphi n'ont-elles pas introduit d'autres problèmes, que la conception initiale de l'application s'efforçait de résoudre ?
  • Comment ces applications plus récentes peuvent-elles continuer à fonctionner sans que l'application n'interfère avec elles ?

Il est évident que Borland s'est rendu compte de la faille dans leur conception initiale. Quelle était leur conception initiale, quel problème résolvait-elle, quel est le défaut, quelle est la nouvelle conception, et comment résout-elle le problème ?

0 votes

Je pense que ces deux astuces vont vous intéresser : yoy.be/item.asp?i89 yoy.be/item.asp?i87

2 votes

@Stinh Sanders : j'ai vu ces méthodes, elles ne résolvent pas les problèmes. De même, ne passez jamais, jamais, jamais GetDesktopWindow en tant que propriétaire d'une fenêtre, comme le suggèrent ces messages et d'autres messages sur le sujet. En faisant cela, Windows se figeait. C'était un tel problème que Microsoft a corrigé CreateWindow, de sorte que toute personne passant GetDesktopWindow comme propriétaire doit utiliser NULL à la place. Et si je pouvais modifier ce post sur yoy.com Je le ferais.

0 votes

A Tokyo, Application.Handle est à zéro !

54voto

Allen Bauer Points 11816

La raison de la fenêtre d'application a une histoire un peu sordide. Lors du développement de Delphi 1, nous savions que nous voulions utiliser le modèle d'interface utilisateur "SDI" (Windows dispersé sur le bureau) pour l'IDE. Nous savions également que Windows était nul (et l'est toujours) pour ce modèle. Cependant, nous avons également remarqué que Visual Basic à l'époque employait ce modèle et qu'il semblait bien fonctionner. Après un examen plus approfondi, nous avons découvert que VB utilisait une fenêtre de parking spéciale "cachée" qui était utilisée comme "propriétaire" (Windows brouille parfois la notion de parent et de propriétaire, mais la distinction est similaire à VCL) pour toutes les autres fenêtres visibles.

C'est ainsi que nous avons résolu le "problème" où la fenêtre contenant le menu principal était rarement focalisée, de sorte que le traitement Alt-F pour le menu Fichier ne fonctionnait tout simplement pas. En utilisant cette fenêtre de parking centrale comme intermédiaire, nous pouvions plus facilement garder la trace des messages et les acheminer vers les fenêtres appropriées.

Cet arrangement a également permis de résoudre un autre problème : normalement, plusieurs fenêtres de niveau supérieur étaient totalement indépendantes. En faisant du gestionnaire d'application le "propriétaire" de toutes ces fenêtres, elles se comportent toutes de concert. Par exemple, vous avez peut-être remarqué que lorsque vous sélectionnez tout de l'application Windows, tous les fenêtres de l'application se déplacent vers l'avant et conservent leur ordre z les unes par rapport aux autres. Cela permettrait également à l'application de minimiser et de restaurer en tant que groupement fonctionnel.

C'est une conséquence de l'utilisation de ce modèle. Nous pourrait ont fait tout ce travail manuellement pour garder les choses en ordre, mais la philosophie de conception était de ne pas réinventer Windows, mais d'en tirer parti quand nous le pouvions. C'est également la raison pour laquelle un TButton ou un TEdit est vraiment une classe et un style de fenêtre Windows "User" BUTTON et EDIT, respectivement.

Au fur et à mesure de l'évolution de Windows, ce modèle "SDI" a commencé à tomber en disgrâce. En fait, Windows lui-même a commencé à devenir "hostile" à ce style d'application. À partir de Windows Vista et jusqu'à 7, le shell de l'utilisateur ne semble pas bien fonctionner avec une application utilisant une fenêtre de stationnement. Nous avons donc entrepris de remanier les choses dans la VCL afin d'éliminer la fenêtre de parking et de déplacer sa fonction dans le formulaire principal. Cela a posé plusieurs problèmes de "poule et d'œuf" : nous devons disposer de la fenêtre de parking suffisamment tôt dans l'initialisation de l'application pour que d'autres fenêtres puissent s'y "attacher", mais le formulaire principal lui-même peut ne pas être construit assez tôt. TApplication doit sauter à travers quelques cerceaux pour que cela fonctionne, et il y a eu quelques cas subtils qui ont causé des problèmes, mais la plupart des problèmes ont été résolus. Cependant, pour toute application que vous ferez évoluer, elle continuera à utiliser l'ancien modèle de fenêtre de parking.

1 votes

+1 pour avoir admis que c'était sordide. Et les piratages de Windows XP ajoutés à la couche de gestion des fenêtres de Microsoft ont contribué à sonner le glas de ce système, car les redoutables bogues de l'ordre Z, lorsque vous exécutez des applications Delphi 7 sur XP, ont commencé à apparaître.

0 votes

Votre explication n'est pas claire à 100%. Je comprends qu'à la fin (nouvelles versions de Delphi) le formulaire caché n'est plus créé. Je suppose que c'est la raison pour laquelle Application.Handle est maintenant égal à zéro. N'est-ce pas ?

12voto

Gerry Coll Points 4723

Toutes les applications VCL possèdent une fenêtre de niveau supérieur "cachée" appelée Application. Celle-ci est créée automatiquement au démarrage de l'application. Il s'agit, entre autres, du principal gestionnaire de messages Windows pour la VCL - d'où Application.ProcessMessages.

Le fait de masquer la fenêtre de premier niveau des applications provoque des phénomènes étranges, notamment le menu système incomplet qui s'affiche dans la barre des tâches et l'ongle de pouce incorrect de Windows dans Vista. Les versions ultérieures de Delphi corrigent ce problème.

Cependant, tous les Windows ne doivent pas l'avoir comme parent, Windows a juste tendance à mieux fonctionner si c'est le cas. Cependant, tout formulaire créé avec Application.CreateForm l'aura comme parent, et il appartiendra également à l'objet Application. Comme ils appartiennent à l'objet Application, ils seront libérés lorsque l'objet Application sera libéré. Cela se passe en coulisses dans Forms.DoneApplication.

3 votes

Les formulaires de premier niveau de votre application n'ont pas leur propriété Parent définie sur la fenêtre Application ! Seul le Propriétaire est défini sur l'objet Application. Pour clarifier : Application.ProcessMessages traite les messages de TOUTES les fenêtres dans le fil d'exécution principal (toutes les fenêtres VCL), il s'agit en fait d'une étape dans une boucle normale de traitement des messages que l'on trouve dans toutes les applications Windows GUI.

0 votes

@Ritsaert Hornstra : Quelle poignée faire les formulaires de premier niveau de mon application ont-ils pour parent ? Notez également que tous les formulaires que je crée faire ont Application.Handle comme leur parent.

0 votes

C'est probablement la raison pour laquelle saphua.com/minime/minime.aspx ne fonctionne pas correctement avec mes applications delphi (7). +1 pour cette pépite d'information.

8voto

Don Dickinson Points 4208

En regardant la source de forms.pas (Delphi 2009), il apparaît qu'ils créent une fenêtre "maître" dans les applications gui win32 pour permettre les appels à

  • TApplication.Minimize
  • TApplication.Restore
  • etc.

Il semble que les messages transmis à la Application.Handle sont transmises, le cas échéant, à l MainForm s'il existe. Cela permettrait à l'application de répondre aux minimisations, etc. si la fenêtre principale n'a pas été créée. En modifiant la source du projet, vous pouvez créer une application delphi. sin une fenêtre principale.

Dans ce cas, le TApplication fonctionneront toujours, même si vous n'avez pas créé de fenêtre principale. Je ne suis pas sûr d'avoir bien saisi tous les objectifs, mais je n'ai pas le temps de passer en revue tout le code de TApplication.

Pour vos questions :

  • D'où vient-il ? C'est le handle d'une fenêtre créée dans TApplication.Create

  • Quelle est la poignée Windows ? une fausse fenêtre que chaque application delphi gui nécessite en tant que partie de l'abstraction TApplication.

  • S'agit-il de l'identifiant Windows du formulaire principal de l'application ? Non

  • Si ce n'est pas l'identifiant du formulaire principal de l'application, qu'est-ce que c'est ? Voir ci-dessus

  • plus important : pourquoi est-il le parent ultime de toute forme ? en supposant que vous avez raison de dire que c'est le parent ultime, je suppose qu'il en est ainsi parce que cela facilite la recherche de tous les formulaires dans votre application (en énumérant les enfants de ce formulaire "maître").

  • et le plus important : pourquoi tout se détraque si j'essaie de faire en sorte qu'un formulaire ne soit pas breveté. Je pense que parce que le formulaire caché "maître" reçoit des messages du système qu'il debe à ses enfants et/ou au formulaire principal, mais ne trouve pas le formulaire non parenté.

Bref, c'est mon point de vue. Vous pouvez probablement en apprendre davantage en examinant la déclaration et le code de TApplication dans le document suivant forms.pas . L'essentiel, d'après ce que je vois, est que c'est une abstraction pratique.

Meilleures salutations,

Don

2 votes

Dans Delphi 2007, la VCL a été modifiée pour ne pas avoir de fenêtre cachée par défaut, mais vous pouvez également choisir l'ancienne méthode si cela vous aide. La fenêtre cachée empêchait l'aperçu de Windows 7 de fonctionner correctement.

0 votes

@mj2008 : avez-vous un lien pour plus d'informations à ce sujet ? Je suis en train de mettre à jour un projet de C++ Builder 2006 -> C++ Builder 2009, et je crois que je vois mon Application->Handle ptr comme NULL. Est-ce le cas maintenant dans Builder 2009 ? Et si c'est le cas, est-ce que l'utilisation de MainForm->Handle serait un bon substitut ?

0 votes

@Rob Le contrôle Delphi pour cela est Application.MainFormOnTaskbar mais je ne sais pas si cela s'applique à votre cas. En général, une application mise à jour n'a pas été modifiée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X