Came here due to an update problem (error) of TScreen when connecting or disconnecting a monitor or USB display device. Answer @ Dave82 does not work for me. The result of the MonitorFromWindow function should return a different value (unknown / invalid value) in order to force the TScreen object to be updated.
This cheat below does the trick:
Make sure multimon is in use :
uses multimon;
Add this to part of the interface (form)
protected procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
Add this to the implementation part (forms)
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 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 happens 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;
Hope this helps when someone is looking for it. If you want to detect changes in display device settings (resolution and orientation), intercept the WM_DISPLAYCHANGE event.
Codebeat
source share