Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.10.14;
Скачать: CL | DM;

Вниз

Указатель на виртуальную функцию. Помогите.   Найти похожие ветки 

 
DevilDevil ©   (2007-08-02 12:25) [0]

Задача на самом деле шире...
Однако постепенно убирая из своего кода лишнее пришёл к следующему:


type
 TClass1 = class
   procedure AnotherVirtual; virtual;
   procedure SomeFunc; virtual;
 end;

procedure TClass1.AnotherVirtual;
begin end;

procedure TClass1.SomeFunc;
begin
 ShowMessage("это функция TClass1");
end;

function GetProc(CLS : TClass; ProcOffs : integer) : pointer;
var
 I : integer;
begin
 Result := pointer(integer(pointer(CLS)^) + ProcOffs);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
ProcOffs : integer;
P1, P2 : pointer;
begin

asm
  mov ProcOffs, VMTOFFSET TClass1.SomeFunc
end;

P1 := @TClass1.SomeFunc;  
P2 := GetProc(TClass1, ProcOffs);

{asm
   call P2
end; }

Caption := IntToStr(Integer(P1)) + "     " + IntToStr(Integer(P2));
end;


В чём собственно ошибка?
- По идее, P1 должен быть равен P2, а не равен!

Причём ProcOffs всегда вычисляется корректно, - сейчас 4; если в объявлении, функции поменять местами, то 0.

Предположение одно: ошибка в функции GetProc(). Как ни старался, всё приводило к AccesViolation.

Заранее спасибо.


 
Eraser ©   (2007-08-02 12:41) [1]


> DevilDevil ©   (02.08.07 12:25) 

не совсем точно понял, что требуется, но глянь в сторону TMethod.
например
procedure ButtonClick (Self : TButton; Sender : TButton);
begin
 ShowMessageFmt ("Нажата кнопка %s", [Sender.Caption]);
 ShowMessageFmt ("Self = %s", [Self.Name]);
end;

procedure AssignButtonClick (const Button : TButton);
var Method : TMethod;
begin
 Method.Code := @ButtonClick;
 Method.Data := Button;
 Button.OnClick := TNotifyEvent (Method);
end;


 
DevilDevil ©   (2007-08-02 12:49) [2]

это не то.

Мне нужно узнать адрес функции класса, в VMT по смещению.


 
Eraser ©   (2007-08-02 13:02) [3]


> Мне нужно узнать адрес функции класса, в VMT по смещению.

тогда возможно данная статья поможет http://rsdn.ru/article/Delphi/delphiabs.xml


 
begin...end ©   (2007-08-02 13:11) [4]


> Result := pointer(integer(pointer(CLS)^) + ProcOffs);

Result := PPointer(Integer(CLS) + ProcOffs)^

Переменная типа TClass -- это указатель на VMT. VMT -- это массив адресов виртуальных методов. Следовательно, переменная типа TClass -- это указатель на адрес первого виртуального метода.

Ошибка в том, что Вы в своей функции прибавляли смещение не к указателю на адрес метода, а к самому адресу метода (т.е. адресу начала его кода).


 
DevilDevil ©   (2007-08-02 13:15) [5]

> begin...end ©   (02.08.07 13:11) [4]

Заработало!!!

Спасибо.


 
DevilDevil ©   (2007-08-02 13:17) [6]

ещё вопрос (пользуясь случаем):

чем class function отличается от function?


 
DevilDevil ©   (2007-08-02 13:21) [7]

что себе хранят IntfTable, AutoTable, InitTable, FieldTable, MethodTable и DynamicTable ? Как получить к ним доступ ?


 
begin...end ©   (2007-08-02 13:49) [8]

> DevilDevil ©   (02.08.07 13:17) [6]

См. справку, статью "Class methods". Это метод, который может быть вызван без создания экземпляра класса. Поэтому компилятор не позволяет обращаться к полям внутри классовых методов. И ещё: в отличие от обычных методов, в которых неявный параметр Self является указателем на экземпляр класса, в классовых методах Self -- это указатель на класс (т.е. на VMT).

Кстати, вызов метода "вручную" в приведённом коде не совсем корректен. Обычно передачей Self в метод занимается компилятор, но, раз уж мы решили вызывать метод самостоятельно, то и о передаче Self теперь должны заботиться мы. Иначе, если внутри метода будут обращения к полям или вызов других динамических/виртуальных методов, будет ошибка. В данном случае (неклассовый метод с register-соглашением о вызове) перед командой CALL нужно поместить в регистр EAX указатель на созданный экземпляр класса:

var
 Obj: TClass1;
 P: Pointer;
begin
 Obj := TClass1.Create;
 try
   P := GetProc(...);
   asm
     MOV  EAX, Obj
     CALL P
   end
 finally
   Obj.Free
 end
end


 
DevilDevil ©   (2007-08-02 14:02) [9]

> begin...end ©   (02.08.07 13:49) [8]

Алексей, спасибо, по поводу Self я знаю. Просто конкретно в данном случае Self не используется. Дело не вэтом.

Меня сейчас больше интересует:
что в себе хранят IntfTable, AutoTable, InitTable, FieldTable, MethodTable и DynamicTable ? Как получить к ним доступ ?

Тема специфическая, информации по ней мало. Вот поэтому, пользуясь случаем, мне и хотелось бы поинтересоваться у настоящего Мастера.


 
DevilDevil ©   (2007-08-02 14:05) [10]

:) наверное:

var
Obj: TClass1;
P: Pointer;
begin
Obj := TClass1.Create;
try
  P := GetProc(...);
  asm
    push eax
    MOV  EAX, Obj
    CALL P
    pop eax
  end
finally
  Obj.Free
end


 
begin...end ©   (2007-08-02 14:32) [11]

> DevilDevil ©   (02.08.07 13:21) [7]

Доступ-то (для чтения) получить проще простого -- используя те же самые смещения от начала VMT. Вообще, небольшое описание VMT можно найти в справке (сделайте поиск по символам "VMT" и выберите статью "Class types").

По этим смещениям расположены указатели на сугубо служебные структуры, пользоваться которыми непосредственно вряд ли имеет смысл. Например, таблица FieldTable содержит описание published-полей класса -- их количество, имена и смещения -- и используется методом TObject.FieldAdress. DynamicTable представляет собой таблицу адресов динамических методов (эти методы отличаются от виртуальных алгоритмом поиска их адреса), и т.д.

> DevilDevil ©   (02.08.07 14:05) [10]

An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers, but can freely modify the EAX, ECX, and EDX registers.

(c) Справка, "The asm statement".


 
DevilDevil ©   (2007-08-02 15:31) [12]

:)

но мы не знаем, что содержалось в регистре eax до нашего асм-кода. Поэтому свободное использование регистров eax, edx и ecx допускается в функциях, полностью написанных на ассмеблере. Я не прав?



Страницы: 1 вся ветка

Текущий архив: 2007.10.14;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.017 c
2-1190060011
NL
2007-09-18 00:13
2007.10.14
Что подумает об этом компилятор?


4-1176294294
ujin2
2007-04-11 16:24
2007.10.14
Столбец "i/o read bytes" в Task Manager e.


4-1176573654
Dmitry_177
2007-04-14 22:00
2007.10.14
SelectDirectory в центре экрана


1-1185802057
ЮрийЛ
2007-07-30 17:27
2007.10.14
FRF to FR3


3-1181203109
Sergey13
2007-06-07 11:58
2007.10.14
Что будет при нехватке места в БД