Windows 10 1607で、高DPI関係のAPIや型が追加されました。 その中にDPI_AWARENESS_CONTEXT
型があるのですが、この扱いで少しはまったので、覚書として残しておきます。
Windows 10 1607で追加された高DPI関係のAPI
Windows 10 1607で、高DPI関係のAPIが追加されました。そのAPI群の中に、
- SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext)
- DPI_AWARENESS_CONTEXT GetDpiAwarenessContextForProcess(…)
- SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext)
- DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext()
- DPI_AWARENESS_CONTEXT GetWindowDpiAwarenessContext(…)
など DPI_AWARENESS_CONTEXT
型を扱うAPIがあります。
DPI_AWARENESS_CONTEXT型
Windows SDKのヘッダーファイルによると、 DPI_AWARENESS_CONTEXT
型の定義は、以下のようになっています。
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5)
このように、Contextの種類ごとに値が定義されています。
DPI_AWARENESS_CONTEXTの値の設定と取得
DPI_AWARENESS_CONTEXT
型は、設定にも取得にも使われます。
- SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext)
- DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext()
のAPIのように、設定と取得のペアのAPIがあります。このAPIで設定して、その値を取得したどんな値が取得できるでしょうか?
例えば、以下のようなコードを実行したら、「Same」と「Different」のどちらのダイアログが表示されるでしょうか?
DPI_AWARENESS_CONTEXT hDpiContextSet = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
SetThreadDpiAwarenessContext(hDpiContextSet);
DPI_AWARENESS_CONTEXT hDpiContextGet = GetThreadDpiAwarenessContext();
if (hDpiContextSet == hDpiContextGet)
{
MessageBox(NULL, _T("Same"), _T("DPI_AWARENESS_CONTEXT"), MB_OK);
}
else
{
MessageBox(NULL, _T("Different"), _T("DPI_AWARENESS_CONTEXT"), MB_OK);
}
答えは、「Different」のダイアログが表示されます。
DPI_AWARENESS_CONTEXTの値
前掲したようにDPI_AWARENESS_CONTEXT
型の定義は、DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
となっています。この定義から分かるようにDPI_AWARENESS_CONTEXT
型は、Enum値ではなく、ハンドルです。そのため、値の直接比較では、内容の比較をしたことにならないのです。
実際、すべての値を設定して取得してみました。取得値は、Windowsの環境やバージョンによって異なることがあるかもしれません。
定義名 | 定義値 | 取得値 |
DPI_AWARENESS_CONTEXT_UNAWARE | -1 | 0x00006010 |
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE | -2 | 0x00009011 |
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE | -3 | 0x00000012 |
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 | -4 | 0x00000022 |
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED | -5 | 0x40006010 |
このように、 DPI_AWARENESS_CONTEXT
型の値は、同じ内容を示すときも別の値となります。そのため列挙値(Enum値)を想定して、値を直接比較したときは、期待の動作になりません。
DPI_AWARENESS_CONTEXTの値の比較
では、DPI_AWARENESS_CONTEXT
型のハンドル値が、どのDpiContextの種類を示しているか比較したいときはどうすればよいのでしょうか?
ちゃんとAPIが用意されています。 DPI_AWARENESS_CONTEXT
型が導入されたWindows 10 1607のときに、以下のAPIも追加されていました。
BOOL AreDpiAwarenessContextsEqual(
In DPI_AWARENESS_CONTEXT dpiContextA,
In DPI_AWARENESS_CONTEXT dpiContextB);
このAPIを使うと DPI_AWARENESS_CONTEXT
型のハンドルの内容の比較ができます。
そのため、前掲したサンプルコードは以下のように書き換えると、正しく動作します。
DPI_AWARENESS_CONTEXT hDpiContextSet = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
SetThreadDpiAwarenessContext(hDpiContextSet);
DPI_AWARENESS_CONTEXT hDpiContextGet = GetThreadDpiAwarenessContext();
if (AreDpiAwarenessContextsEqual(hDpiContextSet, hDpiContextGet))
{
MessageBox(NULL, _T("Same"), _T("DPI_AWARENESS_CONTEXT"), MB_OK);
}
else
{
MessageBox(NULL, _T("Different"), _T("DPI_AWARENESS_CONTEXT"), MB_OK);
}
if文の比較部分をAreDpiAwarenessContextsEqual()
を使って書き換えてました。
以上、DPI_AWARENESS_CONTEXT
型を使うときの注意点でした。