正确覆盖 WndProc

Properly overriding WndProc

一天前,我开始重写我的一个旧组件,我决定提高它的可读性。 我的组件是一个典型的 TWinControl,它覆盖了 WndProc 来处理我自己的很多消息。每条消息代码太多,看代码成了我的难题
因此,为了寻找改进 WndProc 内代码的解决方案,我将这些大块代码组织在程序中,每次在 WndProc 中传递适当的消息时调用这些程序。这就是现在的样子:

procedure TMyControl.WndProc(var Message: TMessage);
begin
  case Message.Msg of        
    WM_WINDOWPOSCHANGED: 
      WMWINDOWPOSCHANGED(Message);
    WM_DESTROY: 
      WMDESTROY(Message);
    WM_STYLECHANGED: 
      WMSTYLECHANGED(Message);
    //  lots of the same procedures for Windows messages
    //  ...
    MM_FOLDER_CHANGED: 
      MMFOLDERCHANGED(Message);
    MM_DIRECTORY_CHANGED: 
      MMDIRECTORYCHANGED(Message);
    //  lots of the same procedures for my own messages
    //  ...
  else
    Inherited WndProc(Message);
  end;
end;

不幸的是 Inherited 这些程序中的单词不再起作用!

重要说明: 在某些 WM_XXX 消息中我没有调用 Inherited 来执行我自己对此类消息的处理,因此代码如下所示将分解我实现某些功能的努力。

procedure TMyControl.WndProc(var Message: TMessage);
begin
  Inherited WndProc(Message);
  case Message.Msg of        
    WM_WINDOWPOSCHANGED: 
      WMWINDOWPOSCHANGED(Message);
    //  further messages
    //  ...
  end;
end;

我还想避免在每个消息 ID 之后插入 Inherited,如下所示,因为它看起来很糟糕,而且我认为存在更优雅的方法来覆盖 WndProc

procedure TMyControl.WndProc(var Message: TMessage);
begin      
  case Message.Msg of        
    WM_WINDOWPOSCHANGED: 
    begin
      Inherited WndProc(Message);
      WMWINDOWPOSCHANGED(Message);
    end;
    //  further messages
    //  ...
  end;
end;

所以我的问题是:
如何正确覆盖 WndProc 以能够使用过程中分组的代码并能够仅为某些消息调用原始 window 过程?

从WMWINDOWPOSCHANGED 调用继承的WndProc 将调用继承的。所以你可以这样做:

procedure WMWINDOWPOSCHANGED(var Message: TMessage)
begin
  // call inherited WndProc if you need to
  inherited WndProc(Message);
  .. do you own processing
end;

正如 RM 的回答所述,您的消息处理方法可以调用 inherited WndProc(Message) 而不仅仅是 inherited,这样就可以正常工作。

但是,通过引入与它们正在处理的消息同名的方法,您公开了您正在处理的特定消息的知识。所以你可能会发现使用 Message Methods 而不是覆盖 WndProc 更容易,例如:

type
  TMyControl = class(...)
  private
    procedure WMWindowPosChanged(var Message: TMessage); message WM_WINDOWPOSCHANGED;
    procedure WMDestroy(var Message: TMessage); message WM_DESTROY;
    procedure WMStyleChanged(var Message: TMessage); message WM_STYLECHANGED;
    // and so on ...
  end;

然后您的 message 方法可以根据需要调用 inherited(或不调用),例如:

procedure TMyControl.WMWindowPosChanged(var Message: TMessage);
begin
  inherited;
  //...
end;