Comment faire en sorte que Delphi 10.2 Tokyo honore ICON_SMALL (icône de la barre de titre de la fenêtre) en plus de ICON_BIG?

Comment atteindre l’objective suivant dans Delphi 10.2 Tokyo: J’ai besoin de Delphi pour définir automatiquement non seulement la grande icône, mais aussi les grandes et petites icons pour chaque fenêtre. J’ai besoin d’une opportunité, pour certains formulaires et pour la TApplication, de changer d’icône lors de l’exécution. Je veux que cela se fasse sans modifier VCL.Forms.pas (la petite icône est celle qui apparaît dans une barre de titre de fenêtre, à gauche de la légende de la fenêtre).

Il y a une fonction dans TCustomForm :

 function GetIconHandle: HICON; 

Malheureusement, Delphi ne définit que les grandes icons, par exemple, voici une citation de VCL.Forms.pas :

  SendMessage(Handle, WM_SETICON, ICON_BIG, GetIconHandle); 

Comme vous le voyez, le code ci-dessus définit uniquement la poignée de la grande icône, mais je dois également définir la poignée de la petite icône, car les fichiers .ICO que j’utilise contiennent des images différentes pour les grandes et les petites icons.

Permettez-moi de résumer les différences entre les grandes et les petites icons, car même la documentation de Microsoft ne dit presque rien. Voici les principales différences:

  • Une petite icône est affichée dans la barre de titre de la fenêtre.

  • La grande image de l’icône est affichée dans la barre des tâches Windows (généralement située dans la partie inférieure de l’écran), si la barre des tâches est épaisse; la grande icône est également affichée lorsque vous appuyez sur Alt + Tab.

Voir https://blog.barthe.ph/2009/07/17/wmseticon/ pour plus d’informations sur les grandes et petites icons.

Delphi, en définissant uniquement le grand handle de fenêtre, supprime efficacement l’image alternative pour une icône plus petite affichée sur les titres de fenêtres. Si seule une grande icône est donnée, mais pas la petite, Windows rééchantillonne l’image de la plus grande icône à la plus petite, la qualité s’aggrave et l’idée principale d’une image plus petite et plus simple est perdue.

Voir l’exemple de courtoisie sanyok . La colonne de gauche, intitulée v7.4.16, est une capture d’écran d’un programme compilé avec un code qui définit ICON_BIG et ICON_SMALL . La colonne de droite, intitulée v7.4.16.22, est une capture d’écran du même programme qui ne définit pas explicitement les icons petites et grandes, mais assigne simplement TIcon à un formulaire, puis Delphi utilisant son code standard affecte simplement la grande icône. Ainsi, l’image de la barre de titre de Windows est redimensionnée par Windows à partir de la grande icône. Vous pouvez voir à quel point la qualité devient médiocre en raison du comportement Delphi standard.

Grand vs petites icônes

Dans le passé, je changeais le GetIconHandle dans la section interface de VCL.Forms.pas de statique en virtuel, en le changeant de function en procedure et en ajoutant deux parameters:

 procedure GetIconHandle(var Big, Small: HICON); virtual; 

Le code suivant dans le fichier VCL.Forms.pas était le suivant:

 var Big, Small: HICON; begin [...] GetIconHandle(Big, Small); SendMessage(Handle, WM_SETICON, ICON_BIG, LParam(Big)); SendMessage(Handle, WM_SETICON, ICON_SMALL, LParam(Small)); [...] 

Est-il possible d’accomplir facilement cela sans modifier le VCL.Forms.pas ?

J’ai résolu le problème dans Delphi 2007 en modifiant les unités VCL, mais je ne peux plus modifier les unités VCL dans Delphi 10.20 Tokyo pour les raisons suivantes:

  1. Les unités VCL comstacknt, mais ensuite, lorsque je comstack mon application, j’obtiens “Erreur interne: AV0047C6C7-R000004CC-0”, quelles que soient les cibles cibles (Win32 / Win64; Debug / Release), voir https: //quality.embarcadero. com / browse / RSP-18455 – la première partie du numéro d’erreur (adresse) est différente, mais la seconde – R000004CC-0 – est toujours la même.

  2. Je dois append manuellement (TObject) à chacune des classes qui n’héritent d’aucune classe; sinon, je commets une erreur que Create ou Destroy ne se trouve pas dans la classe de base. Dans les versions précédentes de Delphi, écrire simplement une class sans ancêtre l’impliquait implicitement dans TObject , mais lorsque je compilais le code à partir de la ligne de commande par dcc32 avec les dcc32 -Q -M -$D- -$M+ ligne de dcc32 dcc32 -Q -M -$D- -$M+ , Create ou Destroy n’est pas trouvé dans la classe de base.

Voici comment j’ai chargé les icons dans le passé:

 procedure LoadIconPair(var Big, Small: hIcon; AName: PChar); begin if Win32MajorVersion < 4 then begin Big := LoadIcon(hInstance, AName); Small := 0; end else begin Big := LoadImage(hInstance, AName, IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); Small := LoadImage(hInstance, AName, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); end; end; 

Ce code peut être encore amélioré: les tailles codées en dur de 32×32 et 16×16 peuvent être modifiées, comme suggéré sur https://blog.barthe.ph/2009/07/17/wmseticon/ , à GetSystemMesortingcs(SM_CXICON) , GetSystemMesortingcs(SM_CYICON) pour les grandes icons et GetSystemMesortingcs(SM_CXSMICON) et GetSystemMesortingcs(SM_CYSMICON) pour les petites icons.

Ainsi, chaque formulaire essentiellement appelé LoadIconPair , puis renvoyé les LoadIconPair via la procedure GetIconHandle(var Big, Small: HICON); override; écrasée procedure GetIconHandle(var Big, Small: HICON); override; procedure GetIconHandle(var Big, Small: HICON); override; .

Les questions sont donc les suivantes:

  1. Est-il possible de laisser Delphi définir des icons petites et grandes sans trop de soucis et sans modifier VCL.Forms.pas? (c’est la question principale) – Je dois avoir la possibilité, pour certains formulaires, et pour l’application TApp, de changer d’icône à l’exécution.

  2. Sinon, comment append une unité VCL source modifiée à votre application sous Delphi 10.2 Tokyo, où la section d’interface d’une unité est modifiée? Y a-t-il des instructions ou un guide officiel? Si quelqu’un a réussi à le faire, comment avez-vous accompli cela? Les avez-vous compilés à partir de l’IDE GUI? Ou en utilisant la ligne de commande dcc32 / dcc64? Ou en utilisant msbuild? Ou autrement? Devez-vous également append manuellement (TObject) aux classes qui n’héritent d’aucune classe pour éviter que Create ou Destroy ne se trouve dans l’erreur de classe de base?

Mise à jour n ° 1: la nouvelle configuration des icons après la définition de VCL.Forms.pas n’est pas une solution complète: nous devons également prendre en compte l’icône de l’application, et pas seulement les icons des formulaires; En plus de cela, VCL.Forms.pas définit les icons de toute façon, mais seulement le ICON_BIG , nous devons ICON_BIG les icons, cette fois en réglant à la fois les petites et les grandes. Avez-vous une idée de la façon dont nous pouvons patcher VCL.Forms.pas pour append le paramètre ICON_SMALL chaque fois qu’il définit la grande icône, alors nous ne ICON_SMALL que la section d’ implementation et appelons certains messages, même WM_USER + N pour demander l’icône gère le formulaire, et notre descendant de TForm implémentera ce gestionnaire de messages?

Update # 2: TApplication et TForm ont des interfaces similaires en ce qui concerne les icons, mais TApplication est un descendant de TComponent qui ne possède pas de handle de fenêtre et qui, respectivement, ne disposent pas de gestionnaires de messages. Ce que nous pouvons faire avec un TForm, nous ne pouvons pas faire avec TApplication.

Mise à jour n ° 3: J’ai mis en place une solution qui est un mélange de ce que kobik a suggéré dans son post et Sertac Akyuz a suggéré dans son post ultérieur . Merci également aux autres personnes qui ont consortingbué aux commentaires. J’ai compilé le programme et l’ai donné aux bêta-testeurs et ils ont confirmé que le problème avait été résolu, que l’icône avait l’air bien maintenant, et que l’animation de l’icône dans la TApplication via les icons changeantes fonctionnait également correctement. Merci à tous!

Corriger la section d’ interface des sources VCL / RTL principales de Delphi n’est pas autorisée (en théorie). Le fait que vous ayez réussi à le faire est revenu comme un boomerang maintenant. Vous pouvez dans la plupart des cas faire ce dont vous avez besoin sans patcher les sources, par exemple en utilisant l’inheritance, les aides de classe, le code des correctifs dans l’exécution, les détours et dans d’autres cas pour votre projet qui est autorisé – voir aussi How to recomstack modifications to VCL source file et How to change VCL code?

Je suggère de créer une classe de base ancêtre pour tous vos formulaires (je pense que tout projet de grande envergure devrait le faire) dans l’application et remplacer CreateWnd :

 procedure TBaseForm.CreateWnd; var Big, Small: HICON; begin inherited; if BorderStyle <> bsDialog then begin GetIconHandles(Big, Small); if Big <> 0 then SendMessage(Handle, WM_SETICON, ICON_BIG, LParam(Big)); if Small <> 0 then SendMessage(Handle, WM_SETICON, ICON_SMALL, LParam(Small)); end; end; 

Introduisez deux méthodes virtuelles :

 procedure TBaseForm.GetIconResName(var Name: ssortingng); begin Name := 'MAINICON'; end; procedure TBaseForm.GetIconHandles(var Big, Small: HICON); var ResName: ssortingng; begin Big := 0; Small := 0; GetIconResName(ResName); if ResName = '' then Exit; Big := LoadImage(HInstance, PChar(ResName), IMAGE_ICON, GetSystemMesortingcs(SM_CXICON), GetSystemMesortingcs(SM_CYICON), 0); Small := LoadImage(HInstance, PChar(ResName), IMAGE_ICON, GetSystemMesortingcs(SM_CXSMICON), GetSystemMesortingcs(SM_CYSMICON), 0); end; 

Tout ce que vous devez faire dans vos classes enfants est de remplacer le GetIconResName .

c’est à dire:

 TMyChildForm = class(TBaseForm) protected procedure GetIconResName(var Name: ssortingng); override; end; procedure TMyChildForm.GetIconResName(var Name: ssortingng); begin Name := 'SPIDERMAN'; end; 

Ce n’est pas une solution complète …

J’ai essayé de vous donner quelques pistes pour montrer que le patch de la source VCL n’est pas nécessaire.

Dans tous les cas, je n’ai aucun problème si j’utilise la propriété Icon (à la fois Application et Form) et que je fournisse une icône avec au moins 2 tailles (16×16 et 32×32) 32 bits (utilisez d’autres formats si nécessaire), Windows affichera l’icône correcte. le système affiche la grande icône dans la boîte de dialog ALT + TAB et la petite icône dans la légende de la fenêtre. même si seul ICON_BIG est envoyé au handle de la fenêtre Formulaire / Application. (Delphi7 / Win7). (C’est pourquoi j’ai demandé à MCVE, y compris des informations sur le format de vos icons, et pas seulement des fragments de code comme vous l’avez fait …)


Étant donné que je suis confus au sujet de vos exigences précises et que vous refusez toujours de fournir MCVE, je vais essayer de proposer une autre approche:

Vous dites que vous devez également gérer l’icône de l’application. l’icône Application est définie au début de la création de l’application, ce qui n’est pas simple à gérer dans vos formulaires car ils ne sont pas encore créés. mais chaque fois que l’ Application.Icon est modifié, l’application notifie les formulaires avec CM_ICONCHANGED (voir: procedure TApplication.IconChanged(Sender: TObject); ). Vous pouvez donc redéfinir l’icône de l’application dans ce gestionnaire de messages via SendMessage(Application.Handle, WM_SETICON... (cela ne déclenchera pas CM_ICONCHANGED ) ou définir directement Application.Icon (qui déclenchera également CM_ICONCHANGED ) si nécessaire. définir les grandes et petites icons via le message WM_SETICON Vous devrez également définir l’icône de la classe:

 SetClassLong(Application.Handle, GCL_HICON, FIcon); 

Donc, chaque fois que l’icône de l’application est modifiée, couvert par CM_ICONCHANGED dans vos formulaires.

 TBaseForm = class(TForm) private procedure CMIconChanged(var Message: TMessage); message CM_ICONCHANGED; ... procedure TBaseForm.CMIconChanged(var Message: TMessage); ... 

Si vous avez besoin de définir cette icône au début de votre application (ce que je ne pense pas est nécessaire), faites ce qui suit dans la création du formulaire principal uniquement.

Pour attraper / manipuler les icons Formulaires, utilisez le WM_SETICON messages WM_SETICON dans vos formulaires:

 TBaseForm = class(TForm) private procedure WMSetIcon(var Message: TWMSetIcon); message WM_SETICON; ... procedure TBaseForm.WMSetIcon(var Message: TWMSetIcon); begin if (Message.Icon <> 0) and (BorderStyle <> bsDialog) then begin // this big icon is being set by the framework if Message.BigIcon then begin // FBigIcon := LoadImage/LoadIcon... // if needed set Message.Icon to return a different big icon // Message.Icon := FBigIcon; // in practice create a virtual method to handle this section so your child forms can override it if needed inherited; FSmallIcon := LoadImage/LoadIcon... // set small icon - this will also re-sortinggger WMSetIcon Perform(WM_SETICON, ICON_SMALL, FSmallIcon); end else inherited; end else inherited; end; 

Cela devrait vous permettre de couvrir toutes les situations.

Je viens de créer une nouvelle application de formulaires VCL, de définir l’icône de l’application dans les options du projet et l’icône du formulaire (uniquement, principal) sur le même fichier, que j’avais modifié pour donner un aspect différent au 16×16 (profondeur 32 bits). code suivant:

 { TForm27 } procedure TForm27.SetIcons; var MainIcon, SmallIcon: HICON; begin MainIcon := Application.Icon.Handle; SmallIcon := Icon.Handle; Perform(WM_SETICON, ICON_BIG, MainIcon); Perform(WM_SETICON, ICON_SMALL, SmallIcon); end; procedure TForm27.FormCreate(Sender: TObject); begin SetIcons; end; 

Cela a produit l’affichage suivant:

Icône de formulaire modifié

Notez que les deux utilisent le même fichier .ico, une modification laide de ib.ico fournie avec 10.2 Tokyo. Je viens de peindre quelques lignes noires et ovales sur la petite icône uniquement .

Je ne connais pas le code de votre modification GetIconHandle, mais vous pouvez faire la même chose ici. Notez également que cela ne fonctionne pas si j’utilise (le formulaire) Icon.Handle pour les deux. Si je le fais, l’icône laide 16×16 s’affiche également dans la barre d’application.

Mais je n’ai eu à modifier aucun code VCL. Vous pouvez le faire dans n’importe quelle application VCL.

Il y a deux questions claires à la toute fin du post.

  1. Est-il possible de laisser Delphi définir des icons petites et grandes sans trop de soucis et sans modifier VCL.Forms.pas? (c’est la question principale);

Dans le contexte de la question, cela signifie vraiment demander si forcer le framework VCL lui-même, sans le modifier, pour charger différentes tailles d’icons est possible. Cela a une réponse très courte: non.

Si pris à la lettre cependant, il est possible d’utiliser Delphi pour ce faire. Les extraits de code dans votre question en sont la preuve, ce qui ne semble pas être très compliqué.

  1. Sinon, comment append une unité VCL source modifiée à votre application sous Delphi 10.2 Tokyo, où la section d’interface d’une unité est modifiée?

Très courte réponse ici aussi: impossible, vous ne pouvez pas modifier les sections d’interface des fichiers source Delphi.


Maintenant, ce qui précède est vraiment la réponse à la question. C’est tout ce qu’il y a à faire. Cependant, bien que ces informations soient disponibles dans les commentaires et qu’une réponse existe déjà, la question est toujours ouverte. Il fournit même une prime. Je dois chercher fort pour trouver ce que la question veut vraiment demander.

La question dans le titre n’est pas plus explicative que celles incluses dans le post.

Il y a une partie de mise à jour dans la deuxième question du poste:

La configuration des icons après la définition de VCL.Forms.pas ne constitue pas une solution complète.

Cela n’aide vraiment pas. Après avoir lu la mise à jour à plusieurs resockets et y avoir réfléchi; Cette mise à jour n’a aucun rapport avec ce qui a été demandé en tant que question, ou même avec les informations de base données dans le message. Et je ne sais absolument pas de quoi il parle.

En fouillant plus, je rencontre votre commentaire sur la réponse de Rudy :

… Delphi lui-même définit parfois ICON_BIG, donc dans certains scénarios complexes, vous devrez intercepter ces cas et appeler à nouveau le WM_SETICON avec ICON_BIG. …

Je suppose que le problème est le suivant. Malgré votre configuration d’icons appropriées, dans certains cas imprévus, la VCL remplace vos icons. Si ce n’est pas ce que vous souhaitez résoudre, veuillez modifier votre question pour la poser.

Je n’ai rien vu de tel, en tout cas nous n’avons pas besoin de modifier “forms.pas” pour ignorer le paramétrage de l’icône du framework. Un simple gestionnaire WM_SETICON sur le formulaire suffit, ne laissez pas le message être traité.

Alors, comment allons-nous définir l’icône? Il y a une réponse à cela sur la documentation de WM_GETICON :

.. Une fenêtre sans icône explicitement définie (avec WM_SETICON ) utilise l’icône de la classe de fenêtre enregistrée, ..

Voici donc la solution contenue dans une classe de formulaire du problème supposé:

 type TForm1 = class(TForm) protected procedure WMSetIcon(var Message: TWMSetIcon); message WM_SETICON; procedure CreateParams(var Params: TCreateParams); override; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited; Params.WindowClass.hIcon := LoadIcon(HInstance, 'ICON_1'); end; procedure TForm1.WMSetIcon(var Message: TWMSetIcon); begin end; 

Vous trouverez ci-dessous une capture d’écran du formulaire exécuté sur W7, petite icône ( entrer la description de l'image ici ) dans la légende, grande icône ( entrer la description de l'image ici ) en haut à gauche de la boîte de dialog alt + tab:

entrer la description de l'image ici

Notez que XE2 a un problème avec son gestionnaire de ressources, j’ai identifié l’icône comme “CANCEL” dans la boîte de dialog “ressources et images”, mais l’icône de l’exécutable s’est retrouvée avec “ICON_1” comme identifiant, donc j’ai dû l’utiliser dans le code.