Delphi: Qu'est-ce que L'Application.La poignée?

Qu'est-Ce que TApplication.Handle?

  • D'où vient-il?
  • Pourquoi existe-t-il?
  • et surtout: pourquoi tous les formulaires l'ont - ils comme handle de fenêtre parent?

L'aide Delphi dit:

TApplication.Poignée

Permet d'accéder au handle de la fenêtre de la forme principale (fenêtre) de l' application.

property Handle: HWND;

Description

Utiliser la poignée lors de L'appel de L'API Windows fonctions qui nécessitent une fenêtre parent gérer. Par exemple, une DLL qui affiche son propre pop-up de haut niveau windows a besoin d'une fenêtre parent afficher ses fenêtres dans le application. Utilisation de la propriété Handle fait de telles fenêtres une partie de l' l'application, de sorte qu'ils sont réduit, restauré, activé et désactivé avec l'application.

Si je me concentre sur les mots "le handle de fenêtre de la fenêtre principale de l'application", et je prends ça pour dire le poignée de fenêtre de la fenêtre principale de l'application, alors je peux comparer:

  • "le handle de fenêtre du formulaire principal de l'application", avec
  • la poignée de fenêtre du MainForm du 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?
  • quelle poignée de fenêtre Windows® est-ce?
  • Si c'est Le handle de fenêtre Windows® des Application MainForm, alors pourquoi ne le font-ils pas match?
  • Si c'est Pas le handle de la fenêtre des Application MainForm, alors qu'est-ce que c'est?
  • plus important encore: Pourquoi est-ce le propriétaire ultime parent de chaque formulaire?
  • Et le plus important: Pourquoi tout se détraque si j'essaie d'avoir un formulaire de unparented propriétaire (j'ai donc apparaître dans la barre des tâches), ou utiliser quelque chose comme IProgressDialog?

Vraiment ce que je demande est: Quelle est la logique de conception qui fait demande.Gérer existe? Si je peux comprendre le pourquoi, le comment devrait devenir évident.


Mise à jour comprendre à travers un jeu de vingt questions:

En parlant de la solution de faire apparaître une fenêtre sur la barre des tâches en faisant son propriétaire null, Peter ci-dessous en 2000 a dit :

Cela peut causer des problèmes avec les formes modales montrées à partir de formes secondaires.

Si l'utilisateur s'éloigne de l'application alors qu'un modal la forme est en place, puis de nouveau à la forme qui l'a montré, la forme modale peut se cacher derrière la forme. Il est possible de faire face à cela en s'assurant la forme modale est parente [sic; il voulait dire possédé] à la forme qui l'a montré (en utilisant params.WndParent comme ci-dessus)

, Mais ce n'est pas possible avec la norme boîtes de dialogue de l'Unité Dialogs et des exceptions , qui nécessitent plus d'efforts pour faites-les fonctionner correctement (en manipulant essentiellement Application.OnActivate, vous cherchez des formes modales apparenté à Application par GetLastActivePopup et les amener au sommet de L'ordre Z via SetWindowPos).

  • pourquoi une forme modale se retrouve-t-elle coincée derrière d'autres formes?
  • 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 des fenêtres empilées. Qu'est-ce qui a mal tourné que Windows® ne montre pas les bonnes fenêtres?

Il a également parlé de l'utilisation du Nouveau Windows extended style qui force une fenêtre à apparaître sur la barre des tâches (lorsque les règles normales pour la rendre non détenue sont insuffisantes, impraticables ou indésirables), en ajoutant le 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 alors il met en garde:

Si vous cliquez sur un bouton de la barre des tâches des formulaires secondaires alors qu'une autre application est actif cela apportera toujours tous les formulaires de demande à l'avant. Si vous Je ne veux pas qu'il y ait option

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


Dans un autre article traitant de la Application, Mike Edenfield dit que la fenêtre parent envoie d'autres la fenêtre minimise, maximise et restaure les messages :

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 évidemment, votre formulaire reçoit toujours minimize / maximize qui est envoyé au parent formulaire (la forme principale de l'application). Afin d'éviter cela, vous pouvez installer un message gestionnaire 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 va dans le PARENT forme de celui que vous voulez se comporter indépendamment du reste de l'application, de manière à éviter de transmettre le message de minimisation. Vous pouvez ajouter similaire > code pour SC_MAXIMIZE, SC_RESTORE, etc.

Comment est-ce que minimiser / maximiser / restaurer les messages pour mes fenêtres Windows® ne vont 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 "détenus" par Application? Cela ne signifie-t-il pas que rendre le propriétaire null:

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

Va supprimer Application et son Handle de fenêtre d'interférer avec mon formulaire, et Windows devrait encore une fois envoyer moi mes messages mimimize/maximize/restore?


Peut - être que si nous comparons et contrastons maintenant une application Windows "normale" fait des choses, avec la façon dont Borland a initialement conçu des applications Delphi pour faire des choses-en ce qui concerne cet objet Application et sa boucle principale.

  • qu' la solution était la résolution d'objet Application?
  • quel changement a été apporté avec les versions ultérieures de Delphi afin que ces mêmes problèmes n'existent pas?
  • le changement dans les versions ultérieures de Delphi n'a-t-il pas introduit d'autres problèmes que la conception de l'application inital a tant essayé de résoudre?
  • Comment ces nouvelles applications peuvent-elles encore fonctionner sans que L'Application ne les interfère?

De toute évidence, Borland a réalisé la faille dans leur conception initiale. Quelle était leur initiale conception, quel problème a-t-il résolu, Quel est le défaut, quel a été le re-design, et comment résout-il le problème?

47
demandé sur Ian Boyd 2010-02-05 06:16:37

3 réponses

La raison de la fenêtre de l'application a un peu d'un historique sordide. Lors du développement de Delphi 1, nous savions que nous voulions utiliser le modèle d'interface utilisateur "SDI" (windows dispersé sur tout le bureau) pour L'IDE. Nous savions aussi que Windows aspirait (et le fait toujours) à ce modèle. Cependant, nous avons également remarqué que Visual Basic à cette époque utilisait ce modèle et cela semblait bien fonctionner. Après un examen plus approfondi, nous avons constaté que VB utilisait une fenêtre de stationnement spéciale "cachée" qui était utilisée comme "propriétaire" (Windows brouille le notion de parent et de propriétaire parfois, 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ù les fenêtres contenant le menu principal étaient rarement focalisées, donc le traitement Alt-F pour le menu fichier ne fonctionnerait tout simplement pas. En utilisant cette fenêtre de stationnement centrale comme intermédiaire, nous pourrions plus facilement suivre et acheminer les messages vers les fenêtres appropriées.

Cet arrangement a également résolu un autre problème où normalement plusieurs fenêtres de niveau supérieur étaient entièrement indépendantes. En faisant l'application gérer le "propriétaire" de toutes ces fenêtres, ils se comporteraient tous de concert. Par exemple, vous avez peut-être remarqué que lorsque vous sélectionnez any des fenêtres d'application, all les fenêtres d'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 regroupement fonctionnel.

C'est une conséquence de l'utilisation de ce modèle. Nous aurait pu faire manuellement tout ce travail pour garder les choses droites, mais la philosophie de conception était de ne pas réinventer Windows, mais de l'exploiter là où nous le pouvions. C'est aussi pourquoi un TButton ou un TEdit est vraiment Un Bouton "utilisateur" Windows et modifier la classe et le style de la fenêtre, respectivement.

Comme Windows a évolué, Ce modèle " SDI " a commencé à tomber en disgrâce. En fait, Windows lui-même a commencé à devenir "hostile" à ce style d'application. En commençant par Windows Vista et en continuant à 7, le shell utilisateur ne semble pas bien fonctionner avec une application utilisant une fenêtre de stationnement. Nous avons donc décidé de mélanger les choses dans VCL pour éliminer la fenêtre de stationnement et déplacer sa fonction dans la forme principale. Cela a présenté plusieurs problèmes de " poulet et oeuf "par lesquels nous devons avoir la fenêtre de Stationnement disponible assez tôt dans l'initialisation de l'application afin que d'autres fenêtres puissent" s'y attacher", mais la forme principale elle-même peut ne pas être construite assez tôt. TApplication doit sauter à travers quelques cerceaux pour que cela fonctionne, et il y a eu quelques cas de bord subtils qui ont causé problème, mais la plupart des problèmes ont été résolus. Cependant, pour toute application que vous avancez, il restera en utilisant l'ancien modèle de fenêtre de stationnement.

48
répondu Allen Bauer 2010-02-05 17:55:37

Toutes les applications VCL ont une fenêtre de niveau supérieur" cachée " appelée Application. Ceci est créé automatiquement au démarrage de l'application. Entre autres choses, c'est le gestionnaire de messages windows principal pour Vcl - d'où L'Application.ProcessMessages.

Avoir la fenêtre de niveau supérieur des applications cachée provoque des choses étranges, sensiblement le menu système incomplet qui s'affiche dans la barre des tâches, et les fenêtres de clous de pouce incorrectes dans Vista. Les versions ultérieures de Delphi corrigent cela.

Cependant, toutes les fenêtres doit l'avoir en tant que parent, Windows a tendance à mieux fonctionner si c'est le cas. Cependant, tout formulaire créé avec L'Application.CreateForm l'aura comme parent, et il appartiendra également à L'objet Application. Comme ils sont détenus, ils seront libérés une fois l'Application libérée. Cela se produit dans les coulisses dans les formes.DoneApplication

11
répondu Gerry Coll 2010-02-05 04:01:57

De regarder la source dans les formulaires.pas (Delphi 2009), il semble qu'ils créent une fenêtre "maître" dans les applications win32 gui pour autoriser les appels à

  • TApplication.Réduire
  • TApplication.Restaurer
  • etc

Il semble que les messages passés au Application.Handle soient transmis comme il convient au MainForm, s'il existe. Cela permettrait à l'application pour répondre à minimiser, etc si la fenêtre principale n'a pas été créé. En modifiant la source du projet vous pouvez créer un delphi app , sans une fenêtre principale.

Dans ce cas, les méthodes TApplication fonctionneront toujours, même si vous n'avez pas créé de fenêtre principale. Je ne sais pas si je saisis tous les objectifs, mais je n'ai pas le temps de parcourir tout le code de TApplication.

Par vos questions:

  • D'Où vient-elle?, Il est le handle d'une fenêtre créée en TApplication.Create

  • Quelle poignée de windows est-ce?{[27] } une fausse fenêtre que chaque application GUI delphi nécessite dans le cadre de L'abstraction TApplication

  • C'Est le handle windows de l'application principale forme Non

  • Si ce n'est pas le handle de MainForm de l'application alors qu'est-ce que c'est? Voir ci-dessus

  • Plus important encore: pourquoi est-ce le parent ultime de chaque forme? en supposant que vous avez raison que c'est le parent ultime, je suppose que c'est le cas parce qu'il est facile de trouver toutes les formes dans votre application (énumérant le enfants de cette forme "maître").

  • Et le plus important: pourquoi tout se détraque-t-il si j'essaie de faire en sorte qu'un formulaire soit unparented je pense que parce que le formulaire "maître" caché reçoit des messages système qu'il devrait transmettre à ses enfants et/ou le mainform, mais ne peut pas trouver le formulaire unparented.

Bref, c'est mon point de vue. Vous pouvez probablement en apprendre plus en regardant la déclaration et le code TApplication dans forms.pas. La ligne de fond de quoi je vois que c'est une abstraction pratique.

Cordialement,

Ne

8
répondu Don Dickinson 2010-02-05 14:28:13