Delphi asm to purepascal

时间:2014-12-22 11:30:09

标签: delphi assembly delphi-5 delphi-xe7

我正在尝试将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;

2 个答案:

答案 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岁的图书馆代码。