Delphi   发布时间:2022-04-11  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何在64位Delphi XE2中将方法转换为回调过程?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_770_1@mustangPeak Common Library(http://code.google.com/p/mustangpeakcommonlib/)包含以下代码,用于将方法转换为可在回调中使用的过程:
const
  AsmPopEDX = $5A;
  AsmMovEAX = $B8;
  AsmPushEAX = $50;
  AsmPushEDX = $52;
  AsmJmpShort = $E9;

type
  Tstub = packed record
    PopEDX: Byte;
    MovEAX: Byte;
    SelfPointer: Pointer;
    PushEAX: Byte;
    PushEDX: Byte;
    JmpShort: Byte;
    Displacement: Integer;
  end;

{ ----------------------------------------------------------------------------- }
function Createstub(ObjectPtr: Pointer; MethodPtr: Pointer): Pointer;
var
  stub: ^Tstub;
begin
  // Allocate memory for the stub
  // 1/10/04 Support for 64 bit,executable code must be in virtual space
  stub := VirtualAlloc(nil,SizeOf(Tstub),MEM_COMMIT,PAGE_EXECUTE_READWRITE);

  // Pop the return address off the stack
  stub^.PopEDX := AsmPopEDX;

  // Push the object pointer on the stack
  stub^.MovEAX := AsmMovEAX;
  stub^.SelfPointer := ObjectPtr;
  stub^.PushEAX := AsmPushEAX;

  // Push the return address BACk on the stack
  stub^.PushEDX := AsmPushEDX;

  // Jump to the 'real' procedure,the method.
  stub^.JmpShort := AsmJmpShort;
  stub^.Displacement := (Integer(MethodPtr) - Integer(@(stub^.JmpShort))) -
    (SizeOf(stub^.JmpShort) + SizeOf(stub^.Displacement));

  // Return a pointer to the stub
  Result := stub;
end;
{ ----------------------------------------------------------------------------- }

{ ----------------------------------------------------------------------------- }
procedure Disposestub(stub: Pointer);
begin
  // 1/10/04 Support for 64 bit,executable code must be in virtual space
  VirtualFree(stub,MEM_DECOMMIT);
end;

我很感激将它转换为64位的任何帮助.我知道Win64中的调用约定是不同的,并且最多四个参数被传递到寄存器中.因此可能必须修改Createstub以包含参数的数量.它实际上不使用四个以上的参数,即整数或指针(没有浮点参数).

解决方法

这是64位版本的Createstub.感谢Andrey Gruzdev提供的代码.
type
  ICallBACkstub = interface(IInterfacE)
    function GetstubPointer: Pointer;
    property stubPointer : Pointer read GetstubPointer;
  end;

  TCallBACkstub = class(TinterfacedObject,ICallBACkstub)
  private
    fstubPointer : Pointer;
    fCodeSize : Integer;
    function GetstubPointer: Pointer; 
  public
    constructor Create(Obj : TObject; MethodPtr: Pointer; NumArgs : Integer);
    destructor Destroy; override;
  end;



constructor TCallBACkstub.Create(Obj: TObject; MethodPtr: Pointer;
  NumArgs: Integer);
{$IFNDEF CPUX64}
// as before
{$ELSE CPUX64}
const
RegParamCount = 4;
ShadowParamCount = 4;

Size32Bit = 4;
Size64Bit = 8;

ShadowStack   = ShadowParamCount * Size64Bit;
SkipParamCount = RegParamCount - ShadowParamCount;

StackSrsOffset = 3;
c64stack: arraY[0..14] of byte = (
$48,$81,$ec,00,//     sub rsp,$0
$4c,$89,$8c,$24,ShadowStack,00//     mov [rsp+$20],r9
);

CopySrcOffset=4;
CopyDstOffset=4;
c64copy: arraY[0..15] of byte = (
$4c,$8b,//     mov r9,[rsp+0]
$4c,00//     mov [rsp+0],r9
);

RegMethodOffset = 10;
RegSelfOffset = 11;
c64regs: arraY[0..28] of byte = (
$4d,$c1,//   mov r9,r8
$49,$d0,//   mov r8,rdx
$48,$ca,//   mov rdx,rcx
$48,$b9,// mov rcx,Obj
$48,$b8,00 // mov rax,MethodPtr
);

c64jump: arraY[0..2] of byte = (
$48,$ff,$e0  // jump rax
);

CallOffset = 6;
c64call: arraY[0..10] of byte = (
$48,//    call rax
$48,$c4,//     add rsp,$0
$c3// ret
);
var
  i: Integer;
  P,PP,Q: PByte;
  lCount : Integer;
  lSize : Integer;
  lOffset : Integer;
begin
    lCount := SizeOf(c64regs);
    if NumArgs>=RegParamCount then
       Inc(lCount,sizeof(c64stack)+(NumArgs-RegParamCount)*sizeof(c64copy)+sizeof(c64call))
    else
       Inc(lCount,sizeof(c64jump));

    Q := VirtualAlloc(nil,lCount,PAGE_EXECUTE_READWRITE);
    P := Q;

    lSize := 0;
    if NumArgs>=RegParamCount then
    begin
        lSize := ( 1+ ((NumArgs + 1 - SkipParamCount) div 2) * 2 )* Size64Bit;   // 16 byte stack align

        pp := p;
        move(c64stack,P^,SizeOf(c64stack));
        Inc(P,StackSrsOffset);
        move(lSize,Size32Bit);
        p := pp;
        Inc(P,SizeOf(c64stack));
        for I := 0 to NumArgs - RegParamCount -1 do
        begin
            pp := p;
            move(c64copy,SizeOf(c64copy));
            Inc(P,CopySrcOffset);
            lOffset := lSize + (i+ShadowParamCount+1)*Size64Bit;
            move(lOffset,Size32Bit);
            Inc(P,CopyDstOffset+Size32Bit);
            lOffset := (i+ShadowParamCount+1)*Size64Bit;
            move(lOffset,Size32Bit);
            p := pp;
            Inc(P,SizeOf(c64copy));
        end;
    end;

    pp := p;
    move(c64regs,SizeOf(c64regs));
    Inc(P,RegSelfOffset);
    move(Obj,SizeOf(Obj));
    Inc(P,RegMethodOffset);
    move(MethodPtr,SizeOf(MethodPtr));
    p := pp;
    Inc(P,SizeOf(c64regs));

    if NumArgs<RegParamCount then
      move(c64jump,SizeOf(c64jump))
    else
    begin
      move(c64call,SizeOf(c64call));
      Inc(P,CallOffset);
      move(lSize,Size32Bit);
    end;
    fCodeSize := lcount;
   fstubPointer := Q;
{$ENDIF CPUX64}
end;

destructor TCallBACkstub.Destroy;
begin
  VirtualFree(fstubPointer,fCodeSize,MEM_DECOMMIT);
  inherited;
end;

function TCallBACkstub.GetstubPointer: Pointer;
begin
  Result := fstubPointer;
end;

大佬总结

以上是大佬教程为你收集整理的如何在64位Delphi XE2中将方法转换为回调过程?全部内容,希望文章能够帮你解决如何在64位Delphi XE2中将方法转换为回调过程?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。