用于分离辅助监视器的C ++应用程序

时间:2010-10-14 15:17:34

标签: c++ windows-7 winapi

我正在尝试创建一个从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;
}

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

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

思想?

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分: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;
    }
}
}

答案 2 :(得分:1)

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

回答原始问题:

拆卸显示设备时:

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

如果您要分离显示,如果您在原始呼叫中指定ChangeDisplaySettings(Ex)CDS_RESET,则无需再次拨打CDS_UPDATEREGISTRY。但是,如果您要附加一个显示器,则第二次调用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!' }
}

答案 3 :(得分:0)

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