【问题标题】:Move Application GUI to another monitor将应用程序 GUI 移动到另一台显示器
【发布时间】:2013-11-14 06:06:14
【问题描述】:

之前在此处提出了与我的问题类似的问题。但我认为这是独一无二的。

我有我的电脑显示器和一个扩展显示器,我通过这段代码得到了 EDID 和一些数据:

ManagementObjectSearcher searcher =
   new ManagementObjectSearcher("root\\WMI", "SELECT * FROM WmiMonitorID");

foreach (ManagementObject queryObj in searcher.Get())
{
    dynamic snid = queryObj["SerialNumberID"];
    string serialnum = GetStringFromInt(snid);

    Console.WriteLine("SerialNumber:  {0}",serialnum);
    Console.WriteLine("YearOfManufacture: {0}", queryObj["YearOfManufacture"]);
    dynamic code = queryObj["ProductCodeID"];
    string pcid = GetStringFromInt(code);
    code = queryObj["ManufacturerName"];
    string manufactrName = GetStringFromInt(code);

    Console.WriteLine("ProductCodeID: " + pcid);
    Console.WriteLine("Manufacture: " + manufactrName);
}}

所以我将Manufacture 和ProductCodeID 组合在一起,类似于ABC3401 和DEF4561(我有两个显示器)。我需要将我的应用程序移至DEF4561。我试过 Move Form onto specified Screen 但名称返回 \\DISPLAY1 、 \\DISPLAY2 等。我需要 ABC3401 字符串来识别监视器。我不知道如何组合这些结果。

【问题讨论】:

  • 产品代码如何识别显示器?您必须编写一个函数来返回特定产品 ID 的监视器编号。
  • 我正在为特定显示器做应用程序。
  • 您的意思是针对特定类型的显示器?您需要找到序列号和显示 ID 之间的映射。那应该在某个地方可以使用,但我不知道在哪里,抱歉。
  • 您需要调用 EnumDisplayDevices() 并在设备 ID 上找到匹配项。

标签: c# wpf screen


【解决方案1】:

为了完成答案,我正在完成这个。首先,通过edokan's answer获取monitor的详细信息

    public struct DisplayInfo
    {
        public string DisplayID;
        public string DisplayName;
        public string EDID;
    }
     [DllImport("user32.dll")]
    static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
     [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

    public static List<DisplayInfo> GetConnectedMonitorInfo()
    {
        var MonitorCollection = new List<DisplayInfo>();
        DISPLAY_DEVICE d = new DISPLAY_DEVICE();
        d.cb = Marshal.SizeOf(d);
        try
        {
            for (uint id = 0; EnumDisplayDevices(null, id, ref d, 0); id++)
            {

                EnumDisplayDevices(d.DeviceName, 0, ref d, 1);

                if (string.IsNullOrEmpty(d.DeviceName.ToString()) 
                        && string.IsNullOrEmpty(d.DeviceID.ToString())) continue; 

                var dispInfo = new DisplayInfo();
                dispInfo.DisplayID = id.ToString();
                dispInfo.DisplayName = d.DeviceName.ToString();
                dispInfo.EDID = d.DeviceID.ToString();

                if (d.DeviceID.ToString().Contains("ABC4562"))
                {
                    //Identify Multiple monitor of same series
                    if (string.IsNullOrEmpty(myMonitor.myMonDevName))
                    {
                        myMonitor.myMonDevName = d.DeviceName.ToString();
                    }
                    else
                    {
                        MultipleMonitorFound = true;
                    }

                }
                    MonitorCollection.Add(dispInfo);

                d.cb = Marshal.SizeOf(d);
            }
        }
        catch (Exception ex)
        {
           LogError(ex.ToString());
        }
        return MonitorCollection;
    }

现在我们有了监视器列表及其详细信息。现在需要将 GUI 更改为该监视器,

我们需要该方法的一些参数:

        //I am Using WPF
        //For C# only, we can use GetActiveWindow() API.
        WindowInteropHelper winHelp = new WindowInteropHelper(this);
        ScreenObject sc = new ScreenObject();
        //Compare the name with screens
        sc.screen = sc.GetMyMonitor(myMonitor.myMonDevName);

ScreenObject 类来自Move form onto the specified screen 答案。

    public static void MoveWindowToMonitor(IntPtr hWnd, int left, int top,double width, double height)
    {


        if (SetWindowPos(hWnd, (IntPtr)SpecialWindowHandles.HWND_TOP, left, top, (int)width, (int)height, SetWindowPosFlags.SWP_SHOWWINDOW))
           LogError( " :  Success");
        else
            LogError(" :  Failed");
    }

P/Invoke 可以帮助您。

C# WPF 用户注意事项:

如果您使用 Windows Presentation Foundation,则需要 WindowInteropHelper 来获取窗口句柄。

确保您引用了 PresentationFramework 程序集。

将此插入到使用块中

using System.Windows.Interop;

创建 WindowInteropHelper 的实例

WindowInteropHelper winHelp = new WindowInteropHelper(target);

然后使用 GetActiveWindowHandle() 的 winHelp.Handle。

【讨论】:

    【解决方案2】:

    您必须使用EnumDisplayDevices 枚举连接到它们的显示设备和监视器,然后才能匹配它们。

    下面是pinvoke.net的代码的无耻复制

    [Flags()]
    public enum DisplayDeviceStateFlags : int
    {
        /// <summary>The device is part of the desktop.</summary>
        AttachedToDesktop = 0x1,
        MultiDriver = 0x2,
        /// <summary>The device is part of the desktop.</summary>
        PrimaryDevice = 0x4,
        /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
        MirroringDriver = 0x8,
        /// <summary>The device is VGA compatible.</summary>
        VGACompatible = 0x10,
        /// <summary>The device is removable; it cannot be the primary display.</summary>
        Removable = 0x20,
        /// <summary>The device has more display modes than its output devices support.</summary>
        ModesPruned = 0x8000000,
        Remote = 0x4000000,
        Disconnect = 0x2000000
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    public struct DISPLAY_DEVICE 
    {
          [MarshalAs(UnmanagedType.U4)]
          public int cb;
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
          public string DeviceName;
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
          public string DeviceString;
          [MarshalAs(UnmanagedType.U4)]
          public DisplayDeviceStateFlags StateFlags;
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
          public string DeviceID;
          [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
          public string DeviceKey;
    }
    
    
    [DllImport("user32.dll")]
    static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
    
    void Main()
    {
        DISPLAY_DEVICE d=new DISPLAY_DEVICE();
        d.cb=Marshal.SizeOf(d);
        try {
            for (uint id=0; EnumDisplayDevices(null, id, ref d, 0); id++) {
                Console.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}", id, d.DeviceName, d.DeviceString, d.StateFlags, d.DeviceID));
                
                EnumDisplayDevices(d.DeviceName, 0, ref d, 1);
                Console.WriteLine(String.Format("    {0}, {1}, {2}, {3}, {4}", id, d.DeviceName, d.DeviceString, d.StateFlags, d.DeviceID));                          
                d.cb=Marshal.SizeOf(d);
            }
        } catch (Exception ex) {
            Console.WriteLine(String.Format("{0}",ex.ToString()));
        }
    }
    

    它在我的电脑上提供以下输出

    0, \\.\DISPLAY1, ATI Radeon HD 5570, 134742017, PCI\VEN_1002&DEV_68D9&SUBSYS_E142174B&REV_00
        0, \\.\DISPLAY1\Monitor0, SyncMaster B2230 (Digital), AttachedToDesktop, MultiDriver, \\?\DISPLAY#SAM0635#5&15bb0574&0&UID256#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
    1, \\.\DISPLAY2, ATI Radeon HD 5570, 134742021, PCI\VEN_1002&DEV_68D9&SUBSYS_E142174B&REV_00
        1, \\.\DISPLAY2\Monitor0, SyncMaster B2230 (Analog), AttachedToDesktop, MultiDriver, \\?\DISPLAY#SAM0635#5&15bb0574&0&UID257#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
    2, \\.\DISPLAYV1, RDPDD Chained DD, 2097160, 
        2, , , 0, 
    3, \\.\DISPLAYV2, RDP Encoder Mirror Driver, 2097160, 
        3, , , 0, 
    4, \\.\DISPLAYV3, RDP Reflector Display Driver, 2097160, 
        4, , , 0, 
    

    【讨论】:

    • 这给出了显卡名称。有什么选项可以忽略它吗? (我认为忽略第一个console.writeLine() 对吧?
    • 您必须通过检查第二次api调用的结果找到您想要的监视器。当你找到你要找的东西时,你应该使用它的卡名来匹配你需要的 Screen 对象
    • 显卡名称:显卡名称?我想这将是答案。让我试试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多