1

I rewrite old code (x86 ~ 1998 year, delphi 7) on new standart (x64, Rad Studio XE 10.4). I find problem place, which stopped my work. I create minimum example, that you can debugging (The structure of the code is strictly like this!):

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, ShellApi;

type
TTestProc = procedure(btn: TButton; i: Integer);

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);

    procedure KeyDownTest();
    function FindNewFocused(): boolean;
    procedure Iterate(IterateProc: TTestProc);

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin
  KeyDownTest();    // -->  KeyDownTest
end;

procedure TForm1.KeyDownTest();
begin
  FindNewFocused();  // -->  FindNewFocused
end;

function TForm1.FindNewFocused(): boolean;

  procedure IntNextVis(btn: TButton; i: Integer);
  begin
    ShowMessage(btn.Caption);  // ----> ERROR: ACCESS VOILATION!
  end;

begin
  Iterate(@IntNextVis); // -->  Iterate
  Result := True;
end;

procedure TForm1.Iterate(IterateProc: TTestProc);

  procedure IntIterate(btn: TButton; i: Integer);
  begin
      if(i > 2) then
        Exit;       // --> break reqursive
      if(i = 2) then
        IterateProc(btn, i) // -->  FindNewFocused.IntNextVis
      else
        IntIterate(btn, i + 1); // -->  Iterate.IntIterate
  end;

var
  i: Integer;
begin
    i := 0;
    //ShowMessage(Button1.Caption); // ----> WORKING!
    IntIterate(Button1, i);  // -->  Iterate.IntIterate
end;
end.

On Form there is button, pressed on which on screen will be write message like: Caption button. This code working without error on x86 platform, but broken on x64 platform. I look in debugger, stack trace and dissassembler (x64 platfrom!) and find error: when app call callback procedure IntNextVis(btn: TButton; i: Integer);, then in asm code args callback first transmitted, and than remove! Therefore, call ShowMessage(btn.Caption); is an not correct, as btn will be removed. My current configuration Debug. Why that going on and how fix this bug? P.S.: please, tell me solution this problem without move procedure IntNextVis of local area of visibility from global area of visiblity, as in my old code very very very mach such codes.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Range
  • 416
  • 7
  • 20
  • 1
    It's simply not possible to save a local routine in a proc var. If you remove the `@` the compiler will tell you "E2094 Local procedure/function 'P' assigned to procedure variable". Did you see https://stackoverflow.com/questions/15181766/how-to-define-a-procedure-type-that-works-for-a-local-procedure and https://stackoverflow.com/questions/5044981/loosen-local-procedure-function-assigned-to-procedure-variable-restriction-gra? The anonymous method approach might be good enough for you. Also, I trust you are aware of the fact that you can make a procedure unit-local by not declaring it in... – Andreas Rejbrand Jan 04 '21 at 12:52
  • the interface section. – Andreas Rejbrand Jan 04 '21 at 12:52
  • @Andreas Rejbrand, sorry, my callback use internal variables, whiches announced in function - parent. Anonymous method I try, thanks. I write about results. – Range Jan 04 '21 at 13:02
  • @Andreas Rejbrand anonymous method work is very good! Thanks! – Range Jan 04 '21 at 15:56

0 Answers0