EN
このコンテンツは設定された言語で表示できません。英語版のページが表示されます。

Tutorial: Writing High-DPI Win32 Applications

This tutorial and the tutorial sample application DPITutorial.exe explain key concepts of high DPI desktop applications. They show how to set an application as DPI–aware and how the application adjusts to DPI changes.

The following actions cause DPI changes:

  • A user moves the application window to a display with a different DPI.
  • A user changes the resolution.
  • A user changes the desktop scaling value by using the slider control in Control Panel.

To download the High DPI tutorial sample, see DPI Tutorial sample.

High DPI Tutorial

DPI Awareness Levels

The sample application can run at any of the three levels of DPI awareness level. Specify the DPI awareness level executing the application from a command prompt.

  • By default, the application does not call SetProcessDpiAwareness, so the application is not DPI-aware.
  • If you specify the “S” option at the command prompt, the application calls SetProcessDpiAwareness and sets the application as System DPI–aware.
  • If you specify the “P” option at the command prompt, the application calls SetProcessDpiAwareness and sets the application as per-monitor DPI–aware.

Call SetProcessDpiAwareness before you create the application window. You can only call SetProcessDpiAwareness once. If you call it more than once or if the application manifest specifies the DPI awareness level, the function call fails.

You can run the sample application on different displays to illustrate DPI issues and the benefits of making an application per-monitor DPI–aware. For illustrations, expected results, and other information about the effects of DPI awareness levels on an application, see Comparison of DPI Awareness Levels.

Developing a Per-Monitor DPI–aware application

Windows 8.1 gives developers new functionality to create desktop applications that are per-monitor DPI–aware. A per-monitor DPI–aware application does the following to adjust to the DPI level of any monitor on which its window is displayed:

  • Changes window dimensions to maintain a physical size that appears consistent on any display
  • Re-renders DX/GDI drawing for the new window size
  • Selects fonts that are scaled appropriately for the DPI level
  • Selects and loads bitmap assets that are tailored for the DPI level

To facilitate making a per-monitor DPI–aware application, Windows 8.1 provides the following:

  • SetProcessDpiAwareness (or DPI manifest entry) sets the process to a specified DPI awareness level, which then determines how Windows scales the UI. This supersedes SetProcessDPIAware.

    Note  You can also set the DPI awareness level in the application manifest.

  • GetProcessDpiAwareness returns the DPI awareness level. This supersedes IsProcessDPIAware.
  • GetDpiForMonitor returns the DPI for a monitor.
  • The WM_DPICHANGED window notification is sent to per-monitor DPI–aware applications when a window’s position changes such that most of its area intersects a monitor with a DPI that is different from the DPI before the position change. To create an application that resizes and re-renders itself when a user moves it to a different display, use this notification.

    Note  The WM_DPICHANGED notification is not sent when the user changes the desktop scaling value in Control Panel.

The tutorial sample application illustrates how an application handles the WM_DPICHANGED window notification to adjust its UI after a user moves it to a display that has a different DPI. The wParam of the window notification contains the new DPI in the wParam. The lParam contains a rectangle that has the size and position of the new suggested window, scaled for the new DPI.

The tutorial sample application stores the DPI value for use in its rendering routine to adjust the values for all relevant UI elements.


case WM_DPICHANGED: 
  // This message tells the program that most of its window is on a
  // monitor with a new DPI. The wParam contains the new DPI, and the 
  // lParam contains a rect which defines the window rectangle scaled 
  // the new DPI. 
 
            g_DPI.SetScale(LOWORD(wParam));  
            // Set the new DPI, retrieved from the wParam 
 
            if (g_DPI.GetAwareness() != PROCESS_PER_MONITOR_DPI_AWARE) 
            { 
                break; 
            } 
 
            lprcNewScale = (LPRECT) lParam;  
            // Get the window rectangle scaled for the new DPI, 
            //retrieved from the lParam 
            CopyRect(&rcNewScale, lprcNewScale);  
            // Save the rectangle for the on-demand rescale option
 
            if (g_bRescaleOnDpiChanged) 
            { 
                // For the new DPI: resize the window, select new 
                // fonts, and re-render window content 
                SetWindowPos(hWnd, 
                    HWND_TOP, 
                    lprcNewScale->left, 
                    lprcNewScale->top, 
                    RectWidth(*lprcNewScale), 
                    RectHeight(*lprcNewScale), 
                    SWP_NOZORDER | SWP_NOACTIVATE); 
                CreateFonts(hWnd); 
                RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE); 
            } 
            break;


In the tutorial sample code, g_DPI is a global helper class with methods to store the DPI and rescale values for rendering/sizing. Here are examples of these helper functions.


// Set the scaling factor % based on a DPI value
void SetScale(__in UINT iDPI) 

// Return the scaling factor %
UINT GetScale()

// Return the value of x scaled by the current scaling factor %
int  Scale(int x)

// Set the awareness level of the application
void SetAwareness(PROCESS_DPI_AWARENESS awareness)

// Get the awareness level of the application
PROCESS_DPI_AWARENESS GetAwareness()


Application code for rendering UI elements such as text, drawings, bitmaps, etc. can use DPI helper functions to appropriately adjust the values for font and drawing APIs, or to select a particular bitmap or other resource that is tailored for the DPI of the display.


// Scale the font height for the DPI
hFont = CreateScaledFont(g_DPI.Scale(nFontHeight));

// Select the bitmap designed for the DPI
if (g_DPI.GetScale() == 200)
{
    hbmpScaled = hBmpFor200DPI;
}
else
{
    hbmpScaled = hBmpFor100DPI;
}

// Scale the coordinates for drawing a rectangular frame
Rectangle(hdc, g_DPI.Scale(rcFrame.left),
               g_DPI.Scale(rcFrame.top),
               g_DPI.Scale(rcFrame.right),
               g_DPI.Scale(rcFrame.bottom));


In the previous examples, the g_DPI.Scale helper method translates the value for a UI element from its default value to its value scaled for the DPI of the display where the UI is presented.

For example, a not DPI–aware application creates a font of height 16. If the application remains not DPI–aware, that same font is used and scaled up by 200% when a user moves the application to a high DPI monitor with 200% scaling.

The per-monitor DPI–aware version of this application instead passes g_DPI.Scale(16) to the font-creation code. This results in passing a value of 32 when the rendering code is called on a monitor with 200% scaling.

Testing Guidance

A per-monitor DPI–aware application that has correctly scaled the values for its UIAPIs handles input and output correctly on all displays.

To test this, move the application’s window to and from displays that have different DPIs and confirm that the window and UI are properly scaled. Test various elements of the application’s UI, including menus and pop-up windows.

The DPI of a display changes in response to a resolution change or detaching the monitor on which the application is displayed.

Test the different ways in which user input can move or resize the application window:

  • Move and resize with mouse, keyboard, and touch input
  • Use hotkeys Win+L arrow and Win+R arrow to move into docked or undocked locations across all displays
  • Minimize, maximize, and restore
  • Move and resize into a position that straddle two monitors

Issues to look out for include:

  • Text that doesn’t fit in the given space
  • Text and controls that overlap or are not properly spaced
  • Text and images that are too small
  • Images that are properly sized but are of poor quality because of scaling
  • Lines that are too thin to see easily
  • Edges that don’t line up because of rounding problems when scaling
  • Controls that don’t respond to mouse or touch input
  • Touch gestures, such as panning and zoom, that don’t work in the expected range

 

 

コミュニティの追加

追加
表示:
© 2014 Microsoft