近日我研究vcl的封装机制时,发现所有的窗口生成都是调用了这个函数.
procedure TWinControl.CreateWindowHandle(const Params: TCreateParams);
begin
  with Params do
    FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,
      X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);
end;这里我就有一个疑问: 对于标准控件,如BUTTON等等,如果用原生的win32 API来创建,不是
需要指定一个控件ID的吗? 然后这个控件ID会在窗口回调里用于判断消息是哪个子控件的.
但在上面那个函数里,这个ID一律指定为0.这样窗口回调如何得知这个消息是哪个子控件来的呢?

解决方案 »

  1.   

    你說的那個0是,hmenu,菜單對象的handle。
    Control := ControlAtPos(SmallPointToPoint(Message.Pos), False);
    ...
    Control.Perform(Message.Msg, Message.Keys, Longint(PointToSmallPoint(P)));
    上面比如會處理wm_command這樣消息,那麽對於處理類似wm_lbuttondown,api---dispatchmessage會根據消息結構中的hwnd直接將消息發送給目標控件,不會通過form。
      

  2.   

    非常抱歉,好几天没来那个0填入的位置确是hmenu, 但是按照api文档的说法,在不同的情境中,这个hmenu是有不同的含义的
    hMenu
    [in] Handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window. 
    按这个说法,此时应填入即将创建的子窗口控件的ID才是,而且应当是"惟一"的, 可vcl却填入一个0, 这是疑惑一.疑惑二
    通过观察TButton的Onclick事件的调用栈,会发现这是由TCustomForm.WndProc调用的,即是由父窗口来调用的.也就是说这个消息并不是操作系统直接发送给这个Button的?
      

  3.   

    關於疑惑二,你要搞清楚是什麽消息。其實click事件是由wm_command轉化而來,但form會優先處理此消息,最後會調用iscontrolmsg,判斷消息的hwnd,將wm_command消息perform給button,然後在button再轉化為click,此部分可參考《inside vcl》中的消息部分;
    關於疑惑一,你要注意depending on the window style. 你看vcl的處理如button,是否為ws_childwindow?如果窗口style不是這樣指定,那就傳0了