44 votes

Propriétés d'interface publiées bugs et solutions de contournement

J'ai écrit un ensemble de composants qui se connectent les uns aux autres via des propriétés d'interface publiées. Ils sont enregistrés et installés dans un package de conception.

L'utilisation de propriétés d'interface publiées n'est pas si courante en Delphi, et donc, sans grande surprise, cela ne semble pas fonctionner si bien.

Cela fonctionne bien lorsque les composants résident sur le même formulaire, cependant les liens de propriété d'interface entre les composants sur des formulaires différents posent problème.

Contrairement aux liens d'objets avec des composants sur un autre formulaire, les liens d'interface ne semblent pas être reconnus par l'IDE. Ce que je veux dire est mieux décrit par un exemple, lorsque vous avez 2 formulaires ouverts dans l'IDE, et que vous avez des liens entre les composants sur eux, alors essayer de passer à la vue formulaire en tant que texte (Alt+F12) ferait correctement remarquer à l'IDE que :

Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.

Mais si la propriété est une interface alors cela ne se produit pas, à la place le lien est rompu (et c'est le meilleur scénario lorsque vous utilisez le mécanisme de Notification pour effacer les références, sinon vous vous retrouvez avec un pointeur invalide)

Un autre problème, probablement en conséquence du même bogue, est que lorsque vous ouvrez un projet dans l'IDE, l'ordre dans lequel les formulaires seront réouverts est indéfini, donc l'IDE peut essayer d'ouvrir un formulaire qui contient des composants ayant des liens d'interface vers des composants sur un autre formulaire, mais cet autre formulaire n'est pas recréé encore. Cela aboutit donc soit à une AV soit à des liens rompus.

Retour dans les années 90 lorsque j'utilisais des Ensembles de données et des Sources de données je me souviens de problèmes similaires avec les liens entre les formulaires qui disparaissaient, donc c'est un peu similaire.

Comme solution temporaire j'ai ajouté des propriétés publiées en double, pour chaque propriété Interface j'ai ajouté une autre déclarée en tant que TComponent. Cela permet à Delphi de reconnaître qu'il y a un lien entre les formulaires, mais c'est une solution de contournement assez laide à dire le moins.

Donc je me demande s'il y a quelque chose que je peux faire pour résoudre ce problème ? C'est un bogue de l'IDE et probablement pas directement corrigible, mais peut-être puis-je remplacer quelque chose ou autrement m'insérer dans le mécanisme de streaming pour contourner plus efficacement ce bogue.

Je ne suis jamais allé aussi loin dans le mécanisme de streaming, mais je soupçonne que le mécanisme de Fixup est censé gérer cela. Il y a un csFixups TComponentState donc j'espère qu'une solution de contournement est possible.

Édit : Utilisation de D2007.

Mise à jour :

Nouvel exemple reproductible mis à jour téléchargé sur http://www.filedropper.com/fixupbugproject2

Ajouté property RéférenceComposant: TComponent pour qu'il soit facile de comparer et de tracer streaming d'interface vs composant.

J'ai limité le problème au niveau de l'assembleur qui dépasse mes compétences.

Dans la procédure GlobalFixupReferences située dans l'unité classes elle appelle :

(GetOrdProp(FInstance, FPropInfo) <> 0)

qui exécute finalement :

function TInterfacedComponent.GetInterfaceReference: IInterface;
begin
// décommentez le code ci-dessous pour éviter l'exception
{  if (csLoading in ComponentState) and (FInterfaceReference = nil) then
  // ne pas assigner de valeur à result pour éviter l'exception
  else
}
    result := FInterfaceReference; // <----- L'exception se produit ici
end;

Comme vous pouvez le voir à partir du commentaire, la seule façon que j'ai trouvée pour éviter l'exception est de ne pas attribuer de valeur au résultat, mais cela casse la fonctionnalité puisque la comparaison ci-dessus dans GlobalFixupReferences échoue en raison de GetOrdProp <> 0, ce qui rompt le lien.

En traçant plus en profondeur, l'emplacement exact de l'exception se trouve dans

procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); dans l'unité system

Cette ligne en particulier déclenche une lecture de l'adresse 0x80000000

{   Maintenant, nous sommes dans les cas moins courants.  }
@@NilSource:
        MOV     ECX, [EAX]      // obtenir la valeur actuelle

Alors, pourquoi le MOV échoue et ce qu'il ne va pas avec ECX ou EAX je n'en ai aucune idée.

5 votes

C'est une question intéressante. Cela semble un peu au-delà de mon expérience personnelle. Je soupçonne que si vous aviez un projet de démonstration, cela aiderait tout enquêteur en herbe.

1 votes

@DavidHeffernan Il est assez facile de reproduire, il vous suffit d'avoir une descendance de TComponent avec une propriété publiée de type IInterface. Enregistrez-le, installez le package et déposez-en un sur chacun des deux formulaires vierges. Cela étant dit, je pourrais le faire moi-même et vous laisser jouer avec...

1 votes

Je pense que cela aiderait si vous le faisiez. Baissez les barrières pour nous.

2voto

Daniel Maurić Points 2170

Pour résumer, le problème se produit uniquement avec les propriétés d'interface publiées qui ont une méthode getter, et la propriété pointe vers un composant sur un autre formulaire/module (et ce formulaire/module n'est pas encore recréé). Dans ce cas, la restauration du DFM du formulaire entraîne une AV.

Je suis assez sûr que le bug se trouve dans le code ASM de GetOrdProp, mais c'est au-delà de mes capacités de le corriger, donc la solution de contournement la plus simple est d'utiliser un champ au lieu d'une méthode getter et de le lire directement dans la propriété. C'est heureusement suffisant pour mon cas actuel.

Alternativement, vous pouvez déclarer la propriété comme TComponent au lieu d'une interface, puis écrire un descendant de TComponentProperty, remplacer ComponentMayBeSetTo pour filtrer les composants qui ne prennent pas en charge l'interface requise. Et bien sûr, l'enregistrer en utilisant RegisterPropertyEditor

0 votes

Y a-t-il une entrée de contrôle qualité pour cela ?

1 votes

Cela ne fait qu'entretenir le problème. Vous ne pouvez pas vous plaindre que ce n'est pas réparé s'ils n'en ont pas connaissance. Vous pouvez vous plaindre s'ils le font :) (Pas que je vous accuse de vous plaindre, mais vous comprenez ce que je veux dire.)

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