8

Windows API を使用してプライマリ モニターを設定しようとしています。動作していないようです - 画面がフリックするだけで、何も起こりません。

    public const int DM_ORIENTATION = 0x00000001;
public const int DM_PAPERSIZE = 0x00000002;
public const int DM_PAPERLENGTH = 0x00000004;
public const int DM_PAPERWIDTH = 0x00000008;
public const int DM_SCALE = 0x00000010;
public const int DM_POSITION = 0x00000020;
public const int DM_NUP = 0x00000040;
public const int DM_DISPLAYORIENTATION = 0x00000080;
public const int DM_COPIES = 0x00000100;
public const int DM_DEFAULTSOURCE = 0x00000200;
public const int DM_PRINTQUALITY = 0x00000400;
public const int DM_COLOR = 0x00000800;
public const int DM_DUPLEX = 0x00001000;
public const int DM_YRESOLUTION = 0x00002000;
public const int DM_TTOPTION = 0x00004000;
public const int DM_COLLATE = 0x00008000;
public const int DM_FORMNAME = 0x00010000;
public const int DM_LOGPIXELS = 0x00020000;
public const int DM_BITSPERPEL = 0x00040000;
public const int DM_PELSWIDTH = 0x00080000;
public const int DM_PELSHEIGHT = 0x00100000;
public const int DM_DISPLAYFLAGS = 0x00200000;
public const int DM_DISPLAYFREQUENCY = 0x00400000;
public const int DM_ICMMETHOD = 0x00800000;
public const int DM_ICMINTENT = 0x01000000;
public const int DM_MEDIATYPE = 0x02000000;
public const int DM_DITHERTYPE = 0x04000000;
public const int DM_PANNINGWIDTH = 0x08000000;
public const int DM_PANNINGHEIGHT = 0x10000000;
public const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;

public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int CDS_SET_PRIMARY = 0x00000010;

public const long DISP_CHANGE_SUCCESSFUL = 0;
public const long DISP_CHANGE_RESTART = 1;
public const long DISP_CHANGE_FAILED = -1;
public const long DISP_CHANGE_BADMODE = -2;
public const long DISP_CHANGE_NOTUPDATED = -3;
public const long DISP_CHANGE_BADFLAGS = -4;
public const long DISP_CHANGE_BADPARAM = -5;
public const long DISP_CHANGE_BADDUALVIEW = -6;

    public static void SetPrimary(Screen screen)
{
  DISPLAY_DEVICE d = new DISPLAY_DEVICE();
  DEVMODE dm = new DEVMODE();
  d.cb = Marshal.SizeOf(d);
  uint deviceID = 1;
  User_32.EnumDisplayDevices(null, deviceID, ref  d, 0); // 
  User_32.EnumDisplaySettings(d.DeviceName, 0, ref dm);
  dm.dmPelsWidth = 2560;
  dm.dmPelsHeight = 1600;
  dm.dmPositionX = screen.Bounds.Right;
  dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
  User_32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, CDS_SET_PRIMARY, IntPtr.Zero);
}

私はこのようにメソッドを呼び出します:

SetPrimary(Screen.AllScreens[1])

何か案は?

4

4 に答える 4

6

私はC#から、そしてここでのアドバイスに従ってC ++で試した後の両方で、まったく同じ問題に遭遇しました。Microsoft のドキュメントで明確にされていないことは、モニターの位置を (0, 0 ) DEVMODE 構造体。もちろん、これは、新しいプライマリ モニターに対して同じ場所に留まるように、他のモニターの位置も移動する必要があることを意味します。ドキュメント ( http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx ) に従って、CDS_NORESET フラグを使用して各モニターの ChangeDisplaySettingsEx を呼び出してから、すべてが null の最終呼び出し。

次のコードは私のために働いた:

    public static void SetAsPrimaryMonitor(uint id)
    {
        var device = new DISPLAY_DEVICE();
        var deviceMode = new DEVMODE();
        device.cb = Marshal.SizeOf(device);

        NativeMethods.EnumDisplayDevices(null, id, ref device, 0);
        NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode);
        var offsetx = deviceMode.dmPosition.x;
        var offsety = deviceMode.dmPosition.y;
        deviceMode.dmPosition.x = 0;
        deviceMode.dmPosition.y = 0;

        NativeMethods.ChangeDisplaySettingsEx(
            device.DeviceName, 
            ref deviceMode, 
            (IntPtr)null, 
            (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), 
            IntPtr.Zero);

        device = new DISPLAY_DEVICE();
        device.cb = Marshal.SizeOf(device);

        // Update remaining devices
        for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++)
        {
            if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id)
            {
                device.cb = Marshal.SizeOf(device);
                var otherDeviceMode = new DEVMODE();

                NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode);

                otherDeviceMode.dmPosition.x -= offsetx;
                otherDeviceMode.dmPosition.y -= offsety;

                NativeMethods.ChangeDisplaySettingsEx(
                    device.DeviceName,
                    ref otherDeviceMode,
                    (IntPtr)null,
                    (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
                    IntPtr.Zero);

            }

            device.cb = Marshal.SizeOf(device);
        }

        // Apply settings
        NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null);
    }

2 番目のパラメーターとして DEVMODE 構造体を使用した ChangeDisplaySettingsEx の署名では、明らかに IntPtr.Zero を渡すことができないことに注意してください。同じ extern 呼び出しに対して 2 つの異なる署名を作成します。つまり、

    [DllImport("user32.dll")]
    public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
于 2014-04-13T14:49:41.067 に答える
3

私はwinapiのようなものであなたを本当に助けることはできませんが、Nvidiaカードを使用している場合は、NVcontrolPanel Apiドキュメントを参照してください。 次に、Hopeを使用してセカンダリ出力をプライマリにすることrundll32.exe NvCpl.dll,dtcfg primary 2 ができます。

于 2008-10-12T10:34:49.387 に答える
3

ChangeDisplaySettingsEx のドキュメントによると、「dmSize メンバーは DEVMODE 構造体のサイズ (バイト単位) に初期化する必要があります」。さらに、EnumDisplaySettings のドキュメントには、「EnumDisplaySettings を呼び出す前に、dmSize メンバーを sizeof(DEVMODE) に設定し、dmDriverExtra メンバーを設定して、プライベート ドライバー データの受信に使用できる追加領域のサイズをバイト単位で示すように」と記載されています。質問で指定されたコードサンプルでは、​​これが起こっているとは思いません。それが失敗する理由の 1 つです。

さらに、質問に含まれていない DEVMODE および DISPLAY_DEVICE 構造体の定義にエラーがある可能性があります。最初に C/C++ から動作させるという Roger Lipscombe の提案は、この種の問題を除外する優れた方法です。

最後に、ChangeDisplaySettingsEx からの戻り値を確認し、失敗の原因の手掛かりが得られるかどうかを確認します。

于 2008-10-12T14:38:39.457 に答える