C++分离辅助显示器的应用程序

发布于 2024-09-27 07:41:02 字数 2650 浏览 2 评论 0原文

我正在尝试创建一个应用程序来将辅助显示器与 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;
}

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

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

想法?

I am trying to create an application to detach a secondary monitor from Windows boxes (long story).

Here is Microsoft's sample code that I used as a basis:
http://support.microsoft.com/kb/308216/en-us

Here is my code:

#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;
}

However, when I compile and run it all I get is the screen to flicker as if it is changing resolutions but it doesn't actually do anything meaningful (I do notice the mouse moved...but other than that nothing).

Perhaps someone else has already created a utility to do this exact functionality, which would work just as good if it can be invoked from the command line.

Thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

那小子欠揍 2024-10-04 07:41:02

您可以使用 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

You can use SetDisplayConfig to do this in windows 7. The example below disables all secondary screens.

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));

For a bit more info on the functions used: http://msdn.microsoft.com/en-us/library/ff539596%28v=VS.85%29.aspx

对岸观火 2024-10-04 07:41:02
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;
    }
}
}
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;
    }
}
}
德意的啸 2024-10-04 07:41:02

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

回答原始问题:

显示设备时:

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

如果要分离显示器,则如果您指定 CDS_RESET 和 <,则无需第二次调用 ChangeDisplaySettings(Ex) code>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!' }
}

I know this is a way old thread but I came upon it while researching my own problem: Looking for a method for displaying a non-interactive desktop on a detached secondary display device while the console session (and therefore WinSta0) is locked on Windows 7.

Answer to original question:

When detaching a display device:

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

If you are detaching a display, the second call to ChangeDisplaySettings(Ex) is unnecessary if you specify CDS_RESET along with CDS_UPDATEREGISTRY in the original call. However, if you are attaching a display, the second call to ChangeDisplaySettings does appear to be required (or, at least, I haven't figured out a way around it).

I provide working C# code below. Here is a PowerShell script to use with it

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!' }
}
久隐师 2024-10-04 07:41:02

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

The code snippet above actually detaches secondary display device, not monitor. The same display device may contain multiple monitors. I haven't succeeded with this problem yet

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文