-1

嗨,我目前正在创建一个动画桌面背景,它使用 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 窗体,我对编程很陌生,我的知识在这方面是有限的,任何帮助都将不胜感激。

4

2 回答 2

0

根据EnumDisplaySettings

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

  • dmBitsPerPel
  • dmPelsWidth
  • dmPelsHeight
  • dmDisplayFlags
  • dmDisplayFrequency

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

于 2021-02-10T09:20:45.750 回答
0

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

        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;
            }
于 2021-02-16T03:52:18.907 回答