Форум: "Основная";
Текущий архив: 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