Recent

Author Topic: WM_DISPLAYCHANGE // recognize a different screen resolution  (Read 4698 times)

RAW

  • Hero Member
  • *****
  • Posts: 868
WM_DISPLAYCHANGE // recognize a different screen resolution
« on: February 10, 2018, 07:57:47 am »
Maybe this is useful for anybody....  :)

This is working for me...
EDIT: Instead of "ShowMessage" I use now "Color" in this example... As GetMem mentioned "ShowMessage" is a bad idea inside a WndProc.
Code: Pascal  [Select][+][-]
  1. UNIT Unit1;
  2. {$MODE OBJFPC}{$H+}{$J-}
  3.  
  4. Interface
  5.  USES
  6.   Windows, Classes, Forms, Dialogs;
  7.  
  8.  TYPE
  9.   TForm1 = Class(TForm)
  10.    Procedure FormCreate (Sender: TObject);
  11.    Procedure FormClick  (Sender: TObject);
  12.  
  13.     PRIVATE
  14.      oldProc: Windows.WndProc;
  15.   End;
  16.  
  17.  VAR
  18.   Form1: TForm1;
  19.  
  20. Implementation
  21. {$R *.LFM}
  22.  
  23.  
  24. Function WndCallback
  25.   (MyWND: HWND; uMSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; StdCall;
  26.  Begin
  27.   If (uMSG = WM_DISPLAYCHANGE)
  28.   Then Form1.Color:= RGB(0, 80, 255);
  29.  
  30.   Result:= CallWindowProc(Form1.oldProc, MyWND, uMSG, wParam, lParam);
  31.  End;
  32.  
  33.  
  34. Procedure TForm1.FormCreate(Sender: TObject);
  35.  Begin
  36.   oldProc:= Windows.WndProc(GetWindowLongPtr(Handle, GWL_WNDPROC));
  37.   SetWindowLongPtr(Handle, GWL_WNDPROC, PtrInt(@WndCallback));
  38.  End;
  39.  
  40.  
  41. Procedure TForm1.FormClick(Sender: TObject);
  42.  Begin
  43.   Color:= RGB(0, 187, 0);
  44.  End;
  45.  
  46. END.


// not working for me...
Code: Pascal  [Select][+][-]
  1. unit unit1;
  2. {$mode objfpc}{$H+}
  3.  
  4. interface
  5.  
  6. uses
  7.  Windows, Classes, SysUtils, Forms, Dialogs;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.   private
  12.    procedure WMDisplayChange(var msg: TMessage); message WM_DISPLAYCHANGE;
  13.   end;
  14.  
  15. var
  16.   Form1: TForm1;
  17.  
  18. implementation
  19.  
  20. {$R *.lfm}
  21.  
  22. procedure TForm1.WMDisplayChange(var msg: TMessage);
  23. begin
  24.  showmessage('Display Changed');
  25. end;
  26.  
  27. end.

WndProc (standard way) isn't working for me either...
« Last Edit: February 11, 2018, 09:42:05 pm by RAW »
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

balazsszekely

  • Guest
Re: WM_DISPLAYCHANGE (Is there any workaround ???)
« Reply #1 on: February 10, 2018, 08:39:39 am »
@RAW
The ShowMessage inside WndCallback is wrong, I mean fundamentally wrong. You cannot block the message chain with a function like ShowMessage. I know you put it there only for testing purposes, still be careful with blocking functions.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: WM_DISPLAYCHANGE // recognize a different screen resolution
« Reply #2 on: February 10, 2018, 09:05:43 am »
@GetMem
Yeah, I added some info lines regarding this... Thanks...  :)
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: WM_DISPLAYCHANGE // recognize a different screen resolution
« Reply #3 on: February 10, 2018, 10:39:07 am »

// not working for me...
Code: Pascal  [Select][+][-]
  1. unit unit1;
  2. {$mode objfpc}{$H+}
  3.  
  4. interface
  5.  
  6. uses
  7.  Windows, Classes, SysUtils, Forms, Dialogs;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.   private
  12.    procedure WMDisplayChange(var msg: TMessage); message WM_DISPLAYCHANGE;
  13.   end;
  14.  
  15. var
  16.   Form1: TForm1;
  17.  
  18. implementation
  19.  
  20. {$R *.lfm}
  21.  
  22. procedure TForm1.WMDisplayChange(var msg: TMessage);
  23. begin
  24.  showmessage('Display Changed');
  25. end;
  26.  
  27. end.

WndProc (standard way) isn't working for me either...
that is because the default handler filters unsupported messages out from the internal message loop. You should use the getwindowlong (look the default handler proc for info) to get the attached wincontrol instead of relying on a global variable that might or might not be valid.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: WM_DISPLAYCHANGE // recognize a different screen resolution
« Reply #4 on: February 11, 2018, 09:16:47 pm »
@taazz
Thanks for the info...
What do you mean? Something like this:
Code: Pascal  [Select][+][-]
  1. Procedure TForm1.FormCreate(Sender: TObject);
  2.  Begin
  3.   oldProc:= Windows.WndProc(GetWindowLongPtr(Handle, GWL_WNDPROC));
  4.   SetWindowLongPtr(Handle, GWL_WNDPROC, PtrInt(@WndCallback));
  5.  End;
  6.  
... is working good too...  :)

But I heard it's better to use this:
Code: Pascal  [Select][+][-]
  1.  TYPE
  2.   TSubClassProc = Function
  3.    (hWnd: HWND; uMSG: UINT; wParam: WPARAM; lParam: LPARAM;
  4.     uIDSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; StdCall;
  5.  ........................
  6.  
  7.  Function SetWindowSubclass
  8.   (hWnd: HWND; pfnSubclass: TSubClassProc; uIDSubclass: UINT_PTR;
  9.    dwRefData: DWORD_PTR): BOOL; StdCall; External 'ComCtl32.dll';
  10.  
  11.  Function RemoveWindowSubclass
  12.   (hWnd: HWND; pfnSubclass: TSubClassProc; uIDSubclass: UINT_PTR): BOOL;
  13.    StdCall; External 'ComCtl32.dll';
  14.  
  15.  Function DefSubclassProc
  16.   (hWnd: HWND; uMSG: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
  17.    StdCall; External 'ComCtl32.dll';
  18.  
I'm working on it...  :)
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: WM_DISPLAYCHANGE // recognize a different screen resolution
« Reply #5 on: February 11, 2018, 09:40:52 pm »
@taazz
Thanks for the info...
What do you mean? Something like this:
Code: Pascal  [Select][+][-]
  1. Procedure TForm1.FormCreate(Sender: TObject);
  2.  Begin
  3.   oldProc:= Windows.WndProc(GetWindowLongPtr(Handle, GWL_WNDPROC));
  4.   SetWindowLongPtr(Handle, GWL_WNDPROC, PtrInt(@WndCallback));
  5.  End;
  6.  
No I mean

Code: Pascal  [Select][+][-]
  1. UNIT Unit1;
  2. {$MODE OBJFPC}{$H+}{$J-}
  3.  
  4. Interface
  5.  USES
  6.   Windows, Classes, Forms, Dialogs;
  7.  
  8.  TYPE
  9.   TForm1 = Class(TForm)
  10.   Procedure FormCreate (Sender: TObject);
  11.    PRIVATE
  12.     PrevWndProc: Windows.WNDPROC;
  13.   End;
  14.  
  15.  VAR
  16.   Form1: TForm1;
  17.  
  18. Implementation
  19. {$R *.LFM}
  20.  
  21.  
  22. Function WndCallback (MyHWND: HWND; uMSG: UINT; wParam: WParam; lParam: LParam): LRESULT; StdCall;
  23. var
  24.   WindowInfo: PWin32WindowInfo;
  25. Begin
  26.   WindowInfo := GetWin32WindowInfo(Window); //<---- step one
  27.   If (uMSG = WM_DISPLAYCHANGE)
  28.   Then ShowMessage('Display Changed') // only for testing purposes...
  29.   Else Form1.Color:= RGB(0, 170, 0);  // don't use this in real world apps, take
  30.                                       // a look at the following post from GetMem
  31.  
  32.   if WindowInfo^.WinControl is TForm1 then //Eliminate form1 global variable for safer handling.
  33.   Result:= CallWindowProc(TForm1(WindowInfo^.WinControl).PrevWndProc, MyHWND, uMSG, WParam, LParam);
  34.  End;
  35.  
  36.  
  37. Procedure TForm1.FormCreate(Sender: TObject);
  38.  Begin
  39.   PrevWndProc:= Windows.WNDPROC
  40.   (SetWindowLongPtr(Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
  41.  End;
  42.  
  43. END.

Take a closer look on WindowProc in the file win32callback.inc it has all the information you need.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

 

TinyPortal © 2005-2018