C# 桌面背景显示的位置可能不正确?

问题描述

嗨,我目前正在创建一个动画桌面背景,它使用 axWindowsMideaPlayer 循环播放视频文件我使用 WMP 并将其句柄设置为桌面句柄,它在单显示器设置上运行良好,但在多台显示器上失败。为什么它失败是因为显示器可以有自己的设置位置,如主屏幕的左/右/左上/左上/右上/上/下/左下和右下,这将它们的位置放在底片中等等..我的问题是如何我可以在每台显示器上正确放置每个 WMP 吗?这是我目前所拥有的,

这就是我获得每台显示器的方式...

public class displayInfo
{
    

    public bool isPrimary { get; set; }
    public int ScreenHeight { get; set; }
    public int ScreenWidth { get; set; }
    public Rect MonitorArea { get; set; }
    public Rect WorkArea { get; set; }
    public string DeviceName { get; set; }        
}

/// <summary>
/// Collection of display information
/// </summary>
public class displayInfoCollection : List<displayInfo>
{
    // size of a device name string
    private const int CCHDEVICENAME = 32;

    /// <summary>
    /// The MONITORINFOEX structure contains information about a display monitor.
    /// The GetMonitorInfo function stores information into a MONITORINFOEX structure or a MONITORINFO structure.
    /// The MONITORINFOEX structure is a superset of the MONITORINFO structure. The MONITORINFOEX structure adds a string member to contain a name
    /// for the display monitor.
    /// </summary>
    [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Auto)]
    internal struct MONITORINFOEX
    {
        /// <summary>
        /// The size,in bytes,of the structure. Set this member to sizeof(MONITORINFOEX) (72) before calling the GetMonitorInfo function.
        /// Doing so lets the function determine the type of structure you are passing to it.
        /// </summary>
        public int Size;

        /// <summary>
        /// A RECT structure that specifies the display monitor rectangle,expressed in virtual-screen coordinates.
        /// Note that if the monitor is not the primary display monitor,some of the rectangle's coordinates may be negative values.
        /// </summary>
        public Rect Monitor;

        /// <summary>
        /// A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications,/// expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor.
        /// The rest of the area in rcMonitor contains system windows such as the task bar and side bars.
        /// Note that if the monitor is not the primary display monitor,some of the rectangle's coordinates may be negative values.
        /// </summary>
        public Rect WorkArea;

        /// <summary>
        /// The attributes of the display monitor.
        ///
        /// This member can be the following value:
        ///   1 : MONITORINFOF_PRIMARY
        /// </summary>
        public uint Flags;

        /// <summary>
        /// A string that specifies the device name of the monitor being used. Most applications have no use for a display monitor name,/// and so can save some bytes by using a MONITORINFO structure.
        /// </summary>
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst = CCHDEVICENAME)]
        public string DeviceName;

        public void Init()
        {
            this.Size = 40 + 2 * CCHDEVICENAME;
            this.DeviceName = string.Empty;
        }
    }

    [DllImport("user32.dll")]
    private static extern bool EnumdisplayMonitors(IntPtr hdc,IntPtr lprcclip,EnumMonitorsDelegate lpfnEnum,IntPtr dwData);
    [DllImport("user32.dll",CharSet = CharSet.Auto)]
    private static extern bool GetMonitorInfo(IntPtr hMonitor,ref MONITORINFOEX lpmi);
    /*
    [DllImport("user32.dll")]
    static extern bool GetMonitorInfo(IntPtr hMonitor,ref MONITORINFO lpmi);
    */
    /// <summary>
    /// Returns the number of displays using the Win32 functions
    /// </summary>
    /// <returns>collection of display Info</returns>
    public static displayInfoCollection Getdisplays()
    {
        displayInfoCollection col = new displayInfoCollection();

        EnumdisplayMonitors(IntPtr.Zero,IntPtr.Zero,delegate (IntPtr hMonitor,IntPtr hdcMonitor,ref Rect lprcMonitor,IntPtr dwData)
            {
                MONITORINFOEX mi = new MONITORINFOEX();
                mi.Size = (int)Marshal.SizeOf(mi);
                bool success = GetMonitorInfo(hMonitor,ref mi);
                if (success)
                {
                    displayInfo di = new displayInfo();
                    di.ScreenWidth = (mi.Monitor.Right - mi.Monitor.Left);
                    di.ScreenHeight = (mi.Monitor.Bottom - mi.Monitor.Top);
                    di.MonitorArea = mi.Monitor;
                    di.WorkArea = mi.WorkArea;
                    di.isPrimary = Convert.ToBoolean(mi.Flags);
                    di.DeviceName = mi.DeviceName;                        
                    col.Add(di);
                }
                return true;
            },IntPtr.Zero);
        return col;
    }
}

这就是我尝试调用和使用它的方式,但它会根据显示器的位置放置 WMP。

displayInfoCollection dic = displayInfoCollection.Getdisplays();
        int count = 0;
        int totalPosX = 0;
        int totalPosY = 0;

        displayInfo dInfo = null;
                    
        List<displayInfo> di = dic.OrderByDescending(d => d.isPrimary).ToList();
        
        var or = Systeminformation.VirtualScreen;
        foreach (displayInfo dm in di)
        {
            bool zeroOutX = false;
            bool zeroOutY = false;
            if (dm.isPrimary)
            {
                totalPosX = or.Left > 0 ? or.Left : -or.Left;
                totalPosY = or.Top > 0 ? or.Top : -or.Top; 
                dInfo = dm;
            }
            else
            {                    
                bool left = false;
                bool top = false;
                bool right = false;
                bool bottom = false;
                bool topLeft = false;
                bool topRight = false;
                bool bottomLeft = false;
                bool bottomright = false;
                int posY = dm.MonitorArea.Top > 0 ? dm.MonitorArea.Top : -dm.MonitorArea.Top;
                if (dm.MonitorArea.Left < 0)
                {
                    left = true;
                }
                else
                    right = dm.MonitorArea.Left > 0;
                if (dm.MonitorArea.Top < 0)
                {
                    top = true;
                }
                else
                    bottom = dm.MonitorArea.Top > 0;
                bool center = (dm.MonitorArea.Left > 0 ?
                    dm.MonitorArea.Left : -dm.MonitorArea.Left) > 0 ||
                    (dm.MonitorArea.Left > 0 ?
                    dm.MonitorArea.Left : -dm.MonitorArea.Left) < dInfo.ScreenWidth;

                topLeft = left && top;
                topRight = right && top;
                bottomLeft = left && bottom;
                bottomright = right && bottom;
                if (topLeft || topRight || bottomLeft || bottomright || left || right)
                {
                    if (dm.MonitorArea.Left < 0)
                        zeroOutX = true;
                    else
                        totalPosX += dInfo.ScreenWidth;
                    if (dm.MonitorArea.Top < 0)
                        zeroOutY = true;
                    else
                        totalPosY += dm.MonitorArea.Top;
                }
                dInfo = dm;
            }

            display display = new display(dm.DeviceName,dm.ScreenWidth,dm.ScreenHeight,zeroOutX ? 0 : totalPosX,zeroOutY ? 0 : totalPosY,Controls,count);
            displays.Add(display);
            count++;
            
        }

在这个问题上找不到太多帮助,并尝试了很多方法来做到这一点,它的 ac# windows 表单,我是编程新手,我的知识有限,任何帮助都将提前感谢。

解决方法

根据EnumDisplaySettings

EnumDisplaySettings 函数为以下五个设置值 DEVMODE 成员:

  • dmBitsPerPel
  • dmPelsWidth
  • dmPelsHeight
  • dmDisplayFlags
  • dmDisplayFrequency

(不包括dmPosition),您应该尝试使用EnumDisplaySettingsEx,并指定DM_POSITION以获得正确的dmPosition值。

,

感谢所有帮助我找到问题解决方案的人,如果有人需要知道的话。

        var or = SystemInformation.VirtualScreen;
        foreach (DisplayInfo dm in dic)
        {                
            int x = or.Left > 0 ? or.Left : -or.Left;
            int y = or.Top > 0 ? or.Top : -or.Top;

            if (dm.isPrimary)
            {
                Rect rect = new Rect();
                rect.Left = x;
                rect.Top = y;
                rect.Right = rect.Left + dm.ScreenWidth;
                rect.Bottom = rect.Top + dm.ScreenHeight;
                dm.MonitorArea = rect;
            }                
            else
            {                 
                Rect rect = new Rect();
                rect.Left = x + dm.MonitorArea.Left;
                rect.Top = y + dm.MonitorArea.Top;
                rect.Right = rect.Left + dm.ScreenWidth;
                rect.Bottom = rect.Top + dm.ScreenHeight;
                dm.MonitorArea = rect;
            }