WPF에서 DPI를 취득하려면 어떻게 해야 하나요?
WPF에서 DPI를 취득하려면 어떻게 해야 하나요?
https://learn.microsoft.com/en-us/archive/blogs/jaimer/getting-system-dpi-in-wpf-app은 기능하고 있는 것 같습니다.
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);
.NET 4.6.2 Preview 이후에서는 에 문의할 수 있습니다.이것은 구조체를 반환합니다.이 구조체는 지정된 DPI를 나타냅니다.Visual
렌더링되거나 렌더링되었습니다.
2015년부터 답변을 갱신했습니다.다음은 Windows 10의 최신 DPI 기능(특히 윈도/어플리케이션/프로세스의 DPI_AWARITION을 지원하는 유일한 방법인 GetDpiForWindow 기능)을 사용하지만 이전 기능(모니터당 dpi, 데스크톱 dpi 등)으로 폴백하여 Windows 7에서도 동작할 수 있는 유틸리티 코드입니다.
WPF나 Winforms에는 의존하지 않고 Windows 자체에만 의존합니다.
// note this class considers dpix = dpiy
public static class DpiUtilities
{
// you should always use this one and it will fallback if necessary
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
public static int GetDpiForWindow(IntPtr hwnd)
{
var h = LoadLibrary("user32.dll");
var ptr = GetProcAddress(h, "GetDpiForWindow"); // Windows 10 1607
if (ptr == IntPtr.Zero)
return GetDpiForNearestMonitor(hwnd);
return Marshal.GetDelegateForFunctionPointer<GetDpiForWindowFn>(ptr)(hwnd);
}
public static int GetDpiForNearestMonitor(IntPtr hwnd) => GetDpiForMonitor(GetNearestMonitorFromWindow(hwnd));
public static int GetDpiForNearestMonitor(int x, int y) => GetDpiForMonitor(GetNearestMonitorFromPoint(x, y));
public static int GetDpiForMonitor(IntPtr monitor, MonitorDpiType type = MonitorDpiType.Effective)
{
var h = LoadLibrary("shcore.dll");
var ptr = GetProcAddress(h, "GetDpiForMonitor"); // Windows 8.1
if (ptr == IntPtr.Zero)
return GetDpiForDesktop();
int hr = Marshal.GetDelegateForFunctionPointer<GetDpiForMonitorFn>(ptr)(monitor, type, out int x, out int y);
if (hr < 0)
return GetDpiForDesktop();
return x;
}
public static int GetDpiForDesktop()
{
int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out ID2D1Factory factory);
if (hr < 0)
return 96; // we really hit the ground, don't know what to do next!
factory.GetDesktopDpi(out float x, out float y); // Windows 7
Marshal.ReleaseComObject(factory);
return (int)x;
}
public static IntPtr GetDesktopMonitor() => GetNearestMonitorFromWindow(GetDesktopWindow());
public static IntPtr GetShellMonitor() => GetNearestMonitorFromWindow(GetShellWindow());
public static IntPtr GetNearestMonitorFromWindow(IntPtr hwnd) => MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
public static IntPtr GetNearestMonitorFromPoint(int x, int y) => MonitorFromPoint(new POINT { x = x, y = y }, MONITOR_DEFAULTTONEAREST);
private delegate int GetDpiForWindowFn(IntPtr hwnd);
private delegate int GetDpiForMonitorFn(IntPtr hmonitor, MonitorDpiType dpiType, out int dpiX, out int dpiY);
private const int MONITOR_DEFAULTTONEAREST = 2;
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpLibFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("user32")]
private static extern IntPtr MonitorFromPoint(POINT pt, int flags);
[DllImport("user32")]
private static extern IntPtr MonitorFromWindow(IntPtr hwnd, int flags);
[DllImport("user32")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32")]
private static extern IntPtr GetShellWindow();
[StructLayout(LayoutKind.Sequential)]
private partial struct POINT
{
public int x;
public int y;
}
[DllImport("d2d1")]
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
}
}
public enum MonitorDpiType
{
Effective = 0,
Angular = 1,
Raw = 2,
}
"진짜" 모니터 dpi를 얻을 수 있는 유일한 방법은 다음과 같습니다.그 외의 모든 기술에서는 96이라고 되어 있습니다만, 대부분의 모니터에서는 올바르지 않습니다.
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,
}
이것이 내가 WPF에서 "스케일 팩터"를 얻을 수 있었던 방법이다.제 노트북의 해상도는 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 my settings says my scale is 150%
사용하다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;
}
Management Class를 사용해 볼 수 있습니다.
public static string GetDPI()
{
using (ManagementClass mc = new ManagementClass("Win32_DesktopMonitor"))
{
using (ManagementObjectCollection moc = mc.GetInstances())
{
int PixelsPerXLogicalInch = 0; // dpi for x
int PixelsPerYLogicalInch = 0; // dpi for y
foreach (ManagementObject each in moc)
{
PixelsPerXLogicalInch = int.Parse((each.Properties["PixelsPerXLogicalInch"].Value.ToString()));
PixelsPerYLogicalInch = int.Parse((each.Properties["PixelsPerYLogicalInch"].Value.ToString()));
}
return PixelsPerXLogicalInch + "," + PixelsPerYLogicalInch;
}
}
}
https://blogs.windows.com/buildingapps/2017/01/25/calling-windows-10-apis-desktop-application/ #FJTMAIFjbtXiLQAp.97이 있습니다.
2017년 1월 25일 오후 3시 54분
"데스크탑 애플리케이션에서 Windows 10 API 호출" 및
https://learn.microsoft.com/en-us/uwp/api/windows.devices.display.displaymonitor
"DisplayMonitor 클래스"
네임스페이스:창문들.장치들.디스플레이 어셈블리:창문들.장치들.Display.dll, Windows.dll
시스템에 연결된 디스플레이 모니터 장치에 대한 정보를 제공합니다.
이러한 데이터에는 일반적으로 사용되는 모니터의 확장 디스플레이 식별 데이터(EDID, 거의 모든 모니터가 지원되는 모드와 일반적인 디바이스 정보를 제공하기 위해 사용하는 업계 표준 디스플레이 디스크립터 블록) 및 디스플레이의 정보가 포함됩니다.ID(EDID의 슈퍼셋을 제공하는 새로운 업계 표준).
Raw DpiX
모니터의 물리적 수평 DPI를 가져옵니다(모니터의 기본 해상도와 물리적 크기에 기반).
DPIY
모니터의 물리적 수직 DPI를 가져옵니다(모니터의 기본 해상도와 물리적 크기에 기반).
2006년 이후 Windows의 기본 모니터 정보
https://learn.microsoft.com/en-us/windows/desktop/wmicoreprov/msmonitorclass
MSMonitor Class 클래스
Wmi Monitor RawEEdidV1Block 클래스
WmiMonitorBasicDisplayParams 클래스
MaxHorizontalImageSize ( EDID byte 21 )
MaxVerticalImageSize ( EDID byte 22 )
(EDID Detailed Timing Descriptor에서는 EDID의 사이즈는 센티미터 이상, 밀리미터 단위입니다).
수평 크기,8 평평 mm 、 mm 、 8 lsbit(0~4095mm, 161인치)
크기,8 mm, in 13 직직, mm, 8 lsbit(0~4095 mm, 161 치)
7 4 수평 크기,4 14 트7 ~ 4 msbit 、 mm 、 4 msbit
3 ~ 0 크기,4 트3 ~ 0 직 ( mm 、 4 msbit )
)
그리고.
언급URL : https://stackoverflow.com/questions/1918877/how-can-i-get-the-dpi-in-wpf
'it-source' 카테고리의 다른 글
Windows에서 Git으로 작업하도록 에디터를 설정하려면 어떻게 해야 합니까? (0) | 2023.04.21 |
---|---|
SELECT DISTING이 지정된 경우 ORDER BY 항목이 선택 목록에 표시되어야 합니다. (0) | 2023.04.21 |
스크립트 기간 동안만 환경변수를 설정하려면 어떻게 해야 합니까? (0) | 2023.04.21 |
클래스(스태틱) 변수 및 메서드 (0) | 2023.04.16 |
모든 파일에 파일 확장자를 재귀적으로 추가하다 (0) | 2023.04.16 |