2022年3月25日金曜日

Windowsのモニタ認識番号でどうしようもなくハマったので覚書

仕事でマルチモニタで作業をすることが多い私。今回はその中で「あんちきしょう!」と叫びたくなるくらいハマったので、自分用の覚書的に記事にしてみました。

なお、今回の記事ではレジストリを弄りまわしているので、自力で元に戻す自信のない方や、レジストリって何?って方は不用意に試さないで下さいね。失敗すると本気でPC壊れちゃうので。 

では、本題。仕事上で使うツールの中に、マルチモニタ環境で複数のツール画面を展開できるものがあるんですが、この中のとあるウィンドウが、表示して欲しいモニタに出てくれない!という事態に遭遇。当初「プライマリディスプレイになってないからでしょ?」程度に軽く考えていたものの、プライマリディスプレイの設定はきちんと行われており、何ら問題ないことを確認。接続を変えてもダメ。

困り果ててリファレンスに目を通すと

「本ツールのウィンドウ制御は、ディスプレイの識別番号によって表示位置を認識しています」との記述を発見。

つまり、プライマリディスプレイを起点とした絶対座標でもなければ、ツールのメインウィンドウを起点とした相対座標でもなく、各ディスプレイ毎の絶対座標をディスプレイ識別番号で設定し、表示していたわけです。

で、困ったのがモニタの接続は入れ替えられるけど、モニタ自体は入れ替えられないって事。いや、入れ替えようと思えば入れ替えられるんですが、モニタアームを使用している環境だったので「めんどくっさ!」となった訳ですね。

何とか設定変更で解決できないものかと色々調べたところ、どうもレジストリでディスプレイ毎のハードウェア的な情報と表示時に付与する番号を管理しているらしい、ということが判明しました。

HKLM\Systems\CurrentControlSet\Control\GraphicsDrivers\Configuration
HKLM\Systems\CurrentControlSet\Control\GraphicsDrivers\Connectivity

 要はこの2つのレジストリを消しちゃえば、過去に当該端末へ接続したディスプレイの識別情報は綺麗さっぱりなくなるということ、ですね。

※作業時に接続するディスプレイは、識別上1番で認識して欲しいディスプレイのみに限定する必要はあるみたいです。

まぁレジストリはレジストリなわけで、下手に弄ると取り返しのつかないことになるわけですね。ええ、訳も分からず弄るとOS壊すって事です。やはり作業前に消そうとしているレジストリはバックアップを取るべきでしょうね。

 ただこの作業、結構な頻度で発生しそうなので(仕事柄マルチモニタ環境を作る機会が結構多い)全部ひっくるめてbatファイルにしちゃうことにしました。

 以下ソース

@echo off

REM カレントディレクトリを保持します
SET CAL_DIR=%~dp0

REM バックアップしたレジストリの出力先
SET TmpFile=%CAL_DIR%%date:/=-%


ECHO 本バッチプログラムを実行すると、過去に端末に接続されたディスプレイの認識情報をすべて初期化されます。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 第1段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

ECHO 本バッチプログラムを実行する前に、ディプレイ認識番号1番で認識させたい
ECHO ディスプレイのみ、接続されている状態であることを確認してください。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 第2段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

REM バックアップしたレジストリファイルの格納先を用意
IF NOT EXIST %TmpFile% (
 MKDIR %TmpFile%
)

REM 既存レジストリをバックアップ
REG EXPORT HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Configuration %TmpFile%\GraphicsDriversConfiguration.reg /y
REG EXPORT HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Connectivity %TmpFile%\GraphicsDriversConnectivity.reg /y

REM 既存レジストリのバックアップ実行状態チェック
IF NOT EXIST %TmpFile%\GraphicsDriversConfiguration.reg (
 ECHO 既存レジストリのバックアップに失敗しました。処理を中止します。
 GOTO END
)
IF NOT EXIST %TmpFile%\GraphicsDriversConnectivity.reg (
 ECHO 既存レジストリのバックアップに失敗しました。処理を中止します。
 GOTO END
)

ECHO 最終確認 過去に端末に接続されたディスプレイの情報を初期化します。
ECHO 実行しているプログラム等によっては、予期しない不具合が生じる可能性があります。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 最終段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

REM 既存レジストリを削除
REG DELETE HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Configuration /f
REG DELETE HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Connectivity /f

:END
pause

はい、わかる方からしたらかなり無駄な事してるなぁと思われそうな(笑)。

処理の流れとしては、

1.既存のレジストリをバックアップするフォルダを日付でカレントディレクトリに作成

2.キー「Configuration」とキー「Connectivity」をバックアップ

3.キー「Connectivity」とキー「Connectivity」を削除

って感じです。気を付けないといけないのは、本処理を実施する場合、事前に認識番号1番で認識して欲しいディスプレイのみ接続されている状態になるようにしなきゃいけないって事と、管理者での実行が必須って事ですかね。 

ちなみに、実行後に認識番号2番以降で接続して欲しいディスプレイをつなぐ場合、必ず再起動すること。というのも、本バッチプログラムで削除したふたつのキーは、ディスプレイの「再接続」時に生成されるため、実行直後は空っぽの状態になっています。これがちょっと厄介。

どういうことかというと、認識番号1番で拾って欲しいディスプレイの接続情報、バッチ実行直後(レジストリ削除直後)には再作成されていない為、「うほーい!レジストリが消えたぜ!」と意気揚々と認識番号1番で拾って欲しいディスプレイが接続されている端末に、認識番号2番で拾って欲しいディスプレイを再起動せずに接続しちゃうと、後から接続したディスプレイに認識番号1番が付与されてしまい、本来1番で認識して欲しかったディスプレイの認識番号が2になっちゃうんですね。何とまぁ。。。

コレ、環境によって再現したり再現しなかったりマチマチで、気づくまでに滅茶苦茶時間がかかりました。あうあうあー。

 

というかこれ、UIレベルで修正できるようにならないものなんですかね。。まったく。

 

 2022/4/4 追記

その後調査してみたところ、オンボードグラフィックと別にUSB接続のグラフィックアダプタや、一部のマザボでは上記手順を実施してもうまくいかないケースがあることが判明。要はUSBアダプタのディスプレイ番号を、オンボード接続のディスプレイ番号の間に割り込むような形(オンボード DVIがNo1,USBアダプタがNo2,オンボードD-SubがNo3)みたいな認識は出来ないみたいです。面倒くさいなぁ。。。

 

ではまた!

0 件のコメント:

コメントを投稿