Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2007.10.14;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.48 MB
Время: 0.045 c
2-1189883966
xvost
2007-09-15 23:19
2007.10.14
массивы


6-1171471733
alexm_hs
2007-02-14 19:48
2007.10.14
Отправка RARP-пакета (Send RARP).


2-1190529112
zavialov
2007-09-23 10:31
2007.10.14
Не увеличивать счетчик ссылок - создать отдельный экземпляр.


2-1189674456
alles
2007-09-13 13:07
2007.10.14
Как правильно уничтожать обьекты?


15-1189887624
wp2
2007-09-16 00:20
2007.10.14
Вот купил BlueTooth....





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский