- yes, I try to implement own TWinControl
Why?
Your implementation is not processing messages correctly. For one thing, all of your
TWinControl and descendant classes are registering a single class name, which is just wrong. Different types of windows need different class names so they can customize their windows as needed without interfering with other window classes.
But also, the message loop is simply the wrong place to handle messages for a window. The correct place is in the wndproc callback that is registered with
RegisterClass() before the window is created, or subclassed after creation with
SetWindowLongPtr(GWL_WNDPROC) or
SetWindowSubclass().
You are calling
HandleMessage() inside of your
GlobalWndProc(), which is the correct thing to do.
HandleMessage() does not belong in your modal message loop. Since you don't have a
ModalResult property in your
TForm class (which I suggest you add), you will need to instead use the return value of
DispatchMessage(). Do not call
HandleMessage() again after it has already been called by
GlobalWndProc() inside of
DispatchMessage().
And, don't forget to
handle WM_QUIT in your modal loop, too.
Something like this:
repeat
if GetMessageA(_msg, 0, 0, 0) then
begin
TranslateMessage(_msg);
ret := DispatchMessageA(_msg);
if (_msg.hwnd = p.FHandle) and
(_msg.Message = WM_NCLBUTTONDOWN) and
(LoWord(_msg.wParam) = HTCLOSE) and
(res = -100) then break;
end else
begin
PostQuitMessage(_msg.wParam);
break;
end;
until False;
Note, however, that
WM_NCLBUTTONDOWN is the wrong message to detect when the window is closed. Use
WM_CLOSE or
WM_DESTROY for that instead.
This would be simpler with a
ModalResult property added, eg:
p.ModalResult := 0;
repeat
if GetMessageA(_msg, 0, 0, 0) then
begin
TranslateMessage(_msg);
DispatchMessageA(_msg);
end else
begin
PostQuitMessage(_msg.wParam);
break;
end;
until p.ModalResult <> 0;
ShowWindow(p.FHandle, SW_HIDE);
...
function TWinControl.HandleMessage(id: HWND; MSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
case msg of
...
WM_CLOSE: begin
writeln('close');
ModalResult := 1;
end;
...
end;
end;
- the Message 96 is a Hit-Test for Non-Client Area that I capture with WM_NCLButtonDown (also a Left-Mouse-Click)
WM_NCLButtonDown is 161 not 96. Like I said earlier, there is no standard window message 96.
Also, 96 is not a defined value for the
wParam of
WM_NCLButtonDown, either.
So, where exactly are you seeing 96?
I don't fiddle out why WM_SYSCOMMAND is not captured.
It is because you are not calling
DefWindowProc() when handling
WM_NCLBUTTONDOWN.
DefWindowProc() is who generates
WM_SYSCOMMAND. Always call
DefWindowProc() for all messages you don't process, don't just blindly return 0 for them.
- it could be a Problem with your Note by using NativeInt / THandle
That is the least of your problems.
- by calling HandleMessage() I can get in touch with TControl Classes and Components - which I don't can easy reach by a normal WndProc
Yes, a normal
WndProc can access controls/component classes. Especially given that the
WndProc (or, in your case,
HandleMessage()) is a non-static class method, so you need access to the control/component class in order to call it. Which your
GlobalWndProc() is doing.
I thinking that one WndProc is bound only one by a Pointer in single use - but a DLL shall handle more WndProc - by Pointer's, too - yes - but then the Pointer's a bound with a T*Class
This is why the standard
TWinControl.WndProc() is virtual. A central shared
WndProc is registered for all control classes, and it delegates to a per-control
WndProc based on the HWND being sent to.