Recent

Author Topic: WM_SYSCOMMAND: things are more complex than suggested in lMessages.pp [solved]  (Read 7861 times)

PeterX

  • Sr. Member
  • ****
  • Posts: 404
WINDOWS widgetset - procedure WMSysCommand()


By accident I came across the fact that reacting on message WM_SYSCOMMAND
is more complex than represented by the CONST values in  lMessages.pp:

Code: Pascal  [Select][+][-]
  1.   //-------------
  2.   // Windows Compatability}
  3.   //-------------
  4.  { System Menu Commands }
  5.   SC_SIZE           = 61440;
  6.   SC_MOVE           = 61456;
  7.   SC_MINIMIZE       = 61472;
  8.   SC_MAXIMIZE       = 61488;
  9.   SC_ ...

I attached the example code to show what's up.

Please touch the minimize, normalize and maximize buttons
of the Child Window to see what happens ..
« Last Edit: May 27, 2021, 01:52:27 pm by PeterX »
usually using latest Lazarus release version with Windows 10

PeterX

  • Sr. Member
  • ****
  • Posts: 404
usually using latest Lazarus release version with Windows 10

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
By accident I came across the fact that reacting on message WM_SYSCOMMAND
is more complex than represented by the CONST values in  lMessages.pp:

Yes, there are undocumented system-reserved bits used by WM_SYSCOMMAND, such as in the $F001..$F009 range that your code is looking at.  This is documented on MSDN:

Quote
In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

Code: Pascal  [Select][+][-]
  1. if (Msg.CmdType and $FF) = $20 then

The only CmdType values whose lower 8 bits are $20 are SC_MINIMIZE ($F020) and SC_RESTORE ($F120) (and only when those lower 4 bits are not being used by the system).  You are pulling these two values out of the CmdType and commenting them as "real" messages. But then your main case block is also handling them too, making the if block redundant.

Code: Pascal  [Select][+][-]
  1. case Msg.CmdType of

This is just plain wrong.  Per the documentation quoted above, you must mask the value of CmdType, eg:

Code: Pascal  [Select][+][-]
  1. case Msg.CmdType and $FFF0 of

For instance, when CmdType is $F001, that is really SC_SIZE ($F000) + 1.  And when CmdType is $F012, that is really SC_MOVE ($F010) + 2.  And so on.

In fact, $F012 is more commonly known as SC_DRAGMOVE, which is used when dragging around a window by its title bar, and as such is useful when you want to manually initiate a drag of a window from an area other than its title bar, for instance when dragging a caption-less window.

Though, you really should not rely on the system bits having any particular meaning.  They are private to the OS, and can change meaning from one version to another.  But, in any case, there are some known meanings, see https://stackoverflow.com/a/763273/65863.

With that said, since Microsoft doesn't want you looking at the private bits, you should end up with code that looks more like this instead:

Code: Pascal  [Select][+][-]
  1. procedure TChildForm.WMSysCommand(var Msg: TWmSysCommand);
  2. begin
  3.   // https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand
  4.   //
  5.   // A window receives this message when the user chooses a command
  6.   // from the Window menu (formerly known as the system or control menu)
  7.   // OR when the user chooses the maximize button, minimize button,
  8.   // restore button, or close button.
  9.  
  10.   case Msg.CmdType and $FFF0 of
  11.     SC_MOVE:  // move form ..
  12.       begin
  13.         {$ifdef DEBUG_SUBUNIT}
  14.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8) +' = SC_MOVE');
  15.         {$endif}
  16.       end;
  17.  
  18.     SC_CLOSE:  // close form ..
  19.       begin
  20.         {$ifdef DEBUG_SUBUNIT}
  21.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8) +' = SC_CLOSE');
  22.         {$endif}
  23.       end;
  24.  
  25.     SC_RESTORE:  // normalize form ..
  26.       begin
  27.         {$ifdef DEBUG_SUBUNIT}
  28.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8) +' = SC_RESTORE');
  29.         {$endif}
  30.       end;
  31.  
  32.     SC_MAXIMIZE:  // maximize form ..
  33.       begin
  34.         StoreBounds;
  35.         {$ifdef DEBUG_SUBUNIT}
  36.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8) +' = SC_MAXIMIZE');
  37.         {$endif}
  38.       end;
  39.  
  40.     SC_MINIMIZE:  // minimize form ..
  41.       begin
  42.         // https://microsoft.public.vc.mfc.narkive.com/EtOQGNmk/sc-restore
  43.         // https://www.askingbox.de/frage/delphi-auf-minimieren-einer-form-reagieren-onminimize
  44.         {$ifdef DEBUG_SUBUNIT}
  45.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8) +' = SC_MINIMIZE');
  46.         {$endif}
  47.       end
  48.  
  49.     // => https://stackoverflow.com/questions/9704075/how-to-detect-when-the-form-is-being-maximized
  50.  
  51.     else
  52.       begin
  53.         Memo1.Append( 'WMSysCommand() .. $' +IntToHex( Msg.CmdType, 8));
  54.         inherited;
  55.       end;
  56.   end;
  57. end;
« Last Edit: May 27, 2021, 02:41:25 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

PeterX

  • Sr. Member
  • ****
  • Posts: 404
Thanks a lot for these informations !

I was really sure that my code was a mess.
But it was too late at night to do it the right way ..


If not already someone else has found this,
I would put up a bug report to change and comment
the CONST definitions in  lMessages.pp

Declaration SC_SIZE for example is in use in 5 lcl units.
But as 61440 = $F000 = b1111000000000000 this is not a big thing.

In hexadecimal it would be plain to see what's behind it, inside Windows

[Edit] I wrote a bugreport.
« Last Edit: May 27, 2021, 01:51:45 pm by PeterX »
usually using latest Lazarus release version with Windows 10

PeterX

  • Sr. Member
  • ****
  • Posts: 404
Not ready at all, but I found most of the values
I probably need, see attached Example Project.
usually using latest Lazarus release version with Windows 10

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
I would put up a bug report to change and comment
the CONST definitions in  lMessages.pp

The constants are not wrong, they are just declared in decimal format whereas Microsoft documents them in hex format instead.  They are the correct numeric values as far as the compiler is concerned.

Declaration SC_SIZE for example is in use in 5 lcl units.

So?  As long as those units are using the human-readable alias names and not the actual numeric values, then it should not matter whether the values are declared as decimal or hex.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Not ready at all, but I found most of the values
I probably need, see attached Example Project.

Just nitpicking at this point, but if you are going to drill into the private OS bits, then you should at least be consistent about it.

Code: Pascal  [Select][+][-]
  1. case Msg.CmdType and $FFF0 of
  2.  
  3.   SC_SIZE:  // move form ..  SC_MOVE = $F000
  4.     begin
  5.       case Msg.CmdType of
  6.         $F001:  // click on left vertical border
  7.         ...
  8.       end;
  9.     end;
  10.   ...
  11. end;

Should be

Code: Pascal  [Select][+][-]
  1. case Msg.CmdType and $FFF0 of
  2.  
  3.   SC_SIZE:  // move form ..  SC_MOVE = $F000
  4.     begin
  5.       case Msg.CmdType and $F of
  6.         $1:  // click on left vertical border
  7.         ...
  8.       end;
  9.     end;
  10.  
  11.   ...
  12. end;

To match with your other case statements.

Just saying...
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

PeterX

  • Sr. Member
  • ****
  • Posts: 404
As long as those units are using the human-readable alias names and not the actual numeric values, then it should not matter whether the values are declared as decimal or hex.
My idea was, when right clicking on one of these CONST values,
Lazarus opens lMessages.pp and shows You the declaration in the source code.
And there is no comments about the technical background as You pointed me to.
( => "the four low-order bits of the wParam parameter are used internally by the system" ..)

I am the first time "hacking into" reserved bits of Windows' internal machine.
Without Your Hints (thanks !) it would have taken much more time for me to find out and understand.

So the const values, declared as hexadecimal, look much more logical
and do point directly to such a mechanism like bitweise operation and/or masking.
The decimal declarations look like a "wild zoo of numbers" to me, and they hide things a little bit.

Just my 2 cents ..
usually using latest Lazarus release version with Windows 10

PeterX

  • Sr. Member
  • ****
  • Posts: 404
Just nitpicking at this point, but if you are going to drill into the private OS bits, then you should at least be consistent about it.
That's totally okay !

I also don't like inconsistent code, thanks for this hint !

Including these wrong comments ..
Code: Pascal  [Select][+][-]
  1. SC_SIZE:  // move form ..  SC_MOVE = $F000

 %)
« Last Edit: May 27, 2021, 06:19:39 pm by PeterX »
usually using latest Lazarus release version with Windows 10

 

TinyPortal © 2005-2018