2017-08-20 4 views
1

Pour les décalages positifs, VMT stocke les pointeurs sur toutes les méthodes virtuelles définies par l'utilisateur.
J'ai besoin d'écrire du code pour accrocher le VMT. La façon dont je fais cela est d'obtenir un pointeur vers une méthode virtuelle dans une classe ancêtre.
Disons: TCustomForm.ShowModal. Je regarde alors le décalage dans le VMT de TCustomForm. Avec ce décalage en main je vais à TMyForm et modifie son VMT pour pointer vers la fonction dont j'ai besoin.Comment obtenir le nombre d'entrées (méthodes virtuelles) dans le VMT?

Je voudrais généraliser l'approche et, pour ce faire, je voudrais connaître le nombre total d'entrées que le VMT détient, donc je ne cherche pas après la fin.

Comment obtenir la taille de la partie (définissable par l'utilisateur) du VMT?

+1

[Où puis-je trouver des informations sur la structure du VMT Delphi?] (Https://stackoverflow.com/q/760513/576719) –

+0

Je me trompe peut-être, mais dans System.Rtti, il y a la classe TVirtualMethodInterceptor. Il y a la création de ProxyClass, cela pourrait vous aider, car il crée une copie VMT, une partie du code pourrait vous aider. Je me souviens de quelque chose comme vmtSize. – nil

+0

@LURD, cette question n'a que des réponses incorrectes à cette question comme Stephan souligne dans son commentaire à cette réponse: https://stackoverflow.com/a/761101/650492 – Johan

Répondre

0

En fouillant dans la source RTL Je pense que c'est la façon d'obtenir le nombre:

function GetVMTCount(AClass: TClass): integer; 
var 
    p: pointer; 
    VirtualMethodCount: word; 
begin 
    p := PPointer(PByte(AClass) + vmtMethodTable)^; 
    VirtualMethodCount:= PWord(p)^; 
    //Size of the VMT in bytes 
    Result:= VirtualMethodCount * SizeOf(Pointer) - vmtSelfPtr; 
    //Number of entries in the VMT 
    Result:= Result div SizeOf(Pointer); 
end; 

Ne hésitez pas à me corriger si nécessaire.

0

Une façon de le faire sans beaucoup de connaissances sur la structure VMT, et donc moins susceptible de se casser lorsque la structure VMT change à nouveau, utilise le Rtti pour cela. TRttiInstanceType connaît le VmtSize de la classe associée.

Donc, en utilisant VmtSize et une entrée VMT étant un Pointer

function GetVirtualMethodCount(AClass: TClass): Integer; 
var 
    AContext: TRttiContext; 
    AType: TRttiType; 
begin 
    AType := AContext.GetType(AClass); 
    Result := (AType as TRttiInstanceType).VmtSize div SizeOf(Pointer); 
end; 

Ce sera toutefois inclure toutes les entrées héritées de la classe de base (es) aussi. Y compris ceux de TObject à des compensations négatives. Mais il est possible de soustraire toutes les entrées d'une classe de base donnée, par ex. TObject. Voici une approche avec une classe de base variable fournie:

function GetVirtualMethodCountMinusBase(AClass: TClass; ABaseClass: TClass): Integer; 
var 
    AContext: TRttiContext; 
    AType, ABaseType: TRttiType; 
begin 
    AType := AContext.GetType(AClass); 
    ABaseType := AContext.GetType(ABaseClass); 
    Result := ((AType as TRttiInstanceType).VmtSize - (ABaseType as TRttiInstanceType).VmtSize) div SizeOf(Pointer); 
end; 

Et: Lorsque vous utilisez Jedi il y a une fonction appelée JclSysUtilsGetVirtualMethodCount. Bien que je ne sois pas sûr que ce soit à jour et correct.