2012-06-30 8 views
6

Al leer here,¿Cómo puedo obtener el nombre de una clase si tengo la dirección de la clase/VMT única

el VMT también contiene un número de campos “mágicas” para apoyar características como enlace de los padres de clase, tamaño de la instancia, nombre de la clase, método dinámico mesa, publicada mesa de métodos, publicada mesa de campos, mesa de RTTI, mesa de inicialización para los campos de magia, el desuso de automatización OLE tabla de despacho y las interfaces implementadas mesa

Parece que el VMT no incluye un campo que contiene el nombre de la unidad donde se define la clase. ¿Hay alguna 'magia del compilador' involucrada?

Respuesta

9

No veo por qué el VMT debería estar involucrado aquí. TObject ya expone un class function UnitName para eso.

System.TObject.UnitName

+9

Para versiones anteriores a D2009, se puede usar 'typinfo.GetTypeData (TSomeClass.ClassInfo) .UnitName' –

1

VMT incluye un puntero a la clase RTTI (proporcionada por ClassInfo método); clase RTTI incluye un nombre de unidad de clase. Como un ejercicio que puede obtener el nombre de la unidad del puntero del VMT, he escrito este (probado en Delphi XE):

uses TypInfo; 

type 
    TObj = class 

    end; 

procedure TForm1.Button3Click(Sender: TObject); 
var 
    Obj: TObj; // dummy obj instance 
    VMT: Pointer; 
    P: Pointer; // class info 

begin 
// you can get VMT pointer so 
    Obj:= TObj.Create; 
    VMT:= PPointer(Obj)^; 
    Obj.Free; 
// or so 
    VMT:= Pointer(TObj); 

    P:= PPointer(PByte(VMT) + vmtTypeInfo)^; 
    if P <> nil then 
    ShowMessage(GetTypeData(P).UnitName); 
end; 
+2

Dado que, como usted menciona, el puntero RTTI está disponible desde el método' ClassInfo', ¿por qué demuestra un rodeo tan complicado? ruta para obtener la misma información? Podría reemplazar todo ese código simplemente con 'P: = TObj.ClassInfo'. –

+0

@RobKennedy - No se puede llamar al método 'ClassInfo' directamente teniendo solo un puntero a VMT de clase desconocida. Puede intentar encasillar el puntero VMT de alguna manera, pero no he encontrado cómo hacerlo. – kludg

+4

@Serg Simplemente lanza el puntero vmt a 'TClass'. Entonces puede hacer una sola línea: 'TypInfo.GetTypeData (TClass (vmt) .ClassInfo) .UnitName' –

0
procedure MessageException(E: Exception); 
var 
    TI: TypInfo.PTypeInfo; 
begin 
    TI := E.ClassInfo; 
    if Assigned(TI) then 
    begin 
    Dialogs.MessageDlg(TypInfo.GetTypeData(TI).UnitName + '.' + 
     E.ClassName + ': ' + E.Message, Dialogs.mtError, [Dialogs.mbOK], 0, Dialogs.mbOK); 
    end 
    else 
    begin 
    Dialogs.MessageDlg(E.ClassName + ': ' + E.Message, Dialogs.mtError, [Dialogs.mbOK], 0, Dialogs.mbOK); 
    end; 
end; 

Tenga en cuenta que ClassInfo debe ser probado para nula. P.ej. SysUtils.ERangeError no lo tiene.

Cuestiones relacionadas