代码之家  ›  专栏  ›  技术社区  ›  Marus Gradinaru

如何将方法指针作为窗口消息参数发送?

  •  0
  • Marus Gradinaru  · 技术社区  · 4 年前

    我想调用通过窗口消息作为参数发送的方法。我尝试了下面的例子。。。但是当 DoWork 方法被执行。我认为程序上 CallBack Delphi documentation 它表示“方法指针”变量有两个指针: “…但我不知道如何访问第二个指针,然后用这两个指针重新构造变量。。。

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TCallBackNotify = function(CallBack: Pointer = nil): Boolean of object;
    
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        procedure Test(var Msg: TMessage); message WM_USER;
        function DoWork(CallBack: Pointer = nil): Boolean;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Test(var Msg: TMessage);
    var CallBack: TCallBackNotify;
    begin
     if Msg.Msg = WM_USER then begin
      @CallBack:= Pointer(Msg.WParam);
      CallBack;
     end;
    end;
    
    function TForm1.DoWork(CallBack: Pointer = nil): Boolean;
    begin
     Caption:= 'It''s working !';
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var CallBack: TCallBackNotify;
    begin
     CallBack:= DoWork;
     PostMessage(Handle, WM_USER, WPARAM(@CallBack) , 0);
    end;
    
    end.
    
    0 回复  |  直到 4 年前
        1
  •  3
  •   Andreas Rejbrand    4 年前

    从上的文档 internal data formats

    方法指针存储为指向方法入口点的32位指针,后跟指向对象的32位指针。

    在32位应用程序中。对于64位应用程序,同样适用,但当然是64位指针。

    TMethod

    如果 M 那么是任何方法指针吗 TMethod(M).Code 是代码(过程)指针和 TMethod(M).Data 是数据(对象)指针。

    如果要发送或发布方法指针,可以对这两个指针使用LPARAM和WPARAM,也可以向包含这两个指针的单个记录(或对象)发送单个指针。只要记住当 邮寄 对于消息,您不能传递局部变量的地址,因为该变量可能在收件人收到之前超出范围。


    var
      CallBack: TCallBackNotify;
    begin
      CallBack := DoWork;
      PostMessage(Handle, WM_USER, WPARAM(@CallBack) , 0);
    

    你正在发送 @CallBack . 自从 CallBack 声明为方法指针, @回拨 是代码指针,即。 @CallBack = TMethod(CallBack).Code . 因此,根本不发送数据指针。

    @@CallBack 这是当地人的地址吗 回拨 变量如果你宣布 回拨 作为一个 (一个正常的记录),这个地址会被表示出来 只有

    procedure TForm1.Button1Click(Sender: TObject);
    var
      CallBack: TCallBackNotify;
      CallBackRec: TMethod absolute CallBack;
    begin
      CallBack := DoWork;
      ShowMessage(
        'Data = ' + NativeInt(CallBackRec.Data).ToString + #13#10 +
        ' = Self = ' + NativeInt(Self).ToString + #13#10 +
        'Code = ' + NativeInt(CallBackRec.Code).ToString + #13#10 +
        ' = @CallBack = ' + NativeInt(@CallBack).ToString + #13#10 +
        '@@CallBack = ' + NativeInt(@@CallBack).ToString + #13#10 +
        ' = @CallBackRec = ' + NativeInt(@CallBackRec).ToString + #13#10
      );
    end;
    

    可能屈服

    Data            = 17376288
     = Self         = 17376288
    Code            = 6278088
     = @CallBack    = 6278088
    @@CallBack      = 1635636
     = @CallBackRec = 1635636
    

    发送 一个方法,你可以做,比如,

    procedure TForm1.Button1Click(Sender: TObject);
    var
      CallBack: TCallBackNotify;
    begin
      CallBack := DoWork;
      SendMessage(Handle, WM_USER, WParam(@@CallBack), 0);
    end;
    
    procedure TForm1.Test(var Msg: TMessage);
    var
      CallBack: TCallBackNotify;
    begin
      if Msg.Msg = WM_USER then
      begin
        CallBack := TCallBackNotify(PMethod(Msg.WParam)^);
        CallBack;
      end;
    end;
    

    SendMessage 是同步的,在接收方处理完消息之前不会返回;特别地, 我不会回来的 TForm1.Test 回拨

    另一方面,如果你 邮递 消息使用 PostMessage ,它会立即返回,如果幸运的话,您将崩溃,否则可能导致内存损坏。的确如此 Button1Click end 这个 回拨 局部变量将被丢弃,只有稍后才会被丢弃 运行——被给予一个悬空的指针。

    推荐文章