es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Obteniendo el área de trabajo precisa del monitor en los cambios de configuración de la pantalla

Trabajando en una aplicación que escucha cambios en la configuración de la pantalla (por ejemplo, conexiones y desconexiones de monitores). El problema con el que me estoy encontrando es que el área de trabajo de un monitor (los límites del monitor excluyendo las barras de tareas y otros espacios reservados para la visualización) no es precisa cuando se dispara el evento.

Usando ya sea la API de Screen o GetMonitorInfo de user32.dll retorna límites inexactos.

Supongo que toma un corto tiempo para que la barra de tareas reserve espacio cuando se cambian los monitores. Si configuro un temporizador corto y luego utilizo los mismos métodos, los límites son precisos, pero esto parece ser una solución muy frágil.

Para reproducir el problema:

using Microsoft.Win32;
using System;
using System.Windows.Forms;

static class Program
{
  [STAThread]
  static void Main()
  {
    SystemEvents.DisplaySettingsChanged += new EventHandler(OnDisplaySettingsChanged);
    Application.Run();
  }

  private static void OnDisplaySettingsChanged(object sender, EventArgs e)
  {
    foreach (var screen in Screen.AllScreens)
    {
      // <code>screen.WorkingArea</code> no es preciso aquí - no incluye el espacio reservado por la barra de tareas.
    }
  }
}

¿Existe alguna manera de obtener de manera confiable el área de trabajo de un monitor cuando se cambian la configuración de la pantalla? Alternativamente, ¿existe una manera de escuchar cambios en el área de trabajo de un monitor?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una solución potencial es usar un Timer para retrasar la obtención del área de trabajo del monitor hasta que el sistema haya actualizado completamente sus configuraciones de pantalla:

    static class Program
    {
      private static Timer _timer;
    
      [STAThread]
      static void Main()
      {
        SystemEvents.DisplaySettingsChanged += OnDisplaySettingsChanged;
    
        Application.Run();
      }
    
      private static void OnDisplaySettingsChanged(object sender, EventArgs e)
      {
        // Detener cualquier timer existente y crear uno nuevo
        if (_timer != null)
        {
          _timer.Stop();
        }
    
        _timer = new Timer();
        _timer.Interval = 1000; // Retraso de 1 segundo
        _timer.Tick += GetWorkingAreas;
        _timer.Start();
      }
    
      private static void GetWorkingAreas(object sender, EventArgs e)
      {
        var monitors = Screen.AllScreens;
        foreach (var monitor in monitors)
        {
          var monitorInfo = new MONITORINFOEX();
          if (GetMonitorInfo(monitor.Handle, ref monitorInfo))
          {
            var workArea = monitorInfo.rcWork;
            // Utilizar workArea para realizar procesamiento adicional
          }
        }
    
        // Detener el timer para evitar llamadas repetidas
        _timer.Stop();
      }
    
      [StructLayout(LayoutKind.Sequential)]
      public struct RECT
      {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
      }
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
      public class MONITORINFOEX
      {
        public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
        public RECT rcMonitor = new RECT();
        public RECT rcWork = new RECT();
        public int dwFlags = 0;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] szDevice = new char[32];
      }
    
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
    }
    

    Este código utiliza un Timer para esperar 1 segundo antes de llamar a GetWorkingAreas y obtener las áreas de trabajo precisas del monitor. Se utiliza la función GetMonitorInfo de user32.dll para acceder a la información del área de trabajo. La estructura MONITORINFOEX representa la información del monitor y es utilizada por la función GetMonitorInfo.

    Otra opción es utilizar una biblioteca de terceros, como WMI o Windows API Code Pack, que proporcionan un mejor acceso a eventos e información relacionados con el monitor. Sin embargo, esto puede introducir una complejidad adicional y dependencias al proyecto.

Comments are closed.