前回の記事で「Formが主に所属するモニターを判断する方法を考える」をまとめたのですが、SNSでいただいたヒントから一発取得方法を見つけました。
楽なことはいいことだ。
結論
このコードで一発!
Screen OrenoScreen = Screen.FromControl(this);
解説
Screen.FromControlは指定したコントロールが最も広く所属するScreenを取得するメソッドです。もちろんForm相手にも使えます。
この実装コードを見ると、FromControlは内部的にFromHandleInternalを呼び出し、その中でWin32APIのMonitorFromWindowを呼び出しています。これこそが「指定したウィンドウがどのモニタ上で最大面積を持っているかを取得」する一発取得なWin32API。
このAPIのドキュメントには下記のようにあります。
指定したウィンドウと重なるディスプレイモニタが1台以上見つかった場合は、ウィンドウとの交差部分が最も広いディスプレイモニタの HMONITOR ハンドルが返ります。
指定したウィンドウと重なるディスプレイモニタが見つからなかった場合は、dwFlags パラメータにより示される内容が返ります。
見つけ方は前回の記事で書いた考え方と同じでした。
私は見つからなかった場合にプライマリモニターを指定していたので、dwFlagsにMONITOR_DEFAULTTOPRIMARYを指定したときの考え方です。
FromHandleInternalはdwFlagsにMONITOR_DEFAULTTONEARESTを指定しているため、見つからなくとも近いモニターを選択することになり、より人間的な結果となります。
やっぱり一発取得方法はあった!
そして俺の考えより高機能だった!
ぱっと分かったのは.NET Framwork 4.6でリファレンスソースが公開された恩恵です。
検索が強力な時代なので、実装コードが見えれば目的のものを探すのは容易。
今後も活用したいと思います。ありがたや。
ということで、こちらを使っていこうと思います。
前回の記事も考え方の整理ってことで参照いただけると幸いです。
ついでに似たようなメソッドも解説
ScreenのFromなんたらメソッドは4つ。
これをうまく使うことでマルチモニター処理をうまいことやれるようになると思います。
FromControl
今回使ったやつ。
内部的にFromHandleの実装となるFromHandleInternalを呼ぶので同じ動作になる。
Windowハンドルとか意識しなくていいので.NET向き。
FromHandle
動きはFromControlと一緒。中でFromHandleInternalを呼んでるだけ。
直接Windowハンドルを使えるんで、Win32APIから取得したWindowハンドルをそのまま使える。
FromRectangle
指定した矩形(Rectangle)の面積が最も大きく含まれるScreenを取得する。
FormやControlではない領域を測る際に使えるかも。
FromPoint
指定した座標が含まれるScreenを取得する。
これは目的も結果も分かりやすい。
謝辞
かおくさん、かずまおさん、情報ありがとうございました!
返信がありません