How can I get the supported screen resolutions in XNA? Like when you change the screen resolution in windows, and instead of giving you a list of all the possible choices, it gives you just a few of them.
Just use this:
foreach (DisplayMode mode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes) {
//mode.whatever (and use any of avaliable information)
}
But it will give you few duplicates, because it also takes into accound refrash rate, so you might include that aswel, or do some filtering.
I'm not that up-to-date with XNA, but I didn't think there was a quick and easy function. There is a way using the old WinForms API, but as I personally don't want to link against that in other applications the easiest way is to use the native functions.
First, define the native struct that will be used:
[StructLayout(LayoutKind.Sequential)]
internal struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
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 = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int 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;
}
We also need to define the two native functions we will use:
[DllImport("user32.dll")]
private static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int nIndex);
And last, our functions to list all screen resolutions and one to get the current screen resolution:
public static List<string> GetScreenResolutions()
{
var resolutions = new List<string>();
try
{
var devMode = new DEVMODE();
int i = 0;
while (EnumDisplaySettings(null, i, ref devMode))
{
resolutions.Add(string.Format("{0}x{1}", devMode.dmPelsWidth, devMode.dmPelsHeight));
i++;
}
resolutions = resolutions.Distinct(StringComparer.InvariantCulture).ToList();
}
catch (Exception ex)
{
Console.WriteLine("Could not get screen resolutions.");
}
return resolutions;
}
public static string GetCurrentScreenResolution()
{
int width = GetSystemMetrics(0x00);
int height = GetSystemMetrics(0x01);
return string.Format("{0}x{1}", width, height);
}
Related
I'm trying to use win32 EnumDisplaySettings to get all available resolutions and refresh rates. But when printing dmDisplayFrequency I always get 0 which means that it cannot get it. Is there any alternatives to enumDisplaySettings ? If windows is able to provide a list in display setting window then there must be another way ?
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace ListResolutions
{
class Program
{
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(
string deviceName, int modeNum, ref DEVMODE devMode);
const int ENUM_CURRENT_SETTINGS = -1;
const int ENUM_REGISTRY_SETTINGS = -2;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
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 dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int 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;
}
static void Main(string[] args)
{
DEVMODE vDevMode = new DEVMODE();
int i = 0;
while (EnumDisplaySettings(null, i, ref vDevMode))
{
Console.WriteLine("Width:{0} Height:{1} Color:{2} Frequency:{3}",
vDevMode.dmPelsWidth,
vDevMode.dmPelsHeight,
1 << vDevMode.dmBitsPerPel, vDevMode.dmDisplayFrequency
);
i++;
}
}
}
}
I have the following C++ to get information about a specific monitor using the EnumDisplaySettings WinAPI function.
#include <iostream>
#include <Windows.h>
int main()
{
DEVMODE dm;
dm.dmSize = sizeof dm;
EnumDisplaySettings(L"\\\\.\\DISPLAY1", ENUM_CURRENT_SETTINGS, &dm);
std::wcout << "Name: " << dm.dmDeviceName << std::endl;
std::wcout << "Width: " << dm.dmPelsWidth << std::endl;
std::wcout << "Height: " << dm.dmPelsHeight << std::endl;
}
I am trying to use the EnumDisplaySettings function in C#.
To do this, I have recreated DEVMODEW as a C# struct and pass it into the method.
static void Main()
{
DeviceModeStruct deviceMode = new DeviceModeStruct();
deviceMode.dmSize = (ushort)Marshal.SizeOf(deviceMode);
bool successfullyGotScale = EnumDisplaySettings("\\\\.\\DISPLAY1",
ENUM_CURRENT_SETTINGS,
ref deviceMode);
if (successfullyGotScale)
{
Console.WriteLine($#"Name: {deviceMode.dmDeviceName}");
Console.WriteLine($#"Width: {deviceMode.dmPelsWidth}");
Console.WriteLine($#"Height: {deviceMode.dmPelsHeight}");
}
}
The issue is, when I run the code, I get the following exception.
Unhandled Exception: System.TypeLoadException: Could not load type 'DeviceModeStruct'
from assembly 'DevModeSo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
because it contains an object field at offset 70 that is incorrectly aligned or
overlapped by a non-object field.
at DevModeSo.Program.Main()
As far as I can tell, the issue is relating to
[FieldOffset(70), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmFormName;
and this answer to another similar Stack Overflow question seems to suggest I can split the string up to fix the issue.
However, when I tried to do that so that the code so that the values were aligned with "DWORDS" I got the same error.
[FieldOffset(70)]
public char dmFormName1;
[FieldOffset(71)]
public char dmFormName2;
[FieldOffset(72), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string dmFormName3;
How can this problem be resolved whilst still meeting the same data structure as defined by DEVMODEW?
Full C# code
using System;
using System.Runtime.InteropServices;
namespace DevModeSo
{
class Program
{
private const int ENUM_CURRENT_SETTINGS = -1;
static void Main()
{
DeviceModeStruct deviceMode = new DeviceModeStruct();
deviceMode.dmSize = (ushort)Marshal.SizeOf(deviceMode);
bool successfullyGotScale = EnumDisplaySettings("\\\\.\\DISPLAY1",
ENUM_CURRENT_SETTINGS,
ref deviceMode);
if (successfullyGotScale)
{
Console.WriteLine($#"Name: {deviceMode.dmDeviceName}");
Console.WriteLine($#"Width: {deviceMode.dmPelsWidth}");
Console.WriteLine($#"Height: {deviceMode.dmPelsHeight}");
}
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool EnumDisplaySettings(string deviceName,
int modeNum,
ref DeviceModeStruct deviceMode);
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
struct DeviceModeStruct
{
private const int STRING_SIZE = 32;
[FieldOffset(0), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmDeviceName;
[FieldOffset(32)] public ushort dmSpecVersion;
[FieldOffset(34)] public ushort dmDriverVersion;
[FieldOffset(36)] public ushort dmSize;
[FieldOffset(38)] public ushort dmDriverExtra;
[FieldOffset(40)] public uint dmFields;
[FieldOffset(44)] public PrinterOnlyFields printerMode;
[FieldOffset(44)] public DisplayOnlyFields displayMode;
[FieldOffset(60)] public short dmColor;
[FieldOffset(62)] public short dmDuplex;
[FieldOffset(64)] public short dmYResolution;
[FieldOffset(66)] public short dmTTOption;
[FieldOffset(68)] public short dmCollate;
[FieldOffset(70), MarshalAs(UnmanagedType.ByValTStr, SizeConst = STRING_SIZE)]
public string dmFormName;
[FieldOffset(102)] public ushort dmLogPixels;
[FieldOffset(104)] public uint dmBitsPerPel;
[FieldOffset(108)] public uint dmPelsWidth;
[FieldOffset(112)] public uint dmPelsHeight;
[FieldOffset(116)] public uint dmDisplayFlags;
[FieldOffset(116)] public uint dmNup;
[FieldOffset(120)] public uint dmDisplayFrequency;
[FieldOffset(124)] public uint dmICMMethod;
[FieldOffset(128)] public uint dmICMIntent;
[FieldOffset(132)] public uint dmMediaType;
[FieldOffset(136)] public uint dmDitherType;
[FieldOffset(140)] public uint dmReserved1;
[FieldOffset(144)] public uint dmReserved2;
[FieldOffset(148)] public uint dmPanningWidth;
[FieldOffset(152)] public uint dmPanningHeight;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct PrinterOnlyFields
{
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct Point
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct DisplayOnlyFields
{
public Point dmPosition;
public uint dmDisplayOrientation;
public uint dmDisplayFixedOutput;
}
}
}
You should remove all the FieldOffset attributes and implement the unions outside of the DeviceModeStruct structure. Like this:
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
struct DeviceModeUnion
{
[FieldOffset(0)]
PrinterOnlyFields Printer;
[FieldOffset(0)]
Point Position;
[FieldOffset(0)]
DisplayOnlyFields Display;
}
....
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct DeviceModeStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public ushort dmSpecVersion;
public ushort dmDriverVersion;
public ushort dmSize;
public ushort dmDriverExtra;
public uint dmFields;
public DeviceModeUnion union;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public ushort dmLogPixels;
public uint dmBitsPerPel;
public uint dmPelsWidth;
public uint dmPelsHeight;
public uint dmDisplayFlags;
public uint dmDisplayFrequency;
public uint dmICMMethod;
public uint dmICMIntent;
public uint dmMediaType;
public uint dmDitherType;
public uint dmReserved1;
public uint dmReserved2;
public uint dmPanningWidth;
public uint dmPanningHeight;
}
I've not checked DeviceModeStruct carefully against the documentation, but I am sure you can do that. However, I can confirm that this struct definition at least has the correct size, when compared against the size of the struct defined in the C++ header file.
I have the below code to change my 2nd display screen resolution. It all works fine and changes as expected. However once it has been changed my mouse/cursor is offset. eg the active location is not where the pointer shows on the screen.
Thoughts?
using System;
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE1
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
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 dmPosition;
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;
};
class User_32
{
[DllImport("user32.dll")]
public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE1 devMode);
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettings(ref DEVMODE1 devMode, int flags);
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE1 lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int DISP_CHANGE_SUCCESSFUL = 0;
public const int DISP_CHANGE_RESTART = 1;
public const int DISP_CHANGE_FAILED = -1;
[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
}
}
namespace Resolution
{
class CResolution
{
public CResolution(int iWidth, int iHeight)
{
DEVMODE1 dm = new DEVMODE1();
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
dm.dmPosition = 2;
if (0 != User_32.EnumDisplaySettings(null, User_32.ENUM_CURRENT_SETTINGS, ref dm))
{
dm.dmPelsWidth = iWidth;
dm.dmPelsHeight = iHeight;
long result = User_32.ChangeDisplaySettingsEx("\\\\.\\DISPLAY2", ref dm, IntPtr.Zero, User_32.ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);
}
}
}
}
-
static void Main(string[] args)
{
Resolution.CResolution ChangeRes = new Resolution.CResolution(2560, 1600);
}
I can switch between Landsacpe and Portrait mode in one screen by using the following code (That I have done this morning). And the problem is I have two screens in a computer. And I want the screen 1 is LANDSCAPE mode, and the screen 2 is PORTRAIT mode. But I don't know how to modify the code to make it work. (Sorry about my English)
class ModeSetting
{
public const int LANDSCAPE = 0;
public const int PORTRAIT = 1;
public static bool ChangeMode(int screenID, int modeID)
{
//I'm not using screenID here. Let me know how to do that. How to get screenID
//Or anything that help me.
DEVMODE dm = new DEVMODE();
dm.dmDeviceName = new string(new char[32]);
dm.dmFormName = new string(new char[32]);
//dm.dmSize = Marshal.SizeOf(dm);
if (modeID != PORTRAIT) modeID = LANDSCAPE;
if (0 != NativeMethods.EnumDisplaySettings(
null,
NativeMethods.ENUM_CURRENT_SETTINGS,
ref dm))
{
int temp = dm.dmPelsHeight;
dm.dmPelsHeight = dm.dmPelsWidth;
dm.dmPelsWidth = temp;
dm.dmDisplayOrientation = modeID;
int iRet = NativeMethods.ChangeDisplaySettings(ref dm, 0);
Console.WriteLine(iRet);
if (NativeMethods.DISP_CHANGE_SUCCESSFUL != iRet)
{
return false;
}
return true;
}
return false;
}
[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;
}
internal 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);
// 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;
public const int DISP_CHANGE_SUCCESSFUL = 0;
}
}
And I can switch between LANDSCAPE and PORTRAIT mode by using:
ModeSetting.ChangeMode(0, ModeSetting.LANDSCAPE);//0 here is screen ID that I cannot do when two screens
ModeSetting.ChangeMode(0, ModeSetting.PORTRAIT);
I've found nice examples using C++ (http://www.codeproject.com/KB/tips/resswitch.aspx), but not in C#.
Can someone help, please?
Edit:
The exact function that list the video modes is:
BOOL CVideoModes::GetAvailableVideoModes(CAvailableVideoModes& modes)
{
modes.SetSize(0, 5);
int i=0;
DEVMODE dm;
while (EnumDisplaySettings(NULL, i, &dm))
{
CVideoMode thismode(dm.dmBitsPerPel, dm.dmPelsWidth,
dm.dmPelsHeight, dm.dmDisplayFrequency);
modes.SetAtGrow(i, thismode);
++i;
}
modes.FreeExtra();
return (i>0);
}
But sincerelly I cannot understand that C++ code. Where I can find that "thismode" function?
If you mean video modes are available resolutions, try to invoke EnumDisplaySettingsEx
details can be found here:
http://msdn.microsoft.com/en-us/library/dd162612(VS.85).aspx
small program that lists available resolutions:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ListResolutions
{
class Program
{
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(
string deviceName, int modeNum, ref DEVMODE devMode);
const int ENUM_CURRENT_SETTINGS = -1;
const int ENUM_REGISTRY_SETTINGS = -2;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
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 ScreenOrientation dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int 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;
}
static void Main(string[] args)
{
DEVMODE vDevMode = new DEVMODE();
int i = 0;
while (EnumDisplaySettings(null, i, ref vDevMode))
{
Console.WriteLine("Width:{0} Height:{1} Color:{2} Frequency:{3}",
vDevMode.dmPelsWidth,
vDevMode.dmPelsHeight,
1 << vDevMode.dmBitsPerPel, vDevMode.dmDisplayFrequency
);
i++;
}
}
}
}