玄铁剑

成功的途径:抄,创造,研究,发明...
posts - 128, comments - 42, trackbacks - 0, articles - 174

以编程方式更改屏幕方向

Posted on 2008-12-09 21:38 玄铁剑 阅读(596) 评论(0)  编辑 收藏 引用 所属分类: windows

摘要: 本文描述如何以编程方式更改显示设备的方向、分辨率及其他方面。相应示例采用 C# 编写。

单击此处可下载本文的代码示例。

本页内容

简介 简介
概述 概述
使用示例 使用示例
在托管代码中获取并更改显示设置 在托管代码中获取并更改显示设置
小结 小结

简介

有些情况下,应用程序需要更改屏幕方向,因为有的功能被设计为在特定模式下运行得最好。其中一个例子就是 Microsoft Office PowerPoint 中的“幻灯片放映”:PowerPoint 以横向模式运行。即使正在纵向模式下使用 Tablet PC,当开始幻灯片放映时,应用程序也会切换到横向方向。当用户结束幻灯片放映时,PowerPoint 会切换回原来的设置。

概述

更改显示设置可以通过使用两个 Win32 API 来完成,这两个 API 都具有指向 DEVMODE 结构的指针,它们分别包含与显示设置有关的所有信息:

使用示例

要编译示例源代码,计算机中必须安装 Microsoft Visual Studio .NET 2003。该示例应用程序有一个用户界面,它具有以下功能:

  • 查看当前显示设备所支持的所有显示设置。

  • 查看当前显示设置的参数。

  • 切换至任何受支持的显示设置。

  • 顺时针和逆时针旋转屏幕方向。

获取当前显示设置

要获取当前显示设置,请将 iModeNum 参数中的 ENUM_CURRENT_SETTINGS 常量传递给 EnumDisplaySettings API,如以下 C++ 代码所示。

   DEVMODE dm;
// initialize the DEVMODE structure
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
// inspect the DEVMODE structure to obtain details
// about the display settings such as
//  - Orientation
//  - Width and Height
//  - Frequency
//  - etc.
}

枚举所有受支持的显示设置

要枚举当前显示设备支持的所有显示设置,请将 iModeNum 参数中的 0 传递给 EnumDisplaySettings API,然后继续以递增的 iModeNum 值调用它,直到该函数返回零,如以下 C++ 代码所示。

   int index = 0;
DEVMODE dm;
// initialize the DEVMODE structure
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
while (0 != EnumDisplaySettings(NULL, index++, &dm))
{
// inspect the DEVMODE structure to obtain details
// about the display settings such as
//  - Orientation
//  - Width and Height
//  - Frequency
//  - etc.
}

更改显示设置

要更改显示设置,请将指向有效 DEVMODE 结构的指针传递给 ChangeDisplaySettings API。以下 C++ 代码演示如何使屏幕方向顺时针旋转 90 度。请注意,这段代码只对支持相应显示设置的设备起作用。遵守 ChangeDisplaySettings API 的返回值十分重要,因为有些操作为了在图形模式下工作,需要计算机重启。

   DEVMODE dm;
// initialize the DEVMODE structure
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
// swap height and width
DWORD dwTemp = dm.dmPelsHeight;
dm.dmPelsHeight= dm.dmPelsWidth;
dm.dmPelsWidth = dwTemp;
// determine new orientaion
switch (dm.dmDisplayOrientation)
{
case DMDO_DEFAULT:
dm.dmDisplayOrientation = DMDO_270;
break;
case DMDO_270:
dm.dmDisplayOrientation = DMDO_180;
break;
case DMDO_180:
dm.dmDisplayOrientation = DMDO_90;
break;
case DMDO_90:
dm.dmDisplayOrientation = DMDO_DEFAULT;
break;
default:
// unknown orientation value
// add exception handling here
break;
}
long lRet = ChangeDisplaySettings(&dm, 0);
if (DISP_CHANGE_SUCCESSFUL != lRet)
{
// add exception handling here
}
}

在托管代码中获取并更改显示设置

映射 API

为了在托管代码中更改显示设置,必须使用平台调用服务 (PInvoke) 调用 EnumDisplaySettingsChangeDisplaySettings API。对此,一个好的做法是创建一个名为 NativeMethods 的类,该类可以将封装这些 API 的公共静态方法公开。该类应该包含 API 所对应的所有必需的常量定义。以下代码示例演示了这种做法。该类的完整实现可在 NativeMethods.cs 文件中找到,该文件是示例应用程序的一部分。

using System.Runtime.InteropServices;
...
public class NativeMethods
{
// PInvoke declaration for EnumDisplaySettings Win32 API
[DllImport("user32.dll", CharSet=CharSet.Ansi)]
public static extern int EnumDisplaySettings(
string lpszDeviceName,
int iModeNum,
ref DEVMODE lpDevMode);
// PInvoke declaration for ChangeDisplaySettings Win32 API
[DllImport("user32.dll, CharSet=CharSet.Ansi")]
public static extern int ChangeDisplaySettings(
ref DEVMODE lpDevMode,
int dwFlags);
// add more functions as needed ??
// constants
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 = 3;
// add more constants as needed ??
}

映射 DEVMODE 结构

在将 DEVMODE 结构映射到托管结构时,应该注意以下几个问题:

  • 因为 DEVMODE 结构包含联合 (union),所以必须挑选出我们所需要的那些成员。

  • 在 .NET Framework 中映射到字符串的数组必须作为相同大小的字符串封送。

  • 为简单起见,可以将嵌套结构平面化(例如,将 POINTL 结构替换为两个托管的 int 类型。)

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public 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;
public int    dmPositionX;
public int    dmPositionY;
public int    dmDisplayOrientation;
public int    dmDisplayFixedOutput;
public short  dmColor;
public short  dmDuplex;
public short  dmYResolution;
public short  dmTTOption;
public short  dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short  dmLogPixels;
public short  dmBitsPerPel;
public int    dmPelsWidth;
public int    dmPelsHeight;
public int    dmDisplayFlags;
public int    dmDisplayFrequency;
public int    dmICMMethod;
public int    dmICMIntent;
public int    dmMediaType;
public int    dmDitherType;
public int    dmReserved1;
public int    dmReserved2;
public int    dmPanningWidth;
public int    dmPanningHeight;
};

在 .NET Framework 中初始化 DEVMODE 结构的新实例时,请确保 dmDeviceNamedmFormNamedmSize 值设置恰当。为此,我在示例应用程序的 NativeMethods 类中添加了以下方法:

public static DEVMODE CreateDevmode()
{
DEVMODE dm = new DEVMODE();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
return dm;
}

C# 中旋转屏幕

以下 C# 代码将前面讨论的技术结合起来,并展示了如何在托管代码中顺时针旋转屏幕。请注意,这段代码只对支持相应显示设置的设备起作用。

// initialize the DEVMODE structure
DEVMODE dm = new DEVMODE();
dm.dmDeviceName = new string(new char[32]);
dm.dmFormName = new string(new char[32]);
dm.dmSize = Marshal.SizeOf(dm);
if (0 != NativeMethods.EnumDisplaySettings(
null,
NativeMethods.ENUM_CURRENT_SETTINGS,
ref dm))
{
// swap width and height
int temp = dm.dmPelsHeight;
dm.dmPelsHeight = dm.dmPelsWidth;
dm.dmPelsWidth = temp;
// determine new orientation
switch(dm.dmDisplayOrientation)
{
case NativeMethods.DMDO_DEFAULT:
dm.dmDisplayOrientation = NativeMethods.DMDO_270;
break;
case NativeMethods.DMDO_270:
dm.dmDisplayOrientation = NativeMethods.DMDO_180;
break;
case NativeMethods.DMDO_180:
dm.dmDisplayOrientation = NativeMethods.DMDO_90;
break;
case NativeMethods.DMDO_90:
dm.dmDisplayOrientation = NativeMethods.DMDO_DEFAULT;
break;
default:
// unknown orientation value
// add exception handling here
break;
}
int iRet = NativeMethods.ChangeDisplaySettings(ref dm, 0);
if (NativeMethods.DISP_CHANGE_SUCCESSFUL != iRet)
{
// add exception handling here
}
}

小结

  • 使用 EnumDisplaySettings API 来获取当前显示设置的相关信息。

  • 使用 EnumDisplaySettings API 来枚举所有受支持的显示设置。

  • DEVMODE 结构包含关于给定的显示模式的所有信息。

  • 使用 ChangeDisplaySettings 来切换到由有效的 DEVMODE 结构指定的新显示模式。

  • 使用平台调用服务以从托管代码实现。

只有注册用户登录后才能发表评论。