👏

C#実装で最背面にしたウィンドウでマルチモニタ環境でハマった話

2025/03/07に公開

状況

作成したアプリをマルチモニタ対応にしようと作業した中で、ハマった話です
作成中アプリってのは、これ
https://zenn.dev/maedan/articles/428a5eacf0b34a
Boothで販売しているので、興味あれば購入下さい
https://nori33.booth.pm/items/6572311

現状

フォームを常時最背面としたいので、Win32APIを使用して、Progman以下のウィンドウを親として登録してました。

Progma/SHELDLL_DefView/SysListView32を親ウィンドウに設定して、最背面としています。
このアプリを、マルチモニタの環境で動作させると、予期せぬ動きとなります

現象

フォームをドラッグ&ドロップで移動出来るようにしていますが、マウスでクリックした瞬間にウィンドウが何処かに飛んで行ってしまいます

原因

マルチモニタの場合には、プライマリモニタ側の左上が原点(0,0)となります

位置が逆の場合には、プライマリモニタの左上が原点(0,0)は変わらないので、セカンダリモニタのX軸方向はマイナス値となります。

この話は、フォームを配置する位置を指定する「Location」プロパティの値にも反映されるので、プライマリモニタが右側にある場合には、Location.xにマイナス値を設定する事で、セカンダリモニタに配置する事が出来ます。
ただし、Progman配下のウィンドウを親とした場合には違います。モニタの位置に関係なく一番左側で上側が原点(0,0)となります。

ただし、

this.Location.X
this.Location.Y

で値を取得すると、Progma配下とか関係なく、通常通りでの値となります。なので、セカンダリモニタが左側にある場合には、設定はセカンダリモニタの左上からの数値指定なんですが、Locationの値を取得すると、マイナス値が取れる事になります。

フォームを移動やサイズ変更するために、マウスクリックした場合に以下の様に、Location情報を覚えておく様な実装だったので、

MouseDown
lastForm = this.Location;

this.Locationで、マイナス値を取得して、lastFormではセカンダリモニタの右上を原点として表示位置としていたので、絶対見えない場所に飛んでった様です。

Discussion