How to Ensure That Your Application Displays Properly on High-DPI Displays
Although DirectWrite addresses many high-DPI issues for you, there are two steps you should take to ensure that your application works properly on high-DPI displays:
- Step 1: Use the System DPI When Creating Windows
- Step 2: Declare That the Application is DPI-Aware
- Related topics
Step 1: Use the System DPI When Creating Windows
The ID2D1Factory interface provides the GetDesktopDpi method for retrieving the system DPI. It provides the horizontal and vertical dimensions of the display in dots per inch (DPI). To use these values to set the width of a window, use the following formula:
<horizontal DPI> * <width, in pixels> / <default horizontal DPI>
...where horizontal DPI is the value retrived by GetDpi and default horizontal DPI is 96. The formula is similar for the vertical size:
<vertical DPI> * <height, in pixels> / <default vertical DPI>
...where vertical DPI is the value retrieved by the GetDesktopDpi method and default vertical DPI is 96.
// Because the CreateWindow function takes its size in pixels, // obtain the system DPI and use it to scale the window size. FLOAT dpiX, dpiY; // The factory returns the current system DPI. This is also the value it will use // to create its own windows. m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY); // Create the window. m_hwnd = CreateWindow( L"D2DDemoApp", L"Direct2D Demo App", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, static_cast<UINT>(ceil(640.f * dpiX / 96.f)), static_cast<UINT>(ceil(480.f * dpiY / 96.f)), NULL, NULL, HINST_THISCOMPONENT, this );
GDI provides the GetDeviceCaps function for retrieving device information. You can retrieve DPI information by passing the LOGPIXELSX and LOGPIXELSY index values. The formula for determining the horizontal and vertical size of a window is the same as with the Direct2D example above.
The following code uses the GetDeviceCaps function to create a 640 x 480 window, scaled to the system DPI.
FLOAT dpiX, dpiY; HDC screen = GetDC(0); dpiX = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSX)); dpiY = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSY)); ReleaseDC(0, screen); hWnd = CreateWindow( TEXT("DirectWriteApp"), TEXT("DirectWrite Demo App"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, static_cast<INT>(dpiX * 640.f / 96.f), static_cast<INT>(dpiY * 480.f / 96.f), NULL, NULL, hInstance, NULL );
Step 2: Declare That the Application is DPI-Aware
When an application declares itself to be DPI-aware, it is a statement specifying that the application behaves well at DPI settings up to 200 DPI. In Windows Vista and Windows 7, when DPI virtualization is enabled, applications that are not DPI-aware are scaled, and applications receive virtualized data from the system APIs, such as the GetSystemMetric function. To declare that your application is DPI-aware, complete the following steps.
Create a file called DeclareDPIAware.manifest.
Copy the following xml into the file and save it:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > <asmv3:application> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> </assembly>
In the project's .vcproj file, add the following entry inside each Configuration element under VisualStudioProject/Configurations:
<Tool Name="VCManifestTool" AdditionalManifestFiles="DeclareDPIAware.manifest" />