2024/04/05(金) [n年前の日記]
#2 [prog] 自作スクリーンセーバを高DPIに対応させる
今時のWindowsは、デスクトップ設定で、文字表示その他を、125%とか150%とかに変更できる。おそらく高DPIと呼ばれる状態なのだろうけど…。
この状態にすると、スクリーンセーバ設定ダイアログ上で、スクリーンセーバのプレビュー表示がおかしな位置に表示されてしまう。この問題を解決したい。
結論を先に書いておく。マニフェストファイルを作成して、スクリーンセーバのリソースファイル内でマニフェストファイルを指定して埋め込んでおけば、一応は正常な表示になる。
環境は、MinGW g++ 6.3.0、ld 2.28、windres 2.28。Windows10 x64 22H2上で作業。
この状態にすると、スクリーンセーバ設定ダイアログ上で、スクリーンセーバのプレビュー表示がおかしな位置に表示されてしまう。この問題を解決したい。
結論を先に書いておく。マニフェストファイルを作成して、スクリーンセーバのリソースファイル内でマニフェストファイルを指定して埋め込んでおけば、一応は正常な表示になる。
環境は、MinGW g++ 6.3.0、ld 2.28、windres 2.28。Windows10 x64 22H2上で作業。
◎ 不具合を発見した経緯 :
自作したWindows用スクリーンセーバを ―― 疑似3D道路を描画するスクリーンセーバを、親父さんのPC上で動かして動作確認してみたところ、スクリーンセーバ設定ダイアログ上のプレビュー表示がおかしくなってることに気づいた。本来表示されるべき位置からかなり左上のほうに表示されてしまって、描画内容の右下だけが、プレビュー画面の左上のほうにちょっとだけ表示されてしまっている。何故だ。どうしてこうなった。
そこでふと気が付いた。親父さんは視力が衰えてしまっているので、Windowsのディスプレイ設定で、「テキスト、アプリ、その他の項目のサイズを変更する」を150%にしていた…。たぶんそのせいじゃないだろうか。
自分のメインPC上でも、そのあたりを変更してみたところ、親父さん用PCと全く同じ不具合が再現できた。
今までビルドしてきた各スクリーンセーバについても一通り試してみたところ、OpenGLを使っている/使ってないに係わらず、どのスクリーンセーバも、プレビュー表示は表示位置がおかしくなった。
この結果は、当然な気もする。自分がググって今まで参考にしてきた、スクリーンセーバの作成方法を解説しているページは、「高DPI? ナニソレ?」「WindowsのDPIと言えば96DPIに固定されてるもんだろJK」という時代に書かれているので、こういった不具合が起きることも、もちろん解決策についても、一切言及していない。故に、どのサンプルを動かしてもこういう不具合が発生するのは必然、ということなのだろう…。
そこでふと気が付いた。親父さんは視力が衰えてしまっているので、Windowsのディスプレイ設定で、「テキスト、アプリ、その他の項目のサイズを変更する」を150%にしていた…。たぶんそのせいじゃないだろうか。
自分のメインPC上でも、そのあたりを変更してみたところ、親父さん用PCと全く同じ不具合が再現できた。
今までビルドしてきた各スクリーンセーバについても一通り試してみたところ、OpenGLを使っている/使ってないに係わらず、どのスクリーンセーバも、プレビュー表示は表示位置がおかしくなった。
この結果は、当然な気もする。自分がググって今まで参考にしてきた、スクリーンセーバの作成方法を解説しているページは、「高DPI? ナニソレ?」「WindowsのDPIと言えば96DPIに固定されてるもんだろJK」という時代に書かれているので、こういった不具合が起きることも、もちろん解決策についても、一切言及していない。故に、どのサンプルを動かしてもこういう不具合が発生するのは必然、ということなのだろう…。
◎ マニフェストファイルがあれば動作が変わる :
ただ、試しているうちに、FreeBASICで作成したスクリーンセーバだけが、高DPIにしても正常なプレビュー表示になっていることに気づいた。
_freeBASIC Screensaver Kit Updated - freebasic.net
_FreeBASIC Screensaver Kit - freebasic.net
一体何が違うのか調べてみたところ、FreeBASICのスクリーンセーバ作成用kitには、マニフェストファイル(manifest)が添付されていることに気づいた。
そのマニフェストファイルに書かれていた内容は以下。
内容についてググった感じでは…。この記述は、Windows Vistaの時点で追加されたDPI変更機能に対応させるための記述、ということらしい。
ちなみに今現在は、Windows10 Version 1607で追加された機能もあるらしくて、完全に対応させるならそのあたりもアプリ側で行わないといかんらしい…。
更に、このマニフェストファイルは、リソースファイルの中で取り込むように指定されていた。リソースファイルの内容は以下。
一番最後に、「1 24 "MambazoDoodle.xml"」 という記述がある。
_freeBASIC Screensaver Kit Updated - freebasic.net
_FreeBASIC Screensaver Kit - freebasic.net
一体何が違うのか調べてみたところ、FreeBASICのスクリーンセーバ作成用kitには、マニフェストファイル(manifest)が添付されていることに気づいた。
そのマニフェストファイルに書かれていた内容は以下。
<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>
内容についてググった感じでは…。この記述は、Windows Vistaの時点で追加されたDPI変更機能に対応させるための記述、ということらしい。
ちなみに今現在は、Windows10 Version 1607で追加された機能もあるらしくて、完全に対応させるならそのあたりもアプリ側で行わないといかんらしい…。
更に、このマニフェストファイルは、リソースファイルの中で取り込むように指定されていた。リソースファイルの内容は以下。
FB_SCRNSAVER_ABOUT DIALOGEX 6, 18, 160, 62 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_NOFAILCREATE FONT 10,"Arial" CAPTION "Mambazo Doodle" BEGIN CTEXT "Mambazo Doodle" -1, 0, 5, 160, 8 CTEXT "Version 1.0" -1, 0, 15, 160, 8 CTEXT "http://langfordtavern.com/" -1, 0, 25, 160, 8 DEFPUSHBUTTON "OK" IDOK, 55, 40, 50, 14 END 1 24 "MambazoDoodle.xml"
一番最後に、「1 24 "MambazoDoodle.xml"」 という記述がある。
- ここで指定されているxmlファイルがマニフェストファイル。
- 最初のほうにある「1 24」は、マニフェストファイルをリソースファイル内で指定する際のお約束らしい。
◎ 自作スクリーンセーバにも導入してみた :
試しに、自作のスクリーンセーバでも同じことをやってみた。
この状態でビルドし直したところ、WindowsのデスクトップのDPIを変更しても、スクリーンセーバ設定ダイアログ上で正常な位置にプレビューが表示される状態になった。
_mieki256/ssp3droadgl
とりあえず今回は、この対応だけでいいんじゃないかな…。
- マニフェストファイル名を、「スクリーンセーバファイル名.manifest」にする。
- リソースファイル(resource.rc)の最後に、該当行を追加。
1 24 "ssp3droadgl.scr.manifest"
この状態でビルドし直したところ、WindowsのデスクトップのDPIを変更しても、スクリーンセーバ設定ダイアログ上で正常な位置にプレビューが表示される状態になった。
_mieki256/ssp3droadgl
とりあえず今回は、この対応だけでいいんじゃないかな…。
◎ 他のスクリーンセーバも対応させておいた :
[ ツッコむ ]
以上です。