为什么不能在64位Delphi中将地址传递给嵌套的局部函数?

如。自关闭相关问题以来-下面添加了更多示例。


下面的简单代码(可找到顶级Ie窗口并枚举其子窗口)可以在“ 32位Windows”目标平台上正常运行。早期版本的Delphi也没有问题:


procedure TForm1.Button1Click(Sender: TObject);


  function EnumChildren(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;

  const

    Server = 'Internet Explorer_Server';

  var

    ClassName: array[0..24] of Char;

  begin

    Assert(IsWindow(hwnd));            // <- Assertion fails with 64-bit

    GetClassName(hwnd, ClassName, Length(ClassName));

    Result := ClassName <> Server;

    if not Result then

      PUINT_PTR(lParam)^ := hwnd;

  end;


var

  Wnd, WndChild: HWND;

begin

  Wnd := FindWindow('IEFrame', nil); // top level IE

  if Wnd <> 0 then begin

    WndChild := 0;

    EnumChildWindows(Wnd, @EnumChildren, UINT_PTR(@WndChild));


    if WndChild <> 0 then

      ..    


end;


我插入了,Assert以指示在使用“ 64位Windows”目标平台时失败的地方。如果我没有嵌套回调,则代码没有问题。


我不确定参数传递的错误值只是垃圾,还是由于某些错误的内存地址(调用约定?)引起的。嵌套回调实际上是我一开始不应该做的事情吗?还是这仅仅是我必须忍受的缺陷?


慕雪6442864
浏览 554回答 3
3回答

30秒到达战场

该技巧从未得到该语言的正式支持,并且由于32位编译器的实现细节,您到目前为止一直在使用它。该文档很清楚:嵌套过程和函数(在其他例程中声明的例程)不能用作过程值。如果我没记错的话,一个额外的隐藏参数将通过指向封闭堆栈框架的指针传递给嵌套函数。如果未引用封闭环境,则在32位代码中将其省略。在64位代码中,总是传递额外的参数。当然,问题的很大一部分是Windows单元将无类型的过程类型用作其回调参数。如果使用了键入程序,则编译器可能会拒绝您的代码。实际上,我认为这是对您所使用的欺骗绝不合法的信念的证明。对于类型化的回调,即使在32位编译器中,也永远无法使用嵌套过程。无论如何,最重要的是您不能将嵌套函数作为参数传递给64位编译器中的另一个函数。

HUH函数

事情是我被迫使用'@'运算符,尽管我为回调提供了准确的签名,因为编译器破坏了类型系统,因为如果不使用隐藏参数(至少在64位上),它将无法处理局部函数。 。
打开App,查看更多内容
随时随地看视频慕课网APP