C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

C# Windows設定の"画面の向き"を変えたい

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■96806 / inTopicNo.1)  C# Windows設定の"画面の向き"を変えたい
  
□投稿者/ りんく (1回)-(2021/02/11(Thu) 16:22:09)

分類:[C#] 

2021/02/11(Thu) 17:06:07 編集(投稿者)
開発環境
 Visual Studio 2019
 C#
 WPF
 .NET Framework 4.8
動作環境
 Windows 10

C#のWPFアプリからWindows設定の画面の向きを変更したいのですが可能でしょうか?
変更したいのは下記の設定です。
 設定->システム->ディスプレイ->画面の向き
 →横 or 縦 or 横(反対向き) or 縦(反対向き)

http://bbs.wankuma.com/index.cgi?mode=al2&namber=78110&KLOG=133
を参考に、SetDisplayAutoRotationPreferencesをやってみたのですが
正常終了はしますが何も変わりませんでした。

-- 画面の向き変更クラス
    public class AutoRotation
    {
        [Flags]
        public enum AR_STATE : int
        {
            AR_ENABLED = 0x0,
            AR_DISABLED = 0x1,
            AR_SUPPRESSED = 0x2,
            AR_REMOTESESSION = 0x4,
            AR_MULTIMON = 0x8,
            AR_NOSENSOR = 0x10,
            AR_NOT_SUPPORTED = 0x20,
            AR_DOCKED = 0x40,
            AR_LAPTOP = 0x80
        };

        public enum ORIENTATION_PREFERENCE : int
        {
            ORIENTATION_PREFERENCE_NONE = 0x0,
            ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,
            ORIENTATION_PREFERENCE_PORTRAIT = 0x2,
            ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
            ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
        };

        public static bool IsRotateEnabled()
        {
            AR_STATE autoRotationState = 0;
            bool success = GetAutoRotationState(out autoRotationState);
            if (!success)
            {
                return false;   // disable
            }

            return autoRotationState.HasFlag(AR_STATE.AR_ENABLED);
        }

        public static ORIENTATION_PREFERENCE GetRotation()
        {
            ORIENTATION_PREFERENCE orientation;
            bool success = GetDisplayAutoRotationPreferences(out orientation);
            if (!success)
            {
                return ORIENTATION_PREFERENCE.ORIENTATION_PREFERENCE_NONE;
            }

            return orientation;
        }

        public static bool SetRotation(ORIENTATION_PREFERENCE orientation)
        {
            return SetDisplayAutoRotationPreferences(orientation);
        }

        [DllImport("user32.dll")]
        private static extern bool GetAutoRotationState(out AR_STATE pState);

        [DllImport("user32.dll")]
        private static extern bool GetDisplayAutoRotationPreferences(out ORIENTATION_PREFERENCE pOrientation);

        [DllImport("user32.dll")]
        private static extern bool SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE orientation);
    }

-- 呼び出し
Console.WriteLine($"{AutoRotation.GetRotation()}");
AutoRotation.SetRotation(AutoRotation.ORIENTATION_PREFERENCE.ORIENTATION_PREFERENCE_PORTRAIT);

引用返信 編集キー/
■96807 / inTopicNo.2)  Re[1]: C# Windows設定の"画面の向き"を変えたい
□投稿者/ Hongliang (1152回)-(2021/02/11(Thu) 21:23:08)
SetDisplayAutoRotationPreferences関数は、docsの該当ページに記述がありますが
https://docs.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-setdisplayautorotationpreferences
> Sets the screen auto-rotation preferences for the current process.
の通り、「画面の自動回転」に対して、自プロセスがどう振舞うかという設定ですね。
自動回転ってのはタブレットモードで左側を上にもっていったときとかになるやつです。

画面の回転設定は、ChangeDisplaySetting関数を使用すると良いようです。
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa
使用するDEVMODE構造体はかなり巨大で共用体も含んでいているなど複雑な構造ですが、
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodea
次のページなど翻訳済みのコードを掲載しているもいくつかあります(screen orientationについての記述もありますね)。
https://www.codeproject.com/articles/36664/changing-display-settings-programmatically
現在の状態を取得するのには、上記codeprojectのページにもありますがEnumDisplaySettingsを使用できます。

考慮するべき点として、マルチディスプレイ、リモートデスクトップ、などのときにどうするかというのが考えらえます。
試してないから分からないけどCDS_UPDATEREGISTRYの有無による再起動(再ログオン?)以降にも設定を残すかどうかってのもあるかな?
引用返信 編集キー/
■96809 / inTopicNo.3)  Re[2]: C# Windows設定の"画面の向き"を変えたい
□投稿者/ りんく (2回)-(2021/02/12(Fri) 09:13:52)
No96807 (Hongliang さん) に返信
返信ありがとうございます。

> 画面の回転設定は、ChangeDisplaySetting関数を使用すると良いようです。
こちらの関数でやりたいことができました。

> 考慮するべき点として、マルチディスプレイ、リモートデスクトップ、などのときにどうするかというのが考えらえます。
考慮点ご指摘いただきありがとうございます。
マルチディスプレイやリモートデスクトップは使用しない端末になりますのでこのあたりの考慮は必要ありませんでした。

> 試してないから分からないけどCDS_UPDATEREGISTRYの有無による再起動(再ログオン?)以降にも設定を残すかどうかってのもあるかな?
再起動しても設定は残しておきたいので、
dwflagsにCDS_UPDATEREGISTRYを指定して、再起動後も設定が残っていることを確認できました。
※dwflagsが0の場合は、再起動後には戻っていました。

コードを以下に記載しておきます。

-- 定義
/// <summary> 横 </summary>
public const uint DMDO_DEFAULT = 0;
/// <summary> 縦 </summary>
public const uint DMDO_90 = 1;
/// <summary> 横(反対向き) </summary>
public const uint DMDO_180 = 2;
/// <summary> 縦(反対向き) </summary>
public const uint DMDO_270 = 3;

/// <summary> 現在の画面のグラフィックスモードを動的に変更する。 </summary>
public const int CDS_UPDATE = 0;
/// <summary> 現在の画面のグラフィックスモードを動的に変更し、レジストリへの登録を更新する。 </summary>
public const int CDS_UPDATEREGISTRY = 1;

/// <summary> 現在の表示モード </summary>
public const int ENUM_CURRENT_SETTINGS = -1;
/// <summary> レジストリに保存されている現在の表示モード </summary>
public const int ENUM_REGISTRY_SETTINGS = -2;

[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean EnumDisplaySettings(
    [param: MarshalAs(UnmanagedType.LPTStr)] string lpszDeviceName,
    [param: MarshalAs(UnmanagedType.U4)] int iModeNum,
    [In, Out] ref DEVMODE lpDevMode);

[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int ChangeDisplaySettings(
    [In, Out] ref DEVMODE lpDevMode,
    [param: MarshalAs(UnmanagedType.U4)] uint dwflags);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    // 省略
}

[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
    // 省略
}

-- 向きを変えるメソッド
void RotateScreen(uint orientation)
{
    DEVMODE mode = new DEVMODE();
    if (EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref mode))
    {
        // Succeeded
    }
    // 画面向き
    mode.dmDisplayOrientation = orientation;

    // Swapping width and height;
    uint temp = mode.dmPelsWidth;
    mode.dmPelsWidth = mode.dmPelsHeight;
    mode.dmPelsHeight = temp;

    // Capturing the operation result
    int result = ChangeDisplaySettings(ref mode, CDS_UPDATEREGISTRY);
}

-- 呼び元
// 縦
RotateScreen(DMDO_90);
// 横
RotateScreen(DMDO_DEFAULT);

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ