Delphi asm to purepascal
Я пытаюсь перенести код Delphi 5 в Delphi XE7-WIN64 и столкнулся с проблемой смешанного кода сборки в следующем блоке. Также я новичок.
procedure IterateMenus(Func: Pointer; Menu1, Menu2: TElMenuItem);
var
I, J: Integer;
IIndex, JIndex: Byte;
Menu1Size, Menu2Size: Integer;
Done: Boolean;
function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: Pointer): Boolean;
var
Item: TMenuItem;
begin
if MenuItem = nil then Exit;
Result := False;
while not Result and (I < MenuItem.Count) do
begin
Item := MenuItem[I];
if Item.GroupIndex > IIndex then Break;
asm
MOV EAX,Item
MOV EDX,[EBP+8]
PUSH DWORD PTR [EDX]
CALL DWORD PTR AFunc
ADD ESP,4
MOV Result,AL
end;
Inc(I);
end;
end;
begin
I := 0;
J := 0;
Menu1Size := 0;
Menu2Size := 0;
if Menu1 <> nil then
Menu1Size := Menu1.Count;
if Menu2 <> nil then
Menu2Size := Menu2.Count;
Done := False;
while not Done and ((I < Menu1Size) or (J < Menu2Size)) do
begin
IIndex := High(Byte);
JIndex := High(Byte);
if (I < Menu1Size) then
IIndex := Menu1[I].GroupIndex;
if (J < Menu2Size) then
JIndex := Menu2[J].GroupIndex;
if IIndex <= JIndex then
Done := Iterate(I, Menu1, Func)
else
begin
IIndex := JIndex;
Done := Iterate(J, Menu2, Func);
end;
while (I < Menu1Size) and (Menu1[I].GroupIndex <= IIndex) do
Inc(I);
while (J < Menu2Size) and (Menu2[J].GroupIndex <= IIndex) do
Inc(J);
end;
end;
Я пытаюсь преобразовать блок asm в purepascal, поскольку delphi x64 не допускает смешанного кода, а asm не подходит для программистов.
Насколько я понимаю, адрес Item перенесен в EAX, тогда я ничего не получаю. Откуда взялся EBP? Что такое ESP и AL? Приведенный выше фрагмент кода взят из ELmenus.pas из ELPack.
Так в основном, какой будет версия PurePascal кодового блока asm?
Для func я нашел это
procedure TElMenuItem.UpdateItems;
function UpdateItem(MenuItem: TElMenuItem): Boolean;
begin
Result := False;
IterateMenus(@UpdateItem, MenuItem.FMerged, MenuItem);
MenuItem.SubItemChanged(MenuItem, MenuItem, True);
end;
begin
IterateMenus(@UpdateItem, FMerged, Self);
end;
procedure TElMenuItem.PopulateMenu;
var
MenuRightToLeft: Boolean;
function AddIn(MenuItem: TElMenuItem): Boolean;
begin
MenuItem.AppendTo(FHandle, MenuRightToLeft);
Result := False;
end;
begin // all menu items use BiDiMode of their root menu
{$ifdef VCL_4_USED}
MenuRightToLeft := (FMenu <> nil) and FMenu.IsRightToLeft;
{$else}
MenuRightToLeft := false;
{$endif}
IterateMenus(@AddIn, FMerged, Self);
end;
2 ответа
Я предполагаю, что оригинальный программист написал странный код для обхода Delphi, не поддерживающего локальные указатели функций. (Что является ограничением, которое раздражало меня время от времени.)
Следующее должно работать. (Хотя я не настолько острый в своем asm, чтобы быть уверенным. Сначала я бы протестировал код asm, пройдя через отладчик в D5, чтобы убедиться, что строка CALL DWORD PTR AFunc
передает значения, которые я ожидаю.)
1) Удалите указатель типа функции и переместите элемент UpdateItem, чтобы он больше не был локальным.
type
TMenuOperation = function (AMenuItem: TElMenuItem): Boolean;
//Or if you want to move the UpdateItem to a method of a class..
//TMenuOperation = function (AMenuItem: TElMenuItem): Boolean of object;
2) Внесите следующие изменения:
procedure IterateMenus(Func: Pointer; Menu1, Menu2: TElMenuItem);
//becomes
procedure IterateMenus(Func: TMenuOperation; Menu1, Menu2: TElMenuItem);
//...
function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: Pointer): Boolean;
var
Item: TMenuItem;
//becomes
function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: TMenuOperation): Boolean;
var
Item: TElMenuItem;
//...
Item := MenuItem[I];
//becomes
Item := MenuItem[I] as TElMenuItem;
3) И, наконец, блок ассемблера становится:
Result := AFunc(Item);
Этот код ASM вызывает метод на Item
, Я бы сказал, что кто бы ни написал код, его голова должна быть исследована. Как будто они не знают о указателях методов.
Я бы решил, что для этого нужно найти код, который вызывает функцию, и посмотреть, что передается как Func
аргумент. Это то, что называется asm
блок. Изменить тип Func
аргумент в соответствующий процедурный тип и заменить asm
блок с вызовом указателя этого метода.
Хорошо, теперь я вижу, что оригинальный код играет быстро и свободно с локальными процедурами. Что вы должны сделать, это сделать Func
быть анонимным типом метода:
Func: TFunc<TElMenuItem, Boolean>;
Затем преобразуйте локальные функции в анонимные методы.
Обычный подход к обновлению версий Delphi заключается в одновременном обновлении сторонних библиотек. Если бы вы сделали это, то, я думаю, вам не нужно было бы переносить 15-летний библиотечный код.