DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ChangeDisplaySettingsExの回転処理

環境/言語:[Windows7 / VC#2010+WinApi32]
分類:[.NET]

お世話になっております。
ChangeDisplaySettingsExを使いディスプレイの縦と横の
切り替えを考えております。
(回転のない解像度の切り替えはできております)
しかし、幅と高さを入れ替え、90度の回転を行うとDISP_
CHANGE_BADMODE(-2)が返ってきます。
180度に関してはDISP_CHANGE_SUCCESSFUL(0)になりますが、
0度のままです。

サポート外の可能性を考え、IsCheckDisplayRotate()という
自作メソッドを作り試したら、サポート外の動きになりまし
た。
しかし、OS標準で備わっている「画面の解像度」では、縦に
切り替え可能です。

最後に、検証したコードを掲載いたします。
ご示教頂ければ幸いです。

>検証コード
using System;
using System.Runtime.InteropServices;

namespace OneButtonDisplaySetting
{
class Sample
{

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmDisplayOrientation;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
//[MarshalAs(UnmanagedType.U4)]
//public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}

private sealed class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
internal static extern int ChangeDisplaySettingsEx(
string lpszDeviceName,
ref DEVMODE lpDevMode,
IntPtr hwnd,
uint dwflags,
IntPtr lParam);

public const int CDS_TEST = 0x00000002;
public const int DM_PELSWIDTH = 0x00080000;
public const int DM_PELSHEIGHT = 0x00100000;
public const int DM_DISPLAYORIENTATION = 0x00800000;
public const int DM_DISPLAYQUERYORIENTATION = 0x01000000;
public const int ENUM_CURRENT_SETTINGS = -1;
public const int DMDO_DEFAULT = 0;
public const int DMDO_90 = 1;
public const int DMDO_180 = 2;
public const int DMDO_270 = 4;

public const int DISP_CHANGE_SUCCESSFUL = 0;
// 省略
}

/// <summary>
/// (C言語のサンプルを参考)縦・横の切り替えが可能か?
/// </summary>
/// <returns></returns>
public bool IsCheckDisplayRotate()
{
DISPLAY_DEVICE d = new DISPLAY_DEVICE();
DEVMODE dm = new DEVMODE();
int ret;

dm.dmSize = (short)Marshal.SizeOf(dm);
dm.dmFields = NativeMethods.DM_DISPLAYQUERYORIENTATION;

ret = NativeMethods.ChangeDisplaySettingsEx(
d.DeviceName,
ref dm,
IntPtr.Zero,
NativeMethods.CDS_TEST,
IntPtr.Zero);

if (ret == NativeMethods.DISP_CHANGE_SUCCESSFUL)
{
if (dm.dmDisplayOrientation == 0)
{
// このメソッドを試すと、ここを通る。
return false;
}
else
{
return true;
}
}

return false;
}

public int Change(int iWidth, int iHeight, int iMdo)
{
// 省略
}

}
}
> しかし、幅と高さを入れ替え、90度の回転を行うとDISP_
> CHANGE_BADMODE(-2)が返ってきます。
> 180度に関してはDISP_CHANGE_SUCCESSFUL(0)になりますが、
> 0度のままです。

  CDS_TESTで、取得した結果を正しく判断していない
  と思われますが。

  たとえば・・・
  http://www.mobileware.jp/index.php/%E7%94%BB%E9%9D%A2%E8%A1%A8%E7%A4%BA%E3%81%AE%E5%9B%9E%E8%BB%A2

  参考になりますでしょうか?

以上。
ご回答ありがとうございます。
タブが除去されていた関係で分かり難いですが、前回貼りつ
けたコードは、提示されたサイトを参考にしております。
memsetなどC#で必要のない処理を除き、他は同じ処理
の認識でおります。
定義した値に間違いがあるのでしょうか?

public const int DMDO_DEFAULT = 0;
public const int DM_DISPLAYORIENTATION = 0x00800000;
public const int DM_DISPLAYQUERYORIENTATION = 0x01000000;

もし、定義した値に問題がなければ、ChangeDisplaySettings
Exで戻り値が得られるまでは、問題ないように思えました。
しかし、提示されたサイトと同じ動きにしてもChangeDisplay
SettingsExの戻り値が-2になります。
最後に分岐を取り除いた回転のコードを載せます。
以上、よろしくお願いいたします。

/// <summary>
/// ディスプレイの状態を変更する。
/// </summary>
/// <param name="iWidth">幅</param>
/// <param name="iHeight">高さ</param>
public int Change(int iWidth, int iHeight)
{
DISPLAY_DEVICE d = new DISPLAY_DEVICE();
DEVMODE dm = new DEVMODE();
d.cb = Marshal.SizeOf(d);

dm.dmFormName = new string(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);

// 今回は値を固定。
dm.dmPelsHeight = iWidth;
dm.dmPelsWidth = iHeight;
dm.dmDisplayOrientation = NativeMethods.DMDO_90;

dm.dmFields =
NativeMethods.DM_PELSWIDTH |
NativeMethods.DM_PELSHEIGHT |
NativeMethods.DM_DISPLAYORIENTATION;

int iRet = NativeMethods.ChangeDisplaySettingsEx(
d.DeviceName,
ref dm,
IntPtr.Zero,
NativeMethods.CDS_RESET,
IntPtr.Zero);

// 戻り値は-2
return iRet;
}


>備考
・Changeメソッド(提示コード)の引数の値
iWidth = 1920;
iHeight = 1200;
IsCheckDisplayRotate()がfalseを返すというのであれば
それは『回転機能を有していない』と言うことなので、
何をどう頑張っても、戻り値が-2になるのは正しいと思い
ますが?

解像度の変更と回転は別物なので、何を根拠に回転ができる
とお考えでしょうか?

仮にディスプレイカードに添付のユーティリティで回転が
可能だった・・・と言うのであれば、逆にWin7なので管理者
権限を有していないと成功しない?とか・・・

ただそn場合は、戻り値が-2にはならないはずです。

以上。
ご回答ありがとうございます。

>仮にディスプレイカードに添付のユーティリティで回転が
>可能だった
 OSの機能にある「画面の解像度」で、縦の回転を利用
しております。
 ディスプレイは、こちらの商品を利用しております。
http://kakaku.com/item/00852012159/spec/
(コードに問題があると思っていたので、お知らせするのが
遅れました。申し訳ありません)

 定義の間違いでもー2になったので、原因の切り分けができ
ずにいました。
 アドバイスを元にセキュリティ関連のソフトをOFFにして、
管理者権限で試してみましたがー2でした。
 コードに間違いがあると思っていたのですが、私の環境を疑
った方がよろしいでしょうか?
 今までのやり取りの中で、不明瞭な点を含めて助言を頂ければ
幸いです。
 可能な限り、お伝えいたします。
>  OSの機能にある「画面の解像度」で、縦の回転を利用
> しております。
>  ディスプレイは、こちらの商品を利用しております。
> http://kakaku.com/item/00852012159/spec/

  ええ〜と・・・
  まず、縦横の解像度の変更で、CRTを回転等させての
  横長・縦長の見栄えを動的に変更するのは、解像度変更
  の方法で間違いないです。

  懸案の回転ですが・・・
  これはモバイル用の機能です。
  よってデスクトップ機等のビデオカードとCRTで使う
  機能では無いのですが・・・

  まぁ〜中には回転で行えるビデオカードもあるのかもし
  れませんが、私は知らないです。

  タブレットやスマホでのWindowsCE/Phone OSなら
  回転のAPIは使えないとダメですが。

以上。
モバイル用の機能と教えて頂き、WindowsCE用のサンプルが
多かったのにも納得がいきました。
私が利用しているビデオカードでは対応していないことがわ
かっただけスッキリしました。
Win32Api以外での回転を模索すると、趣旨と異なりますので
解決済みにします。

お付き合い頂きまして、誠にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板