我正在尝试将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? 上面的代码片段来自ELPack的ELmenus.pas。
那么基本上什么是asm代码块的PurePascal版本?
对于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;
答案 0 :(得分:4)
我猜测原始程序员编写的奇怪代码绕过Delphi不支持本地函数指针。 (这是一种让我偶尔烦恼的限制。)
以下内容应该有效。 (虽然我的确不是那么敏锐但确定。我会首先通过D5中的调试器来测试 asm 代码以确认行{{ 1}}传递我期望的值。)
1)Delcare一个函数指针类型并移动UpdateItem,使其不再是本地的。
CALL DWORD PTR AFunc
2)进行以下更改:
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;
3)最后汇编程序块变为:
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;
答案 1 :(得分:3)
asm代码正在调用Item
上的方法。我要说的是,编写代码的人需要经过检验。好像他们不了解方法指针一样。
我要解决这个问题的方法是查找调用该函数的代码,并查看作为Func
参数传递的内容。那是asm
块调用的内容。将Func
参数的类型更改为适当的过程类型,并使用对该方法指针的调用替换asm
块。
好的,现在我看到原始代码在本地程序中播放速度很快。你应该做的是让Func
成为匿名方法类型:
Func: TFunc<TElMenuItem, Boolean>;
然后将本地函数转换为匿名方法。
升级Delphi版本的常用方法是同时升级第三方库。如果你这样做,我想你不需要移植这个15岁的图书馆代码。