2009-04-17 15 views
12

El archivo System.pas contiene una buena cantidad de información sobre desplazamientos VMT codificados, pero en realidad no parece decir mucho sobre la estructura del VMT. Lo que realmente me gustaría saber es, ¿hay alguna manera de averiguar el tamaño de un VMT en tiempo de ejecución, o en otras palabras, cuántos métodos virtuales existen para una clase determinada?¿Dónde puedo encontrar información sobre la estructura de Delphi VMT?

Respuesta

13

¿Qué pasa con la estructura de VMT que desea saber? También sabe que se trata de un detalle de implementación interna que está sujeto a cambios (y ha cambiado con el tiempo).

Para responder a su pregunta específica, aquí es una forma sencilla de encontrar el número de métodos virtuales para una clase dada:

function GetVirtualMethodCount(AClass: TClass): Integer; 
begin 
    Result := (PInteger(Integer(AClass) + vmtClassName)^ - 
    (Integer(AClass) + vmtParent) - SizeOf(Pointer)) div SizeOf(Pointer); 
end; 

Esto funciona porque me he enterado de que la cadena que representa el nombre de la clase se coloca siguiendo inmediatamente todos los vectores de métodos virtuales en el VMT.

También sé que hay 11 métodos virtuales (para D2009, 9 para D2007 y anteriores) en todos los TObjects que se compensan negativamente desde el puntero de VMT.

Ese es el motivo de la referencia de vmtParent.

Finalmente, al usar una referencia de clase TClass, puede pasar cualquier clase derivada TObject a esta función y obtener la cantidad de métodos virtuales.

+0

VmtEquals? Nunca había oído hablar de eso antes. ¿Es igual uno de los dos nuevos métodos virtuales en TObject para Delphi 2009? –

+0

Sí. Es necesario para que funcionen ciertas cosas relacionadas con los genéricos, creo. –

+0

Allen: ¡Eso es muy bueno! Justo lo que estaba buscando. Usted dice que la estructura puede cambiar y cambia.Entonces, ¿de qué versión (s) de Delphi funciona ese truco? –

2

Google :-P para "delphi vmt" cede this. Tal vez esto te da un comienzo.

+2

* sonrisa * ¡Me encanta Hallvard! Él es bueno en trucos como este. Desafortunadamente, él define los virtuales definidos por el usuario como una "matriz [0.999]", o en otras palabras, "más grande de lo que alguna vez necesitaría ser". Estoy buscando una manera de encontrar el tamaño real. –

1

me conecto mi propio sitio para éste:

What is the virtual-method table?

Es exacta en Delphi 2005, creo.

El VMT no tiene ningún valor que proporcione la cantidad de punteros de método virtual que contiene. Nada más que el compilador necesita saber esa información, por lo que no hay razón para grabarla para usarla en tiempo de ejecución.

9

Estaba bastante seguro de que Hallvard tenía algo en el VMT. Efectivamente, tiene Hack #8: Explicit VMT calls que hace referencia a Ray Lischner Secretos de Delphi 2 y Delphi in a Nutshell.

Aquí es su hackeado versión del VMT

type 
    PClass = ^TClass; 
    PSafeCallException = function (Self: TObject; ExceptObject: 
    TObject; ExceptAddr: Pointer): HResult; 
    PAfterConstruction = procedure (Self: TObject); 
    PBeforeDestruction = procedure (Self: TObject); 
    PDispatch   = procedure (Self: TObject; var Message); 
    PDefaultHandler = procedure (Self: TObject; var Message); 
    PNewInstance  = function (Self: TClass) : TObject; 
    PFreeInstance  = procedure (Self: TObject); 
    PDestroy   = procedure (Self: TObject; OuterMost: ShortInt); 
    PVmt = ^TVmt; 
    TVmt = packed record 
    SelfPtr   : TClass; 
    IntfTable   : Pointer; 
    AutoTable   : Pointer; 
    InitTable   : Pointer; 
    TypeInfo   : Pointer; 
    FieldTable  : Pointer; 
    MethodTable  : Pointer; 
    DynamicTable  : Pointer; 
    ClassName   : PShortString; 
    InstanceSize  : PLongint; 
    Parent   : PClass; 
    SafeCallException : PSafeCallException; 
    AfterConstruction : PAfterConstruction; 
    BeforeDestruction : PBeforeDestruction; 
    Dispatch   : PDispatch; 
    DefaultHandler : PDefaultHandler; 
    NewInstance  : PNewInstance; 
    FreeInstance  : PFreeInstance; 
    Destroy   : PDestroy; 
    {UserDefinedVirtuals: array[0..999] of procedure;} 
    end; 

Usted tendrá que leer su artículo para más información sobre el hack sin embargo.

Cuestiones relacionadas