Ruud Schmeitz
Ruud Schmeitz

Reputation: 151

Using TScreen in Delphi 7

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

Answers (3)

Dave82
Dave82

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

Codebeat
Codebeat

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

Ruud Schmeitz
Ruud Schmeitz

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

Related Questions