Recent

Author Topic: WM_ message List for destroy a window/exe application (GetMessage loop)  (Read 751 times)

paule32

  • Hero Member
  • *****
  • Posts: 516
  • One in all. But, not all in one.
Code: Pascal  [Select][+][-]
  1. type
  2.   TWinControl = class(TControl)
  3.   private
  4.     FHandle: Integer;
  5.   protected
  6.     function HandleMessage(id: HWND; MSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
  7.   public
  8.     constructor Create;
  9.     destructor Destroy; override;
  10.   published
  11.     property Handle: Integer read FHandle;
  12.   end;
  13.  
  14. function TWinControl.HandleMessage(id: HWND; MSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
  15. begin
  16.   writeln('wmsg: ' + IntToStr32(msg));
  17.   case msg of
  18.     WM_COMMAND: begin
  19.       writeln('control-ID: ' + IntToStr32(LoWord(wParam)));
  20.       writeln('code: ' + intToStr32(HiWord(wParam)));
  21.     end;
  22.     WM_CLOSE: begin
  23.       writeln('close');
  24.       DestroyWindow(id);
  25.     end;
  26.     WM_DESTROY: begin
  27.       writeln('des');
  28.       PostQuitMessage(0);
  29.       Halt(0);
  30.     end else begin
  31.       result := DefWindowProcA(id, msg, wParam, lParam);
  32.     end;
  33.   end;
  34.   result := 0;
  35. end;
  36. ...
  37.   while GetMessageA(_msg, 0, 0, 0) do
  38.   begin
  39.     TranslateMessage(_msg);
  40.     DispatchMessageA(_msg);
  41.     p.HandleMessage(p.FHandle, _msg.Message, _msg.wParam, _msg.lParam);
  42.   end;

the global window Proc as follows:

Code: Pascal  [Select][+][-]
  1. function GlobalWndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; export;
  2. var
  3.   winCtrl: TWinControl;
  4.   cs: PCREATESTRUCTA;
  5. begin
  6.   if msg = WM_NCCREATE then
  7.   begin
  8.     cs := PCREATESTRUCTA(lParam);
  9.     winCtrl := TWinControl(cs^.lpCreateParams);
  10.    
  11.     if Assigned(winCtrl) then
  12.     begin
  13.       SetWindowLongPtrA(hwnd, GWLP_USERDATA, NativeInt(winCtrl));
  14.       winCtrl.FHandle := hWnd;
  15.       Exit(DefWindowProcA(hWnd, Msg, wParam, lParam));
  16.     end;
  17.   end;
  18.  
  19.   winCtrl := TWinControl(GetWindowLongPtrA(hWnd, GWLP_USERDATA));
  20.  
  21.   if Assigned(winCtrl) then
  22.   Exit(winCtrl.HandleMessage(hWnd, Msg, wParam, lParam)) else
  23.   Exit(DefWindowProcA(hWnd, Msg, wParam, lParam));
  24. end;

When I click on the X (Close Button) I get Code 96 - but:

const
  WM_CLOSE              = $0010;
  WM_COMMAND        = $0111;
  WM_DESTROY          = $0002;
  WM_NCCREATE         = $0081;
  WM_QUIT                 = $0012;

dont seem effected (the writeln Functions are not called - maybe the messages are wrong ?  :o ).
When I move the mouse over the Window, I get code 512.
So, after closeing the Window the message loop still idle.
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1529
    • Lebeau Software
When I click on the X (Close Button) I get Code 96


Is that decimal or hex? Either way, there is no official Window message 96/$60 or 150/$96, so just ignore it.

More importantly, why is your Handle declared as an Integer instead of a NativeInt or better a THandle? And why is your message loop calling HandleMessage() directly? DispatchMessage() will have already delivered the message to the window. You should be handling window messages in an overridden WndProc() method, or in individual message handlers.

This code makes me think you are trying to implement your own TWinControl class manually instead of using the native one provided by the LCL.
« Last Edit: May 28, 2025, 06:04:52 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

paule32

  • Hero Member
  • *****
  • Posts: 516
  • One in all. But, not all in one.
Hi Remy  ;D

- yes, I try to implement own TWinControl

- the Message 96 is a Hit-Test for Non-Client Area that I capture with WM_NCLButtonDown (also a Left-Mouse-Click) because I don't fiddle out why WM_SYSCOMMAND is not captured.

- it could be a Problem with your Note by using NativeInt / THandle

- by calling HandleMessage() I can get in touch with TControl Classes and Components - which I don't can easy reach by a normal WndProc - because 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

- you can follow the Posting: "I lost in Code" where I have already publish older Code of a Forms.pas, that shall handle Form Dialogs:

https://dpaste.com/DBG6VPRZC

All Code are experimental and not for productive systems, yet.
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1529
    • Lebeau Software
- 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:

Code: Pascal  [Select][+][-]
  1. repeat
  2.   if GetMessageA(_msg, 0, 0, 0) then
  3.   begin
  4.     TranslateMessage(_msg);
  5.     ret := DispatchMessageA(_msg);
  6.     if (_msg.hwnd = p.FHandle) and
  7.        (_msg.Message = WM_NCLBUTTONDOWN) and
  8.        (LoWord(_msg.wParam) = HTCLOSE) and
  9.        (res = -100) then break;
  10.   end else
  11.   begin
  12.     PostQuitMessage(_msg.wParam);
  13.     break;
  14.   end;
  15. 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:

Code: Pascal  [Select][+][-]
  1. p.ModalResult := 0;
  2. repeat
  3.   if GetMessageA(_msg, 0, 0, 0) then
  4.   begin
  5.     TranslateMessage(_msg);
  6.     DispatchMessageA(_msg);
  7.   end else
  8.   begin
  9.     PostQuitMessage(_msg.wParam);
  10.     break;
  11.   end;
  12. until p.ModalResult <> 0;
  13. ShowWindow(p.FHandle, SW_HIDE);
  14.  
  15. ...
  16.  
  17. function TWinControl.HandleMessage(id: HWND; MSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
  18. begin
  19.   case msg of
  20.     ...
  21.     WM_CLOSE: begin
  22.       writeln('close');
  23.       ModalResult := 1;
  24.     end;
  25.     ...
  26.   end;
  27. 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.
« Last Edit: May 28, 2025, 07:38:20 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018