Comment puis-je obtenir le DPI dans WPF?
http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx semble fonctionner
PresentationSource source = PresentationSource.FromVisual(this);
double dpiX, dpiY;
if (source != null) {
dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
}
var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
var dpiX = (int)dpiXProperty.GetValue(null, null);
var dpiY = (int)dpiYProperty.GetValue(null, null);
Avec .NET 4.6.2 Preview et les versions ultérieures, vous pouvez appeler VisualTreeHelper.GetDpi(Visual visual)
. Il retourne une structure DpiScale
, qui indique le DPI auquel la Visual
donnée sera ou a été rendue.
Le seul moyen que j'ai trouvé pour obtenir le "vrai" moniteur dpi est le suivant. Toutes les autres techniques mentionnées ne font que 96, ce qui n'est pas correct pour la plupart des moniteurs.
public class ScreenInformations
{
public static uint RawDpi { get; private set; }
static ScreenInformations()
{
uint dpiX;
uint dpiY;
GetDpi(DpiType.RAW, out dpiX, out dpiY);
RawDpi = dpiX;
}
/// <summary>
/// Returns the scaling of the given screen.
/// </summary>
/// <param name="dpiType">The type of dpi that should be given back..</param>
/// <param name="dpiX">Gives the horizontal scaling back (in dpi).</param>
/// <param name="dpiY">Gives the vertical scaling back (in dpi).</param>
private static void GetDpi(DpiType dpiType, out uint dpiX, out uint dpiY)
{
var point = new System.Drawing.Point(1, 1);
var hmonitor = MonitorFromPoint(point, _MONITOR_DEFAULTTONEAREST);
switch (GetDpiForMonitor(hmonitor, dpiType, out dpiX, out dpiY).ToInt32())
{
case _S_OK: return;
case _E_INVALIDARG:
throw new ArgumentException("Unknown error. See https://msdn.Microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
default:
throw new COMException("Unknown error. See https://msdn.Microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
}
}
//https://msdn.Microsoft.com/en-us/library/windows/desktop/dd145062.aspx
[DllImport("User32.dll")]
private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);
//https://msdn.Microsoft.com/en-us/library/windows/desktop/dn280510.aspx
[DllImport("Shcore.dll")]
private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);
const int _S_OK = 0;
const int _MONITOR_DEFAULTTONEAREST = 2;
const int _E_INVALIDARG = -2147024809;
}
/// <summary>
/// Represents the different types of scaling.
/// </summary>
/// <seealso cref="https://msdn.Microsoft.com/en-us/library/windows/desktop/dn280511.aspx"/>
public enum DpiType
{
EFFECTIVE = 0,
ANGULAR = 1,
RAW = 2,
}
Voici une méthode qui repose sur la technologie Direct2D (prise en charge sur Windows Vista avec SP2 et versions supérieures et sur les serveurs), de sorte que cela fonctionne correctement dans WPF (qui repose sur les mêmes bases). Il utilise la méthode ID2D1Factory :: GetDesktopDpi
public static class DpiUtilities
{
private static Lazy<Tuple<float, float>> _dpi = new Lazy<Tuple<float, float>>(ReadDpi);
public static float DesktopDpiX
{
get
{
return _dpi.Value.Item1;
}
}
public static float DesktopDpiY
{
get
{
return _dpi.Value.Item2;
}
}
public static void Reload()
{
ID2D1Factory factory;
int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
factory.ReloadSystemMetrics();
Marshal.ReleaseComObject(factory);
}
private static Tuple<float, float> ReadDpi()
{
ID2D1Factory factory;
int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
float x;
float y;
factory.GetDesktopDpi(out x, out y);
Marshal.ReleaseComObject(factory);
return new Tuple<float, float>(x, y);
}
[DllImport("d2d1.dll")]
private static extern int D2D1CreateFactory(D2D1_FACTORY_TYPE factoryType, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, IntPtr pFactoryOptions, out ID2D1Factory ppIFactory);
private enum D2D1_FACTORY_TYPE
{
D2D1_FACTORY_TYPE_SINGLE_THREADED = 0,
D2D1_FACTORY_TYPE_MULTI_THREADED = 1,
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("06152247-6f50-465a-9245-118bfd3b6007")]
private interface ID2D1Factory
{
int ReloadSystemMetrics();
[PreserveSig]
void GetDesktopDpi(out float dpiX, out float dpiY);
// the rest is not implemented as we don't need it
}
}
Utilisez la fonction GetDeviceCaps
:
static void Main(string[] args)
{
// 1.25 = 125%
var dpi = GetDpi() ;
}
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
private static float GetDpi()
{
IntPtr desktopWnd = IntPtr.Zero;
IntPtr dc = GetDC(desktopWnd);
var dpi = 100f;
const int LOGPIXELSX = 88;
try
{
dpi = GetDeviceCaps( dc, LOGPIXELSX);
}
finally
{
ReleaseDC(desktopWnd, dc);
}
return dpi / 96f;
}
C’est ainsi que j’ai réussi à obtenir un "facteur d’échelle" dans WPF. La résolution de mon ordinateur portable est de 1920x1440.
int resHeight = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height; // 1440
int actualHeight = SystemParameters.PrimaryScreenHeight; // 960
double ratio = actualHeight / resHeight;
double dpi = resHeigh / actualHeight; // 1.5 which is true because settings says 150%
Informations de base sur le moniteur sous Windows à partir de 2006
https://docs.Microsoft.com/en-us/windows/desktop/wmicoreprov/msmonitorclass
Classe MSMonitorClass
Classe WmiMonitorRawEEdidV1Block
Classe WmiMonitorBasicDisplayParams
MaxHorizontalImageSize ( EDID byte 21 )
MaxVerticalImageSize ( EDID byte 22 )
(Les tailles dans EDID sont en centimètres au-dessus et en millimètres dans le descripteur de minutage détaillé EDID
12 Taille d'image horizontale, mm, 8 lsbits (0–4095 mm, 161 in)
13 Taille d'image verticale, mm, 8 lsbits (0–4095 mm, 161 in)
14 bits 7–4 Taille d'image horizontale, mm, 4 msbits
Bits 3–0 Taille d'image verticale, mm, 4 msbits
)
et
25 janvier 2017 15h54
"Appel des API Windows 10 à partir d'une application de bureau" Et
https://docs.Microsoft.com/en-us/uwp/api/windows.devices.display.displaymonitor
"Classe de moniteur d'affichage"
Espace de noms: Windows.Devices.Display Assemblies: Windows.Devices.Display.dll, Windows.dll
Fournit des informations sur un périphérique moniteur connecté au système.
Ces données incluent des informations couramment utilisées provenant des données d'identification d'affichage étendu du moniteur (EDID, un bloc de descripteur d'affichage standard utilisé par presque tous les moniteurs pour fournir des descriptions des modes pris en charge et des informations générales sur le périphérique) et de DisplayID (qui est une nouvelle norme industrielle. qui fournit un sur-ensemble d'EDID).
DpiX brut
Obtient le DPI physique horizontal du moniteur (basé sur la résolution native du moniteur et sa taille physique).
Raw DpiY
Obtient le DPI physique vertical du moniteur (basé sur sa résolution native et sa taille physique).