My Delphi-7 application displays :
Screen.DesktopWidth
Screen.DesktopHeight
Screen.Monitors[0].Width
Screen.Monitors[0].Height
and , if there's a second monitor selected , also :
Screen.Monitors[1].Width
Screen.Monitors[1].Height
With the application running on my WinXP-Pro PC , I go to Control Panel / Display / Settings , and change the settings for the second monitor (either add or remove it) .
I then click on a Refresh button to display the new values of the 4 (or 6) parameters , and something unexpected happens : Screen.DesktopWidth and Screen.DesktopHeight show the correct new values , but the values of the other 2 (or 4) parameters are very wrong .
Like Screen.Monitors[0].Width = 5586935 , while it should be 1680 .
Are there some special rules for using TScreen in Delphi 7 ?
Came here because of refresh problem (bug) of TScreen when connect or disconnect a monitor or USB display device. The answer of @Dave82 doesn't work for me. The result of the function MonitorFromWindow must return another value (unknown/invalid value) to force an update of the TScreen object.
This cheat below does the trick:
Be sure multimon is in the uses clause:
uses
multimon;
Add this to the interface part (of the form)
protected
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
Add this to implementation part (of the form)
function cheatMonitorFromWindow(hWnd: HWND; dwFlags: DWORD): HMONITOR; stdcall;
begin
// Does nothing, returns zero to force invalidate
Result:=0;
end;
procedure TForm1.WMDeviceChange(var Msg: TMessage);
var
iCurrDisplayCount : LongInt;
iNewDisplayCount : LongInt;
pMonitorFromWinProc : TMonitorFromWindow;
begin
iCurrDisplayCount:=Screen.MonitorCount;
// Force monitor update, fix bug in customform, won't update at display change.
// This a hack/cheat to multimon MonitorFromWindow func, it's fakes the result.
// This is required to tell customform.getMonitor() to update the TScreen object.
pMonitorFromWinProc:=MonitorFromWindow; // Backup pointer to dynamic assigned DLL func
MonitorFromWindow:=cheatMonitorFromWindow; // Assign cheat func
monitor; // call the monitor property that calls customform.getMonitor and cheatfunc
MonitorFromWindow:=pMonitorFromWinProc; // restore the original func
// ==========
iNewDisplayCount:=Screen.MonitorCount;
if( iCurrDisplayCount <> iNewDisplayCount ) then
begin
// Display count change!
end;
end;
What happen inside customform (code in Forms.pas)?
function TCustomForm.GetMonitor: TMonitor;
var
HM: HMonitor;
I: Integer;
begin
Result := nil;
HM := MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST);
for I := 0 to Screen.MonitorCount - 1 do
if Screen.Monitors[I].Handle = HM then
begin
Result := Screen.Monitors[I];
Exit;
end;
//if we get here, the Monitors array has changed, so we need to clear and reinitialize it
for i := 0 to Screen.MonitorCount-1 do
TMonitor(Screen.FMonitors[i]).Free;
Screen.FMonitors.Clear;
EnumDisplayMonitors(0, nil, @EnumMonitorsProc, LongInt(Screen.FMonitors));
for I := 0 to Screen.MonitorCount - 1 do
if Screen.Monitors[I].Handle = HM then
begin
Result := Screen.Monitors[I];
Exit;
end;
end;
Hopes it helps when somebody is looking for this. When you want to detect display device settings changes (resolution and orientation), catch the WM_DISPLAYCHANGE event instead.
Screen.Monitors array contain invalid values if you switch user while your program is running. We use this line of code to force the Screen object to update lists:
Screen.MonitorFromWindow(0, mdNull);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With