Reputation: 151
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 ?
Upvotes: 8
Views: 5764
Reputation: 66
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);
Upvotes: 1
Reputation: 6610
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.
Upvotes: 4
Reputation: 151
Thanks to TLama , I found a workaround for the TScreen problem in Delphi 7 .
The original code that 'caused' the problem :
LabMon1.Caption := ' Mon 1: ' + IntToStr (Screen.Monitors[0].Width) +
' x ' + IntToStr (Screen.Monitors[0].Height);
if (Screen.MonitorCount = 1)
then LabMon2.Caption := ' Mon 2: -'
else LabMon2.Caption := ' Mon 2: ' + IntToStr (Screen.Monitors[1].Width) +
' x ' + IntToStr (Screen.Monitors[1].Height);
I only had to add 1 line of code to solve it :
LabMon1.Caption := ' Mon 1: ' + IntToStr (Monitor.Width) +
' x ' + IntToStr (Monitor.Height) ;
LabMon1.Caption := ' Mon 1: ' + IntToStr (Screen.Monitors[0].Width) +
' x ' + IntToStr (Screen.Monitors[0].Height);
if (Screen.MonitorCount = 1)
then LabMon2.Caption := ' Mon 2: -'
else LabMon2.Caption := ' Mon 2: ' + IntToStr (Screen.Monitors[1].Width) +
' x ' + IntToStr (Screen.Monitors[1].Height);
So thanks again TLama , for your great contributions to this Question-thread !
Upvotes: 0