子类化VCL的后代TWinControl

Subclassing descendant of VCL TWinControl

本文关键字:后代 TWinControl VCL 子类      更新时间:2023-10-16

使用伪函数创建子类:

CreateSpecialHandle(TWinControl *Control, const TCreateParams &Params, const AnsiString SubClass)  
{  
......;  
    set Control DefWndProc to SubClass.lpfnWndProc  
    set Control WindowHandle from CreateWindowEx 
......;  
subclass(TWinControl *Control);  
}
subclass(TWinControl *Control)
{
  ......;
  oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
  oldDefWProc = (void*)(Control->DefWndProc);
  oldWindowProc = Control->WindowProc;
  MakeObjectInstance(newWProc) for SetWindowLong
  MakeObjectInstance(newDefWProc) for Control->DefWndProc
  Control->WindowProc = newWindowProc;
  ......;
}

现在,我们有了子类控件的意外行为。WM_NCHITTEST结果0,等等…
例如,当newWProc拦截WM_NCHITTEST时,将Result设置为HTCLIENT我们有鼠标响应,但是,如果没有将msg.result设置为1的msg.msg WM_NCHITTEST我的错误和错误的子类化后果,我们还需要手动处理什么?

  • newWProc回调oldWProc
  • newDefWProc回调oldDefWProc
  • newWindowProc呼叫oldWindowProc

我们是否必须子类化父控件的子类化控件?
此外,发送WM_GETTEXT结果与空缓冲区。
显然,我们做错了什么。我们需要解释,
提前感谢大家
更新:

   in TDCEdit:public TCustomEdit overriding CreateWindowHandle
   void __fastcal CreateWindowHandle(const TCreateParams &Params)
      {
       CreateSpecialHandle(this,Params,TEXT("EDIT"));
      }
     void CreateSpecialHandle(TWinControl *Control,const TCreateParams &Params, AnsiString SubClass)  
     {
     ... 
     Control->WindowHandle = CreateWindowEx(...,"EDIT",....);
     ....
     subclass(Control);
     }
     subclass(TWinControl* Control)
     {
     ......;
     oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
     oldDefWProc = (void*)(Control->DefWndProc);
     oldWindowProc = Control->WindowProc;
     MakeObjectInstance(newWProc) for SetWindowLong
     MakeObjectInstance(newDefWProc) for Control->DefWndProc
     Control->WindowProc = newWindowProc;
     ......;
     }

现在,当我使用TDCEdit和拦截消息。Msg == WM_NCHITTEST
newWProc消息。结果为0,并在所有消息处理链中保持0。
注意,子类TCustomEdit是我们需要子类化
的其他控件之一。在项目中,我们尝试使用相同的子类(TWinControl*)函数。

这是newWProc的一部分,还有几行关注问题

void __fastcall TControlWrapper::newWProc(Messages::TMessage &Message)
 {
   if(Message.Msg == WM_NCHITTEST ) // TEST
            if(Message.Result == 0) 
                  Message.Result=1;//<- WHY I NEED TO DO THIS
    if( Message.Msg == WM_DESTROY) {
      HandleWMDestroy(Message);
      return; 
    }
      CallWindowProcW( (int(__stdcall*)())oldWProc, 
              Handle, Message.Msg, Message.WParam, 
              Message.LParam);
     if(Message.Msg == WM_NCHITTEST )
            if(Message.Result == 0)Message.Result=1;//<- OR THIS

 }

这是一个令人困惑的问题-它没有帮助,你的代码示例不是c++。

set Control DefWndProc to SubClass.lpfnWndProc
例如,

在c++函数中不是一行。你能显示你的实际代码吗?

我可以猜测你想做什么:你是否试图子类化一个窗口(也许是一个窗体?),以便它在鼠标点击时移动?如果是这样,你不需要做任何原始的Windows api风格的子类化,你似乎在做GetWindowLong的方式。在c++ Builder中,VCL是一个围绕Windows API的面向对象的包装器,您可以通过以下两种更简洁的方式之一来实现:

    创建一个新的WindowProc并设置它;这是一个指向新窗口过程的属性,你可以简单地调用旧窗口过程;
  1. 创建TWinControl的后代类(如果您正在使用表单,您已经有一个)并实现虚拟方法WndProc

#1的一个例子,在Delphi(但你应该能够很容易地将其转换为c++)是在Embarcadero文档中子类化WndProc。

一个例子#2,最干净的OO版本,在这里,这实际上显示了如何做你想做的事情:c++ Builder:创建一个带有BorderStyle bsNone的TForm,但仍然是可移动和可调整大小

考虑到你似乎想要做的事情,我建议你用#2。