【问题标题】:C++ application to detach secondary monitor用于分离辅助监视器的 C++ 应用程序
【发布时间】:2023-03-31 12:36:01
【问题描述】:

我正在尝试创建一个应用程序以将辅助监视器从 Windows 盒子中分离出来(长话短说)。

这是我用作基础的 Microsoft 示例代码: http://support.microsoft.com/kb/308216/en-us

这是我的代码:

#include <iostream>
#include <windows.h>

void DetachDisplay()
{
    BOOL            FoundSecondaryDisp = FALSE;
    DWORD           DispNum = 0;
    DISPLAY_DEVICE  DisplayDevice;
    LONG            Result;
    TCHAR           szTemp[200];
    int             i = 0;
    DEVMODE   defaultMode;

    // initialize DisplayDevice
    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
    DisplayDevice.cb = sizeof(DisplayDevice);

    // get all display devices
    while (EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0))
        {
        ZeroMemory(&defaultMode, sizeof(DEVMODE));
        defaultMode.dmSize = sizeof(DEVMODE);
        if ( !EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName, ENUM_REGISTRY_SETTINGS, &defaultMode) )
                  OutputDebugString("Store default failed\n");

        if ((DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&
            !(DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
            {
            DEVMODE    DevMode;
            ZeroMemory(&DevMode, sizeof(DevMode));
            DevMode.dmSize = sizeof(DevMode);
            DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION
                        | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS ;
            Result = ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &DevMode, NULL, CDS_UPDATEREGISTRY, NULL);
            //Result = ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &DevMode, NULL, CDS_UPDATEREGISTRY, NULL);
            ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL);


            //The code below shows how to re-attach the secondary displays to the desktop

            //ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &defaultMode, NULL, CDS_UPDATEREGISTRY, NULL);
            //ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName, &defaultMode, NULL, CDS_UPDATEREGISTRY, NULL);

            }

        // Reinit DisplayDevice just to be extra clean

        ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
        DisplayDevice.cb = sizeof(DisplayDevice);
        DispNum++;
        } // end while for all display devices
}

int main()
{
    DetachDisplay();
    return 0;
}

但是,当我编译并运行它时,我得到的只是屏幕闪烁,好像它正在改变分辨率,但实际上并没有做任何有意义的事情(我确实注意到鼠标移动了......但除此之外什么都没有) .

也许其他人已经创建了一个实用程序来执行这个确切的功能,如果可以从命令行调用它,它会同样有效。

想法?

【问题讨论】:

    标签: c++ windows-7 winapi


    【解决方案1】:

    您可以在 Windows 7 中使用 SetDisplayConfig 来执行此操作。下面的示例禁用所有辅助屏幕。

    UINT32 NumPathArrayElements = 0;
    UINT32 NumModeInfoArrayElements = 0;
    LONG error = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS,&NumPathArrayElements,&NumModeInfoArrayElements); 
    std::vector<DISPLAYCONFIG_PATH_INFO> PathInfoArray(NumPathArrayElements);
    std::vector<DISPLAYCONFIG_MODE_INFO> ModeInfoArray(NumModeInfoArrayElements);
    error = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,&NumPathArrayElements, &PathInfoArray[0],&NumModeInfoArrayElements, &ModeInfoArray[0],NULL);
    
    for(unsigned int i=0;i<PathInfoArray.size();++i){
        if(PathInfoArray[i].sourceInfo.modeInfoIdx<ModeInfoArray.size()){
            int modeIndex=PathInfoArray[i].sourceInfo.modeInfoIdx;
            _POINTL pos=ModeInfoArray[modeIndex].sourceMode.position;
            if(pos.x!=0 || pos.y!=0){
                PathInfoArray[i].flags=0;
                break;
            }
        }
    }
    error = SetDisplayConfig(NumPathArrayElements, &PathInfoArray[0],NumModeInfoArrayElements, &ModeInfoArray[0],(SDC_APPLY | SDC_ALLOW_CHANGES | SDC_USE_SUPPLIED_DISPLAY_CONFIG));
    

    有关所用函数的更多信息:http://msdn.microsoft.com/en-us/library/ff539596%28v=VS.85%29.aspx

    【讨论】:

      【解决方案2】:
      using System;
      using System.Runtime.InteropServices;
      
      namespace MyNamespace
      {
      public class Win32
      {
          public struct POINTL
          {
              public Int32 x;
              public Int32 y;
          }
      
          public struct RECT
          {
              public long left;
              public long top;
              public long right;
              public long bottom;
          }
      
          [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;
          }
      
          [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
          public struct DEVMODE
          {
              public const int CCHDEVICENAME = 32;
              public const int CCHFORMNAME = 32;
      
              [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
              [System.Runtime.InteropServices.FieldOffset(0)]
              public string dmDeviceName;
              [System.Runtime.InteropServices.FieldOffset(32)]
              public Int16 dmSpecVersion;
              [System.Runtime.InteropServices.FieldOffset(34)]
              public Int16 dmDriverVersion;
              [System.Runtime.InteropServices.FieldOffset(36)]
              public Int16 dmSize;
              [System.Runtime.InteropServices.FieldOffset(38)]
              public Int16 dmDriverExtra;
              [System.Runtime.InteropServices.FieldOffset(40)]
              public DmFlags dmFields;
      
              [System.Runtime.InteropServices.FieldOffset(44)]
              Int16 dmOrientation;
              [System.Runtime.InteropServices.FieldOffset(46)]
              Int16 dmPaperSize;
              [System.Runtime.InteropServices.FieldOffset(48)]
              Int16 dmPaperLength;
              [System.Runtime.InteropServices.FieldOffset(50)]
              Int16 dmPaperWidth;
              [System.Runtime.InteropServices.FieldOffset(52)]
              Int16 dmScale;
              [System.Runtime.InteropServices.FieldOffset(54)]
              Int16 dmCopies;
              [System.Runtime.InteropServices.FieldOffset(56)]
              Int16 dmDefaultSource;
              [System.Runtime.InteropServices.FieldOffset(58)]
              Int16 dmPrintQuality;
      
              [System.Runtime.InteropServices.FieldOffset(44)]
              public POINTL dmPosition;
              [System.Runtime.InteropServices.FieldOffset(52)]
              public Int32 dmDisplayOrientation;
              [System.Runtime.InteropServices.FieldOffset(56)]
              public Int32 dmDisplayFixedOutput;
      
              [System.Runtime.InteropServices.FieldOffset(60)]
              public short dmColor; // See note below!
              [System.Runtime.InteropServices.FieldOffset(62)]
              public short dmDuplex; // See note below!
              [System.Runtime.InteropServices.FieldOffset(64)]
              public short dmYResolution;
              [System.Runtime.InteropServices.FieldOffset(66)]
              public short dmTTOption;
              [System.Runtime.InteropServices.FieldOffset(68)]
              public short dmCollate; // See note below!
              [System.Runtime.InteropServices.FieldOffset(72)]
              [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
              public string dmFormName;
              [System.Runtime.InteropServices.FieldOffset(102)]
              public Int16 dmLogPixels;
              [System.Runtime.InteropServices.FieldOffset(104)]
              public Int32 dmBitsPerPel;
              [System.Runtime.InteropServices.FieldOffset(108)]
              public Int32 dmPelsWidth;
              [System.Runtime.InteropServices.FieldOffset(112)]
              public Int32 dmPelsHeight;
              [System.Runtime.InteropServices.FieldOffset(116)]
              public Int32 dmDisplayFlags;
              [System.Runtime.InteropServices.FieldOffset(116)]
              public Int32 dmNup;
              [System.Runtime.InteropServices.FieldOffset(120)]
              public Int32 dmDisplayFrequency;
          }
      
          [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)]
          public struct SECURITY_ATTRIBUTES
          {
              public int nLength;
              public IntPtr lpSecurityDescriptor;
              public int bInheritHandle;
          }
      
          [Flags]
          public enum ACCESS_MASK : uint
          {
              DELETE = 0x00010000,
              READ_CONTROL = 0x00020000,
              WRITE_DAC = 0x00040000,
              WRITE_OWNER = 0x00080000,
              SYNCHRONIZE = 0x00100000,
      
              STANDARD_RIGHTS_REQUIRED = 0x000F0000,
      
              STANDARD_RIGHTS_READ = 0x00020000,
              STANDARD_RIGHTS_WRITE = 0x00020000,
              STANDARD_RIGHTS_EXECUTE = 0x00020000,
      
              STANDARD_RIGHTS_ALL = 0x001F0000,
      
              SPECIFIC_RIGHTS_ALL = 0x0000FFFF,
      
              ACCESS_SYSTEM_SECURITY = 0x01000000,
      
              MAXIMUM_ALLOWED = 0x02000000,
      
              GENERIC_READ = 0x80000000,
              GENERIC_WRITE = 0x40000000,
              GENERIC_EXECUTE = 0x20000000,
              GENERIC_ALL = 0x10000000,
      
              DESKTOP_READOBJECTS = 0x00000001,
              DESKTOP_CREATEWINDOW = 0x00000002,
              DESKTOP_CREATEMENU = 0x00000004,
              DESKTOP_HOOKCONTROL = 0x00000008,
              DESKTOP_JOURNALRECORD = 0x00000010,
              DESKTOP_JOURNALPLAYBACK = 0x00000020,
              DESKTOP_ENUMERATE = 0x00000040,
              DESKTOP_WRITEOBJECTS = 0x00000080,
              DESKTOP_SWITCHDESKTOP = 0x00000100,
      
              WINSTA_ENUMDESKTOPS = 0x00000001,
              WINSTA_READATTRIBUTES = 0x00000002,
              WINSTA_ACCESSCLIPBOARD = 0x00000004,
              WINSTA_CREATEDESKTOP = 0x00000008,
              WINSTA_WRITEATTRIBUTES = 0x00000010,
              WINSTA_ACCESSGLOBALATOMS = 0x00000020,
              WINSTA_EXITWINDOWS = 0x00000040,
              WINSTA_ENUMERATE = 0x00000100,
              WINSTA_READSCREEN = 0x00000200,
      
              WINSTA_ALL_ACCESS = 0x0000037F
          }
      
          [Flags()]
          public enum ChangeDisplaySettingsFlags : uint
          {
              CDS_NONE = 0,
              CDS_UPDATEREGISTRY = 0x00000001,
              CDS_TEST = 0x00000002,
              CDS_FULLSCREEN = 0x00000004,
              CDS_GLOBAL = 0x00000008,
              CDS_SET_PRIMARY = 0x00000010,
              CDS_VIDEOPARAMETERS = 0x00000020,
              CDS_ENABLE_UNSAFE_MODES = 0x00000100,
              CDS_DISABLE_UNSAFE_MODES = 0x00000200,
              CDS_RESET = 0x40000000,
              CDS_RESET_EX = 0x20000000,
              CDS_NORESET = 0x10000000
          }
      
          [Flags()]
          public enum DISP_CHANGE : int
          {
              SUCCESSFUL = 0,
              RESTART = 1,
              FAILED = -1,
              BADMODE = -2,
              NOTUPDATED = -3,
              BADFLAGS = -4,
              BADPARAM = -5,
              BADDUALVIEW = -6
          }
      
          [Flags()]
          public enum DmFlags : int
          {
              DM_ORIENTATION = 0x00000001,
              DM_PAPERSIZE = 0x00000002,
              DM_PAPERLENGTH = 0x00000004,
              DM_PAPERWIDTH = 0x00000008,
              DM_SCALE = 0x00000010,
              DM_POSITION = 0x00000020,
              DM_NUP = 0x00000040,
              DM_DISPLAYORIENTATION = 0x00000080,
              DM_COPIES = 0x00000100,
              DM_DEFAULTSOURCE = 0x00000200,
              DM_PRINTQUALITY = 0x00000400,
              DM_COLOR = 0x00000800,
              DM_DUPLEX = 0x00001000,
              DM_YRESOLUTION = 0x00002000,
              DM_TTOPTION = 0x00004000,
              DM_COLLATE = 0x00008000,
              DM_FORMNAME = 0x00010000,
              DM_LOGPIXELS = 0x00020000,
              DM_BITSPERPEL = 0x00040000,
              DM_PELSWIDTH = 0x00080000,
              DM_PELSHEIGHT = 0x00100000,
              DM_DISPLAYFLAGS = 0x00200000,
              DM_DISPLAYFREQUENCY = 0x00400000,
              DM_ICMMETHOD = 0x00800000,
              DM_ICMINTENT = 0x01000000,
              DM_MEDIATYPE = 0x02000000,
              DM_DITHERTYPE = 0x04000000,
              DM_PANNINGWIDTH = 0x08000000,
              DM_PANNINGHEIGHT = 0x10000000,
              DM_DISPLAYFIXEDOUTPUT = 0x20000000
          }
      
          [DllImport("kernel32.dll")]
          public static extern uint GetLastError();
      
          [DllImport("user32.dll", EntryPoint = "CreateWindowStation", CharSet = CharSet.Unicode, SetLastError = true)]
          public static extern IntPtr CreateWindowStation(
              [MarshalAs(UnmanagedType.LPWStr)] string name,
              [MarshalAs(UnmanagedType.U4)] uint dwFlags,
              [MarshalAs(UnmanagedType.U4)] ACCESS_MASK desiredAccess,
              [MarshalAs(UnmanagedType.LPStr)] ref SECURITY_ATTRIBUTES attributes
          );
          [DllImport("user32.dll", EntryPoint = "CreateWindowStation", CharSet = CharSet.Unicode, SetLastError = true)]
          public static extern IntPtr CreateWindowStation(
              [MarshalAs(UnmanagedType.LPWStr)] string name,
              [MarshalAs(UnmanagedType.U4)] uint dwFlags,
              [MarshalAs(UnmanagedType.U4)] ACCESS_MASK desiredAccess,
              [MarshalAs(UnmanagedType.U4)] uint attributes
          );
      
          [DllImport("user32.dll", EntryPoint = "CreateDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
          public static extern IntPtr CreateDesktop(
              [MarshalAs(UnmanagedType.LPWStr)] string desktopName,
              [MarshalAs(UnmanagedType.LPWStr)] string device, // must be null.
              [MarshalAs(UnmanagedType.LPWStr)] string deviceMode, // must be null,
              [MarshalAs(UnmanagedType.U4)] int flags,  // use 0
              [MarshalAs(UnmanagedType.U4)] ACCESS_MASK accessMask,
              [MarshalAs(UnmanagedType.LPStruct)] ref SECURITY_ATTRIBUTES attributes
          );
          [DllImport("user32.dll", EntryPoint = "CreateDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
          public static extern IntPtr CreateDesktop(
              [MarshalAs(UnmanagedType.LPWStr)] string desktopName,
              [MarshalAs(UnmanagedType.LPWStr)] string device, // must be null.
              [MarshalAs(UnmanagedType.LPWStr)] string deviceMode, // must be null,
              [MarshalAs(UnmanagedType.U4)] int flags,  // use 0
              [MarshalAs(UnmanagedType.U4)] ACCESS_MASK accessMask,
              [MarshalAs(UnmanagedType.U4)] uint attributes
          );
      
          [DllImport("user32.dll", EntryPoint = "CloseDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool CloseDesktop(IntPtr handle);
      
          [DllImport("user32.dll")]
          public static extern IntPtr OpenWindowStation(
              [MarshalAs(UnmanagedType.LPWStr)]string name,
              [MarshalAs(UnmanagedType.Bool)] bool fInherit,
              [MarshalAs(UnmanagedType.U4)] uint desiredAccess
          );
      
          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool SetProcessWindowStation(IntPtr hWinSta);
      
          [DllImport("user32.dll")]
          public static extern IntPtr GetProcessWindowStation();
      
          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool CloseWindowStation(IntPtr hWinSta);
      
          [DllImport("user32.dll")]
          public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
      
          [DllImport("user32.dll")]
          public static extern int EnumDisplaySettingsEx(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode, uint dwFlags);
      
          [DllImport("user32.dll")]
          public static extern int ChangeDisplaySettingsEx(
                  string lpszDeviceName,
                  ref DEVMODE lpDevMode,
                  IntPtr hwnd,
                  ChangeDisplaySettingsFlags dwflags,
                  IntPtr lParam);
          [DllImport("user32.dll")]
          public static extern int ChangeDisplaySettingsEx(
                  string lpszDeviceName,
                  IntPtr lpDevMode,
                  IntPtr hwnd,
                  ChangeDisplaySettingsFlags dwflags,
                  IntPtr lParam);
      
          [DllImport("user32.dll")]
          public static extern IntPtr GetDC(IntPtr hWnd);
      
          [DllImport("user32.dll")]
          public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
      
          [DllImport("user32.dll")]
          public static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);
      
          [DllImport("user32.dll")]
          static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
      
          public const int ENUM_CURRENT_SETTINGS = -1;
          public const int ENUM_REGISTRY_SETTINGS = -2;
          public const int CWF_CREATE_ONLY = 1;
          public const int DF_ALLOWOTHERACCOUNTHOOK = 1;
          public const int DT_TOP = 0x00000000;
          public const int DT_LEFT = 0x00000000;
          public const int DT_CENTER = 0x00000001;
          public const int DT_RIGHT = 0x00000002;
          public const int DT_VCENTER = 0x00000004;
          public const int DT_BOTTOM = 0x00000008;
          public const int DT_WORDBREAK = 0x00000010;
          public const int DT_SINGLELINE = 0x00000020;
          public const int DT_EXPANDTABS = 0x00000040;
          public const int DT_TABSTOP = 0x00000080;
          public const int DT_NOCLIP = 0x00000100;
          public const int DT_EXTERNALLEADING = 0x00000200;
          public const int DT_CALCRECT = 0x00000400;
          public const int DT_NOPREFIX = 0x00000800;
          public const int DT_INTERNAL = 0x00001000;
      
      }
      public class Gdi32
      {
          [Flags()]
          public enum DeviceCap : int
          {
              DRIVERVERSION = 0,
              TECHNOLOGY = 2,
              HORZSIZE = 4,
              VERTSIZE = 6,
              HORZRES = 8,
              VERTRES = 10,
              BITSPIXEL = 12,
              PLANES = 14,
              NUMBRUSHES = 16,
              NUMPENS = 18,
              NUMMARKERS = 20,
              NUMFONTS = 22,
              NUMCOLORS = 24,
              PDEVICESIZE = 26,
              CURVECAPS = 28,
              LINECAPS = 30,
              POLYGONALCAPS = 32,
              TEXTCAPS = 34,
              CLIPCAPS = 36,
              RASTERCAPS = 38,
              ASPECTX = 40,
              ASPECTY = 42,
              ASPECTXY = 44,
              SHADEBLENDCAPS = 45,
              LOGPIXELSX = 88,
              LOGPIXELSY = 90,
              SIZEPALETTE = 104,
              NUMRESERVED = 106,
              COLORRES = 108,
              PHYSICALWIDTH = 110,
              PHYSICALHEIGHT = 111,
              PHYSICALOFFSETX = 112,
              PHYSICALOFFSETY = 113,
              SCALINGFACTORX = 114,
              SCALINGFACTORY = 115,
              VREFRESH = 116,
              DESKTOPVERTRES = 117,
              DESKTOPHORZRES = 118,
              BLTALIGNMENT = 119
          }
      
          [DllImport("gdi32.dll")]
          public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
      
          [DllImport("gdi32.dll")]
          public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
      
          [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
          public static extern bool DeleteDC([In] IntPtr hdc);
      
          [DllImport("gdi32.dll")]
          public static extern int SetTextColor(IntPtr hdc, int crColor);
      
          [DllImport("gdi32.dll")]
          public static extern int SetBkColor(IntPtr hdc, int crColor);
      
      }
      public class Display
      {
          public static void EnumDisplayDevices()
          {
              uint deviceID = 0;
              Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
              d.cb = Marshal.SizeOf(d);
              Win32.DEVMODE dm = GetDevMode();
              while (Win32.EnumDisplayDevices(null, deviceID, ref d, 1))
              {
      
                  // Print Device Information 
                  Console.WriteLine("\nDeviceID: {5} \nDeviceName: {0} \nDeviceString: {1}\nDeviceID (GUID): {2}\nDeviceKey {3}\nStateFlags {4}\n",
                      d.DeviceName, d.DeviceString, d.DeviceID, d.DeviceKey, d.StateFlags, deviceID);
                  deviceID++;
      
              }
          }
      
          private static Win32.DEVMODE GetDevMode()
          {
              Win32.DEVMODE dm = new Win32.DEVMODE();
              dm.dmDeviceName = new String(new char[32]);
              dm.dmFormName = new String(new char[32]);
              dm.dmSize = (short)Marshal.SizeOf(dm);
              return dm;
          }
      
          public static bool DetachDisplayDevice(uint deviceID)
          {
              bool rval = false;
              Win32.DEVMODE dm = GetDevMode();
              Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
              d.cb = Marshal.SizeOf(d);
      
              // Get the display device
              if (!Win32.EnumDisplayDevices(null, deviceID, ref d, 0))
              {
                  Console.WriteLine("Device not found!");
                  return false;
              }
      
              // Test that the display is actually attached to the desktop - bail if it is not
              if ((d.StateFlags & Win32.DisplayDeviceStateFlags.AttachedToDesktop) == 0)
              {
                  Console.WriteLine("Display Device {0} is not attached to this desktop!", d.DeviceName);
                  return false;
              }
      
              // Get current device settings 
              if (0 == Win32.EnumDisplaySettingsEx(d.DeviceName, Win32.ENUM_CURRENT_SETTINGS, ref dm, 0))
              {
                  Console.WriteLine("Settings for {0} could not be enumerated!", d.DeviceName);
                  return false;
              }
      
              // Prepare for detach
              dm.dmPelsWidth = 0;
              dm.dmPelsHeight = 0;
              dm.dmFields = Win32.DmFlags.DM_POSITION | Win32.DmFlags.DM_PELSWIDTH | Win32.DmFlags.DM_PELSHEIGHT;
              //dm.dmFields = (int) (DmFlags.DM_POSITION);  
      
              // Test the change
              int iRet = Win32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, Win32.ChangeDisplaySettingsFlags.CDS_TEST, IntPtr.Zero);
              if (iRet == (int)Win32.DISP_CHANGE.FAILED)
              {
                  Console.WriteLine("Unable To Process Your Request.");
                  return false;
              }
      
              // Now do it for real
              iRet = Win32.ChangeDisplaySettingsEx(
                  d.DeviceName,
                  ref dm,
                  IntPtr.Zero,
                  Win32.ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | Win32.ChangeDisplaySettingsFlags.CDS_RESET, 
                  IntPtr.Zero
                  );
              //Win32.ChangeDisplaySettingsEx((string) null, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);  // Not needed for detach with CDS_RESET set.
      
              switch (iRet)
              {
                  case (int)Win32.DISP_CHANGE.SUCCESSFUL:
                      {
                          Console.WriteLine("Detached display: {0} \n", d.DeviceName);
                          rval = true;
                          break;
                      }
                  case (int)Win32.DISP_CHANGE.RESTART:
                      {
                          Console.WriteLine("A reboot is required for the change to take affect.\n");
                          break;
                      }
                  default:
                      {
                          Console.WriteLine("Failed! Return value: {0}\n", iRet);
                          break;
                      }
              }
              return rval;
          }
      
          public static bool AttachDisplayDevice(uint deviceID)
          {
              bool rval = false;
              Win32.DEVMODE dm = GetDevMode();
              Win32.DISPLAY_DEVICE d = new Win32.DISPLAY_DEVICE();
              d.cb = Marshal.SizeOf(d);
              int nWidth;
              IntPtr hdc;
      
              // Get current device context width
              hdc = Win32.GetDC(IntPtr.Zero);
              nWidth = Gdi32.GetDeviceCaps(hdc, (int)Gdi32.DeviceCap.HORZRES);
              Win32.ReleaseDC(IntPtr.Zero, hdc);
      
      
              // Get the display device
              if (!Win32.EnumDisplayDevices(null, deviceID, ref d, 0))
              {
                  Console.WriteLine("Device not found!");
                  return false;
              }
      
              // Test that the display is NOT actually attached to the desktop - bail if it is
              if ((d.StateFlags & Win32.DisplayDeviceStateFlags.AttachedToDesktop) != 0)
              {
                  Console.WriteLine("Display Device {0} is already attached to this desktop!", d.DeviceName);
                  return false;
              }
      
              // Get current device settings 
              if (0 == Win32.EnumDisplaySettingsEx(d.DeviceName, Win32.ENUM_REGISTRY_SETTINGS, ref dm, 0))
              {
                  Console.WriteLine("Settings for {0} could not be enumerated!", d.DeviceName);
                  return false;
              }
      
              // Prepare for attach
              dm.dmPosition.x += nWidth;
              dm.dmFields = Win32.DmFlags.DM_POSITION;
      
              // Test the change
              int iRet = Win32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, Win32.ChangeDisplaySettingsFlags.CDS_TEST, IntPtr.Zero);
              if (iRet == (int)Win32.DISP_CHANGE.FAILED)
              {
                  Console.WriteLine("Unable To Process Your Request.");
                  return false;
              }
      
              // Now do it for real
              iRet = Win32.ChangeDisplaySettingsEx(
                  d.DeviceName,
                  ref dm,
                  IntPtr.Zero,
                  Win32.ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | Win32.ChangeDisplaySettingsFlags.CDS_NORESET,
                  IntPtr.Zero
                  );
              Win32.ChangeDisplaySettingsEx((string)null, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
      
              switch (iRet)
              {
                  case (int)Win32.DISP_CHANGE.SUCCESSFUL:
                      {
                          Console.WriteLine("Attached display: {0} \n", d.DeviceName);
                          rval = true;
                          break;
                      }
                  case (int)Win32.DISP_CHANGE.RESTART:
                      {
                          Console.WriteLine("A reboot is required for the change to take affect.\n");
                          break;
                      }
                  default:
                      {
                          Console.WriteLine("Failed! Return value: {0}\n", iRet);
                          break;
                      }
              }
              return rval;
          }
      }
      }
      

      【讨论】:

      • 在将所有 pinvoke 内容复制粘贴在一起并严重失败后,我拿走了你的代码。 DetachDisplayDevice 工作完美,但我无法让AttachDisplayDevice 工作。无论我为DEVMODE 设置什么,ChangeDisplaySettingsEx 一直为我返回Win32.DISP_CHANGE.FAILED。你是否也遇到过这个问题?你有什么解决办法吗?
      【解决方案3】:

      我知道这是一个旧线程,但我在研究自己的问题时遇到了它:寻找一种在控制台会话(因此 WinSta0)被锁定时在分离的辅助显示设备上显示非交互式桌面的方法在 Windows 7 上。

      回答原问题:

      分离显示设备时:

      DEVMODE.dmPelsWidth = 0;
      DEVMODE.dmPelsHeight = 0;
      DEVMODE.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
      ChangeDisplaySettingsEx(....    
      

      如果您要分离显示器,如果您在原始调用中指定 CDS_RESETCDS_UPDATEREGISTRY,则不需要第二次调用 ChangeDisplaySettings(Ex)。但是,如果您要连接显示器,则似乎确实需要第二次调用 ChangeDisplaySettings(或者,至少,我还没有找到解决方法)。

      我在下面提供了可用的 C# 代码。这是一个可以使用的 PowerShell 脚本

      param(
          [Parameter(Mandatory=$true, Position = 0)] [string]$Function,
          [Parameter(Mandatory=$false, Position = 1)] [int]$DeviceID
      )
      clear-host
      add-type -TypeDefinition (Get-Content -Path .\Display.cs | Out-String)
      Switch ($Function) {
          'Enum' {[MyNamespace.Display]::EnumDisplayDevices()}
          'Detach' {[MyNamespace.Display]::DetachDisplayDevice($DeviceID)}
          'Attach' {[MyNamespace.Display]::AttachDisplayDevice($DeviceID)}
          Default { write-host 'There is no "' $Function '" function available!' }
      }
      

      【讨论】:

      • 我肯定有兴趣看看你想出了什么 C# 代码。
      • Nathan,我不得不去掉很多 cmets,但我把它贴在了底部。它是为与 PowerShell 一起使用而编写的。我在这篇文章中包含了一个小例子。享受吧。
      【解决方案4】:

      上面的代码 sn-p 实际上分离了辅助显示设备,而不是监视器。同一个显示设备可能包含多个监视器。我还没有成功解决这个问题

      【讨论】:

        猜你喜欢
        • 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
        相关资源
        最近更新 更多