You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
if (setDllDirectoryW) setDllDirectoryW(L""); // DLL hijacking prevention.
254
+
FreeLibrary(kernel32);
255
+
}
289
256
```
290
257
258
+
ちなみに、[`SetDllDirectoryW()`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectoryw) を直接呼び出さないのは Windows 2000 にこの API が実装されていないためなので、Windows XP 以降が対象なら単に `SetDllDirectoryW(L"");` だけで十分です。この機能を持たない Windows 2000 上では DLL hijacking に対して脆弱となりますが、そもそも今では脆弱性の塊みたいな OS なのでそこまで考えなくても良いでしょう。
259
+
291
260
## 番外編:`MessageBoxW()`
292
261
293
262
High DPI 対応にあたり、考慮が必要な API があります。ここではほとんどのプログラムで使用するであろう超主要なものを説明します。まずはちょっとしたダイアログの表示に使う [`MessageBoxW()`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxw) についてです。
294
263
295
264

296
265
297
-
`MessageBoxW()` は System DPI レベルなので、異なる DPI 設定のモニタ間を移動させたり DPI 設定を変更したりするとピンぼけします(クソポイント 3)。その対策として代替 API である [`TaskDialog()`](https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-taskdialog) が使えますが、引数などの仕様が大きく異なります。また、これは Windows Vista で導入されたため Windows XP 以前では存在しません。なので、以下の仕様の wrapper 関数を作成する必要があります(まあ、Windows Vista 以降しかサポートしないなら `TaskDialog()` をそのまま使えば良いわけですが)。
266
+
`MessageBoxW()` は System DPI レベルなので、異なる DPI 設定のモニタ間を移動させたり DPI 設定を変更したりするとピンぼけします。その対策として代替 API である [`TaskDialog()`](https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-taskdialog) が使えますが、引数などの仕様が大きく異なります。また、これは Windows Vista で導入されたため Windows XP 以前では存在しません。なので、以下の仕様の wrapper 関数を作成する必要があります(まあ、Windows Vista 以降しかサポートしないなら `TaskDialog()` をそのまま使えば良いわけですが)。
次はフォント選択画面を表示する [`ChooseFontW()`](https://learn.microsoft.com/en-us/windows/win32/api/commdlg/nc-commdlg-choosefontw) に関してで、これも System DPI レベルの対応です。しかし、こちらはピンぼけではなく**挙動がおかしくなります**(クソポイント 4)。
346
+
次はフォント選択画面を表示する [`ChooseFontW()`](https://learn.microsoft.com/en-us/windows/win32/api/commdlg/nc-commdlg-choosefontw) に関してで、これも System DPI レベルの対応です。しかし、こちらはピンぼけではなく**挙動がおかしくなります**。
378
347
379
348

380
349
@@ -412,7 +381,7 @@ if (ret) {
412
381
413
382
## おわりに
414
383
415
-
本日は、Windows の High DPI 対応用 API の現状を簡単にまとめた上で、Win32 API 実装で古い OS との互換性を切らずに High DPI 対応する方法を説明しました。複雑な実装とはなりますが、古い環境でも最新の環境でも完璧に振る舞えるアプリを開発できるのが C/C++ による Win32 API 直呼び出し実装の醍醐味だと思います。まあ、実用的なアプリを開発するには原始的すぎて今となっては非現実的ですが、古くから開発を続けているアプリの High DPI 対応化などの役に立てば幸いです。
384
+
本日は、Windows の High DPI 対応用 API の現状を簡単にまとめた上で、Win32 API 実装で古い OS との互換性を切らずに High DPI 対応する方法を説明しました。歴史的経緯で塗り固められた Windows の汚い部分に真正面から向き合うことになりますが、古い環境でも最新の環境でも完璧に振る舞えるアプリを開発できるのが C/C++ による Win32 API 直呼び出し実装の醍醐味だと思います。まあ、実用的なアプリを開発するには原始的すぎて今となっては非現実的ですが、古くから開発を続けているアプリの High DPI 対応化などの役に立てば幸いです。
416
385
417
386
実際に Windows 2000 以降の互換性を維持しながら、Windows 11 でも完璧に Per-Monitor V2 High DPI 対応するように設計したソフトウェアとして、拙作の [Brainfuck インタプリタ](https://github.com/watamario15/brainfuck)があります(これはさらに preprocessor switch で [SHARP Brain 電子辞書](https://jp.sharp/edictionary/)を含む [Windows CE](https://ja.wikipedia.org/wiki/Microsoft_Windows_Embedded_CE) にも対応します)。まあ、2025 年を目前に控えて Windows 10 より古い OS をサポートする理由はもはや皆無なわけですが、ロマンがありますよね。
[^4]: Device context まで指定して呼び出す画面の pixels per inch を返す関数が、High DPI awareness のセーフガードまでついているにも関わらず、System DPI しか返さないのが謎でしかないのです。セーフガードがある時点で壊れる互換性なんてないだろうし、むしろ画面の pixels per inch を取れると期待するプログラムの互換性を壊しているはずです。
437
410
[^5]: 2025 年を目前に控えた今では普通それで良いですが、「古い OS との互換性を切らずに High DPI 対応する」が本記事の趣旨なので。
0 commit comments