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

Posted

技术标签:

【中文标题】C# 桌面背景可能显示不正确的位置?【英文标题】:C# Desktop background displaying incorrect location maybe? 【发布时间】:2021-04-30 03:40:10 【问题描述】:

您好,我目前正在创建一个使用 axWindowsMideaPlayer 循环播放视频文件的动画桌面背景为什么它失败是因为监视器可以有自己的设置位置,例如主屏幕的左/右/左上/右上/上/下/左下和右下,这将它们的位置置于负片等等。我的问题是如何我可以在每台显示器上正确放置每个 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 窗体,我是编程新手,我的知识有限,任何帮助都将提前感谢。

【问题讨论】:

为什么会有C标签? 你是唯一一个回复了消息的人,即使这样也与我的问题无关..... EnumDisplaySettingsExGetMonitorInfo 的坐标是virtual-screen 坐标,可能是负值。不确定 axWindowsMideaPlayer 是否使用相同的坐标系?将axWindowsMideaPlayer的位置设置为默认值(0,0)是否有效? 它可以在单显示器上完美运行,在多显示器上它们会搞砸,如果显示器位置是负值,那么它会丢弃其余的,将它们设置为 value(0,0) 不能作为virtual-desktop 的最左边表示 x 可能是 -1920 或 y -1366 【参考方案1】:

根据EnumDisplaySettings

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

dmBitsPerPel dmPelsWidth dmPelsHeight dmDisplayFlags dmDisplayFrequency

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

【讨论】:

嗨 Drake 我已将代码更改为 EnumDisplaySettingsEx 但它仍然显示相同的位置不确定我是否做得对?我在原始帖子中添加了更改,谢谢。【参考方案2】:

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

        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;
            

【讨论】:

以上是关于C# 桌面背景可能显示不正确的位置?的主要内容,如果未能解决你的问题,请参考以下文章

从代码设置桌面背景颜色

组策略 设置桌面背景

组策略 设置桌面背景

VC++如何获取并保存桌面背景?

C#语言实例源码系列-设置桌面背景

Windows7获取更换桌面背景,C#