无法在EnumWindows回调中修改params

时间:2012-06-22 10:47:45

标签: delphi pascal freepascal lazarus fpc

我尝试使用Lazarus(Free Pascal)中的以下代码获取主窗口句柄:

function FindMainWindow(Pid: LongWord): LongWord;
type
  TParam = record
    Window: HWnd;
    Test: Integer;
    Pid: LongWord;
  end;
  PParam = ^TParam;
var
  Params: TParam;
  function _FindMainWindow(Wnd: HWnd; MyLParam: PParam): Bool; stdcall;
  var
    WinPid: DWord;
  begin
    with MyLParam^ do
    begin
      Test := 2;
      GetWindowThreadProcessID(Wnd, @WinPid);
      Result := (WinPid <> Pid) or (not IsWindowVisible(Wnd))
        or (not IsWindowEnabled(Wnd));
      if not Result then begin
        Window := Wnd;
      end;
    end;
  end;
begin
  Params.Pid := Pid;
  Params.Test := 1;
  EnumWindows(@_FindMainWindow, LParam(@Params));
  ShowMessage('Done!');
  ShowMessage(IntToStr(Params.Test));
  Result := Params.Window;
end; 

问题是在运行回调后Params.Test仍为1。我想修改Params函数中的_FindMainWindow

注意:我无法直接访问Params中的_FindMainWindow,因为我收到了“访问冲突”错误。

1 个答案:

答案 0 :(得分:3)

当然在Delphi中,它看起来也是FPC,嵌套函数无法用作回调函数。使用32位编译器时,嵌套函数可以用作回调。但是这样的代码只能被编译器接受,因为回调函数在Windows单元中被声明为无类型指针。如果Windows单元将它们声明为过程类型,则会发现编译器对象使用嵌套函数。

对于64位Delphi编译器,根本不能使用嵌套函数作为回调。虽然编译器允许您继续使用,但由于在Windows单元中使用了无类型指针(参见上文),因此未正确调用回调函数。显然,FPC也是如此。您将不得不停止使用嵌套函数进行回调。

有趣的是,FPC和Delphi编译器在这里具有相同的特性。我的猜测是x64调用约定,这是一个基于寄存器的约定,而不是基于堆栈的x86 stdcall是这个问题的驱动力。我敢打赌,如果你试图使用嵌套的x86 register函数作为回调,那么在运行时也会失败。