{"record":{"id":"d4eb33f148cdc270","repo":"NickeManarin/ScreenToGif","slug":"it-was-not-possible-to-get-a-list-of-known-screens-d4eb33","errorCode":null,"errorMessage":"It was not possible to get a list of known screens.","messagePattern":"It was not possible to get a list of known screens\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"ScreenToGif/Windows/Recorder.xaml.cs","lineNumber":1430,"sourceCode":"            {\n                UserSettings.All.RecorderLeft = Arguments.Region.Left - Constants.LeftOffset;\n                UserSettings.All.RecorderTop = Arguments.Region.Top - Constants.TopOffset;\n                UserSettings.All.RecorderWidth = (int)Arguments.Region.Width + Constants.HorizontalOffset;\n                UserSettings.All.RecorderHeight = (int)Arguments.Region.Height + Constants.VerticalOffset;\n                Arguments.Region = Rect.Empty;\n            }\n        }\n\n        //Since the list of monitors could have been changed, it needs to be queried again.\n        _viewModel.Monitors = MonitorHelper.AllMonitorsGranular();\n\n        //Detect closest screen to the point (previously selected top/left point or current mouse coordinate).\n        var point = startup ? (double.IsNaN(UserSettings.All.RecorderTop) || double.IsNaN(UserSettings.All.RecorderLeft) ?\n            CursorHelper.GetMousePosition(_scale, Left, Top) : new Point((int)UserSettings.All.RecorderLeft, (int)UserSettings.All.RecorderTop)) : new Point((int) Left, (int) Top);\n        var closest = _viewModel.Monitors.FirstOrDefault(x => x.Bounds.Contains(point)) ?? _viewModel.Monitors.FirstOrDefault(x => x.IsPrimary) ?? _viewModel.Monitors.FirstOrDefault();\n\n        if (closest == null)\n            throw new Exception(\"It was not possible to get a list of known screens.\");\n\n        //Move the window to the correct location.\n        var left = UserSettings.All.RecorderLeft;\n        var top = UserSettings.All.RecorderTop;\n\n        if (double.IsNaN(UserSettings.All.RecorderTop) || double.IsNaN(UserSettings.All.RecorderLeft))\n        {\n            left = closest.WorkingArea.Left + closest.WorkingArea.Width / 2d - ActualWidth / 2d;\n            top = closest.WorkingArea.Top + closest.WorkingArea.Height / 2d - ActualHeight / 2d;\n        }\n        else\n        {\n            //To much to the Left.\n            if (closest.WorkingArea.Left > UserSettings.All.RecorderLeft + UserSettings.All.RecorderWidth - 100)\n                left = closest.WorkingArea.Left;\n\n            //Too much to the top.\n            if (closest.WorkingArea.Top > UserSettings.All.RecorderTop + UserSettings.All.RecorderHeight - 100)","sourceCodeStart":1412,"sourceCodeEnd":1448,"githubUrl":"https://github.com/NickeManarin/ScreenToGif/blob/a4d0a67c2131cd048ceec86cd40afc2f1a06f2fd/ScreenToGif/Windows/Recorder.xaml.cs#L1412-L1448","documentation":"Thrown by the Recorder's monitor-selection routine when MonitorHelper.AllMonitorsGranular() returns an empty list, so none of the three FirstOrDefault fallbacks (point-containing, primary, any) resolve a monitor. AllMonitorsGranular delegates to the AllMonitors getter which drives User32.EnumDisplayMonitors via a callback closure; if that native enumeration yields zero monitors, the List is empty. The throw means the window cannot determine which screen to anchor itself to.","triggerScenarios":"Called during recorder startup/positioning (startup=true) or repositioning. AllMonitorsGranular() returns an empty list because User32.EnumDisplayMonitors invoked no callback items — typically when the calling thread has no visible desktop, the session is in transition (logoff/lock/UAC secure desktop), or all displays were disconnected while the window was open.","commonSituations":"All monitors disconnected / powered off while ScreenToGif was open; running on a session that lost its desktop (fast-user-switch, RDP disconnect); the window is being positioned during a WM_DISPLAYCHANGE before the new monitor list is populated; headless service context with no interactive desktop; display driver crashed and the GDI desktop is momentarily gone.","solutions":["Ensure at least one display is active and powered on before opening the recorder.","Reconnect the disconnected monitor, then close and reopen the recorder window so AllMonitorsGranular re-enumerates.","Delay the reposition call until the SystemEvents.DisplaySettingsChanged event has fully fired and the desktop is stable.","Do not launch the recorder from a non-interactive session (service/scheduled task) — it needs an interactive desktop to enumerate monitors.","Add a guard: if the list is empty, fall back to SystemParameters.PrimaryScreenWidth/Height instead of throwing, or retry enumeration after a short delay."],"exampleFix":"// before\n_viewModel.Monitors = MonitorHelper.AllMonitorsGranular();\nvar point = /* ... */;\nvar closest = _viewModel.Monitors.FirstOrDefault(x => x.Bounds.Contains(point)) ?? _viewModel.Monitors.FirstOrDefault(x => x.IsPrimary) ?? _viewModel.Monitors.FirstOrDefault();\nif (closest == null)\n    throw new Exception(\"It was not possible to get a list of known screens.\");\n\n// after: retry + graceful fallback to SystemParameters primary screen\n_viewModel.Monitors = MonitorHelper.AllMonitorsGranular();\nfor (var i = 0; _viewModel.Monitors.Count == 0 && i < 3; i++)\n    _viewModel.Monitors = MonitorHelper.AllMonitorsGranular();\n\nvar point = /* ... */;\nvar closest = _viewModel.Monitors.FirstOrDefault(x => x.Bounds.Contains(point))\n           ?? _viewModel.Monitors.FirstOrDefault(x => x.IsPrimary)\n           ?? _viewModel.Monitors.FirstOrDefault();\n\nif (closest == null)\n{\n    // No enumerated monitor — anchor to the WPF primary-screen rect instead of crashing.\n    closest = new Monitor { Bounds = new Rect(0, 0, SystemParameters.PrimaryScreenWidth, SystemParameters.PrimaryScreenHeight),\n                            WorkingArea = SystemParameters.WorkArea, IsPrimary = true };\n    LogWriter.Log(new InvalidOperationException(\"Monitor enumeration returned empty list; falling back to primary screen.\"), \"Monitor enumeration fallback.\");\n}","handlingStrategy":"validation","validationCode":"// Validate monitor enumeration before using it for positioning.\nvar monitors = MonitorHelper.AllMonitorsGranular();\nif (monitors == null || monitors.Count == 0)\n{\n    // Retry once after the display subsystem settles.\n    await Task.Delay(200);\n    monitors = MonitorHelper.AllMonitorsGranular();\n}\nif (monitors.Count == 0)\n    throw new InvalidOperationException(\"No displays available; cannot position the recorder.\");\n\n_viewModel.Monitors = monitors;","typeGuard":"// Ensure a non-empty monitor list before resolving 'closest'.\nstatic bool HasUsableMonitor(List<Monitor> monitors, Point point) =>\n    monitors.Count > 0 &&\n    (monitors.Any(x => x.Bounds.Contains(point)) || monitors.Any(x => x.IsPrimary));\n\nif (!HasUsableMonitor(_viewModel.Monitors, point))\n    return; // skip repositioning, keep current location","tryCatchPattern":"try\n{\n    // ... monitor selection + positioning ...\n}\ncatch (Exception e) when (e.Message.Contains(\"list of known screens\"))\n{\n    LogWriter.Log(e, \"Monitor enumeration failed during recorder positioning.\");\n    // Keep the window at its last known position instead of crashing.\n}","preventionTips":["Subscribe to SystemEvents.DisplaySettingsChanged and defer repositioning until the new list is stable.","Never assume AllMonitorsGranular() returns non-empty — always null/empty-check before FirstOrDefault chains.","Avoid launching the recorder from a non-interactive session; it needs a live desktop.","Cache the last-good monitor rect so a transient enumeration gap doesn't break positioning."],"tags":["monitor","display-enumeration","enumdisplaymonitors","wpf","multi-monitor","desktop"],"backgroundTag":null,"analyzedSha":"a4d0a67c2131cd048ceec86cd40afc2f1a06f2fd","analyzedAt":"2026-08-13T11:12:06.147Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}