近日我研究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.这样窗口回调如何得知这个消息是哪个子控件来的呢?
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.这样窗口回调如何得知这个消息是哪个子控件来的呢?
Control := ControlAtPos(SmallPointToPoint(Message.Pos), False);
...
Control.Perform(Message.Msg, Message.Keys, Longint(PointToSmallPoint(P)));
上面比如會處理wm_command這樣消息,那麽對於處理類似wm_lbuttondown,api---dispatchmessage會根據消息結構中的hwnd直接將消息發送給目標控件,不會通過form。
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的?
關於疑惑一,你要注意depending on the window style. 你看vcl的處理如button,是否為ws_childwindow?如果窗口style不是這樣指定,那就傳0了