このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com ロゴ
作成 December 15, 2022、部分調整 September 4, 2024
トップページ > Windows トップ > マルチモニタを制御
line
Windows 開発
line

ここでは、マルチモニタを制御する方法について、書いています。

Natural Intelligence による記事要点まとめ
・簡単に構築できるマルチモニタ環境は便利である。
・接続されたモニタの台数やモニタごとの解像度を取得できる。
・スクリーン全体のキャプチャもできる。

ソフトウェア開発においても、ドキュメント作成においても、スマホよりはるかに広い画面を使える PC ですが、 それでもなお、2 画面を同時に使えるマルチモニタ環境に慣れてしまうと、もう 1 画面には戻れません。 SSD を使い始めたらもう HDD には戻れない、と同じように。

デスクトップ PC の場合、モニタを 2 台同時に使用するのは簡単です。 モニタが 2 台あれば、 メインモニタ ( プライマリ、「主要な」と呼ぶようです。 ) で Visual Studio を最大化で開いて、サブモニタでブラウザを開いて調べ物をする、というのが簡単です。 メインモニタでドキュメントを書いてサブモニタで YouTube を観る・・・ということもできます。 メインモニタで PhotoShop を開いてサブモニタで素材を選ぶ、でも構いません。

私の環境では、デスクトップ PC の背面の USB に次の製品を接続し、サブモニタとして使うモニタ 2 に接続するのみです。 電源などは必要ありません。

Amazon 広告 ▼
アイ・オー・データ マルチ画面 USB グラフィック アナログ RGB 対応 WXGA+/SXGA対応 USB2.0 接続 USB-RGB2
アイ・オー・データ 外付けグラフィックアダプター アナログ専用モデル USB アナログ RGB 変換 マルチディスプレイ USB-RGB2S
アイ・オー・データ マルチ画面 USB グラフィック DVI-I/アナログ RGB 対応 WUXGA/フル HD 対応 USB2.0 接続 USB-RGB/D2

Amazon の購入履歴を確認したところ、2013 年に購入していました。 もうすぐ 10 年です。 実際に使用しているのは上の広告の一番上のアナログ用で、いまだに壊れずに動いています。

後継機種が発売されており、もう新品は入手しにくそうです。

初期設定も簡単です。 説明書に従って接続し認識されたら、デスクトップの何もないところで右クリックし 「ディスプレイ設定」を選択して、配置などを指定するだけです。

ディスプレイ設定

新しいモニタと古いモニタで解像度が異なっていても大丈夫です。 余っているモニタが生き返ります。

ディスプレイの配置を変更する

ここでは使い方ではなく、すでに設定が済んでいる 2 台のモニタの C++ からの検出や制御について、書いています。

コードは Windows 10、Visual Studio 2015 で作成、確認したものです。 一部 MFC ( Microsoft Foundation Class、マイクロソフトが提供する、便利なクラスライブラリです。 ) を使用していますが大きな要素ではありませんので、 MFC を使用しなくても、あるいは Visual Basic でも同様のコードで動作すると思います。

アイコン システム SSD を大容量のものに交換する
DELL デスクトップ PC で、システム SSD を大容量のものに交換する手順について書いています。 もちろん OS ごとデータを移動させます。



▼ セクション一覧

接続されたモニタの台数を取得する
画面ごとの解像度を取得する
画面のキャプチャを保存する

なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。

接続されたモニタの台数を取得する

投稿 December 15, 2022

Windows で、接続されているモニタの台数を取得するのは簡単です。

int nNum = GetSystemMetrics(SM_CMONITORS);

モニタが 1 台であれば 1 が、2 台であれば 2 が返されます。

GetSystemMetrics 関数は、 システム設定を取得する便利な Windows API です。 この関数に定数 SM_CMONITORS を渡すだけです。 SM_CMONITORS は WinUser.h値 80 が割り当てられています。 Visual Basic から使用する場合は、80 を渡せばよいことになります。

▲ページ先頭へ

画面ごとの解像度を取得する

投稿 December 15, 2022

以下の実験は、メインモニタを左に、サブモニタを右に並べた状態で行っています。

ディスプレイの配置を変更する

画面解像度を得ようといつものように取得を試みると、メインモニタの解像度が返されました。

int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);

メインモニタが 1920x1080、サブモニタが 1366x768 でこの呼び出しを行うと、1920x1080 が返されました。 まずはこの呼び出しでメインモニタの解像度を取得できました。

次のような呼び出しを行うと、バーチャルスクリーンの解像度を取得できます。 「バーチャル」ですから「仮想」です。

int vw = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int vh = GetSystemMetrics(SM_CYVIRTUALSCREEN);

1920x1080 と 1366x768 で運用のとき、3286x1080 が返されました。

横方向に並んでいますので 1920 + 1366 = 3286 でぴったりですが、 縦方向はメインモニタは 1080 ですが、サブモニタは 768 ですので、サブモニタの下部には表示できない領域が含まれています

サブモニタの解像度を取得できる関数や引数は、なさそうです。

int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);

この呼び出しで、バーチャルスクリーンの原点の座標を取得できるようです。 左にメインモニタ、右にサブモニタを配置している場合は、x、y とも 0 が返されます。

モニタが左右に配置されている場合SM_CXVIRTUALSCREEN で取得したバーチャルスクリーンの横幅は、 SM_CXSCREEN で取得したメインモニタの横幅より大きくなっています。 この場合、メインモニタが左でサブモニタが右なのか、その逆にメインモニタが右でサブモニタが左なのか、判断する必要があります(連続的に使用したい場合)。

バーチャルスクリーンの原点の座標が (0,0) ならサブモニタが右に配置されていると言えます。 しかし x 座標が 0 未満、例えば -1366 なら、サブモニタが左に配置されているということになります。

ディスプレイの配置を変更する

モニタが上下に配置されている場合SM_CXVIRTUALSCREEN で取得したバーチャルスクリーンの横幅は、 SM_CXSCREEN で取得したメインモニタの横幅と一致しているはずです(メインモニタの解像度がサブモニタの解像度より低くない場合)。 この場合には、メインモニタが上でサブモニタが下なのか、その逆にメインモニタが下でサブモニタが上なのか、判断する必要があります。

同様に、バーチャルスクリーンの原点の座標が (0,0) ならサブモニタが下に配置されていると言えます。 しかし y 座標が 0 未満、例えば -768 なら、サブモニタが上に配置されているということになります。

前提条件がない場合は、バーチャルスクリーンの原点の座標の符号をみて判断する、ということになりそうです。

サブモニタの情報を取得するために、サブモニタ上の座標を指定します。

モニタが横に並んでいる場合は、x 座標は、サブモニタが左なら -1、右ならメインモニタの解像度 w を使います。 どちらの場合でも y 座標は 0 です。

モニタが縦に並んでいる場合は、y 座標は、サブモニタが上なら -1、下ならメインモニタの解像度 h を使います。 どちらの場合でも x 座標は 0 です。

サブモニタ上にある座標を POINT 構造体、 あるいは MFC の CPoint クラスに設定します。 そしてそれを MonitorFromPoint 関数 に渡してモニタのハンドル HMONITOR を取得します。

HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);

取得に失敗すると NULL が返されるようです。

モニタのハンドルを取得できたら、モニタの情報を取得できます。

MONITORINFO mi;
mi.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMonitor, &mi);

GetMonitorInfo 関数 にモニタのハンドルを渡すと、 MONITORINFO 構造体 に情報を設定してくれます。

MONITORINFO 構造体の RECT rcMonitor メンバに、そのモニタの表示位置を仮想画面座標で表した値を得られます。 つまり、そのモニタ、今の場合はサブモニタの解像度は、次のように計算できます。

int w2 = mi.rcMonitor.right - mi.rcMonitor.left;
int h2 = mi.rcMonitor.bottom - mi.rcMonitor.top;

サブモニタの原点が (mi.rcMonitor.left, mi.rcMonitor.top) になることに注意が必要です。

サブモニタを縦に並べた場合、バーチャルスクリーンの解像度は 1920 x 1848 となり、 サブモニタが下にあるときの領域は (0, 1080) から 1366x768 となりました。 サブモニタが上にあるときには (0, -768) から 1366x768 となりました。

サブモニタが左にある場合には、バーチャルスクリーンの解像度は 3286x1080 ですが、 サブモニタの領域は (-1366,0) からの 1366x768 です。

なお、「ディスプレイの配置を変更する」画面では、 モニタを横に並べる場合でも、y 座標を上に合わせなくても中間にできたり、下を揃えたりできますので、原点座標は変わってきます。 縦に並べる場合でも同様に、x 座標を左にあわせなくても、右に合わせたり、中間に設定したりもできますので注意します。

▲ページ先頭へ

画面のキャプチャを保存する

投稿 December 15, 2022

ここまでの内容とは特に強い関係はないのですが、バーチャルスクリーン全体のキャプチャをファイルに保存してみました。

まずはバーチャルスクリーンの解像度を取得します。

int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);

続いてデスクトップのウィンドウを取得します。

CWnd* pwndDesktop = CWnd::GetDesktopWindow();
CPaintDC dcDesktop(pwndDesktop);

ここに出てくるクラス、CWndCPaintDC は MFC 特有です。

GetDesktopWindow 関数はデスクトップのウィンドウクラスを取得するための関数で、ウィンドウを表すクラス CWnd のポインタが返されます。 Windows API の GetDesktopWindow 関数 を使えば、ウィンドウハンドル HWND を取得できます。

CPaintDC は、描画用 DC、デバイス・コンテキストです。

デスクトップと互換性のある CBitmap を作成します。 ここにスクリーンショットを格納します。

CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dcDesktop, w, h);

メモリ DC を作成して、今作成した互換性のある CBitmap を選択します。 メモリ DC とは、実際のデバイスとは関連付けられていない、仮想の描画面です。

CDC memDC;
memDC.CreateCompatibleDC(&dcDesktop);
CBitmap* pBmp = memDC.SelectObject(&bitmap);

デスクトップの DC からこのメモリ DC に全体をコピーします。

memDC.BitBlt(0, 0, w, h, &dcDesktop, 0, 0, SRCCOPY);
memDC.SelectObject(pBmp);

MFC の BitBlt 関数 により、メモリ DC に、dcDesktop の (0,0) からの画像を、(0,0) から横 w ピクセル、縦 h ピクセルの領域をコピーしています。 Windows API の BitBlt 関数 と同等です。

コピーしたら、もとの CBitmap を選択して戻しておきます。

MFC の CImage クラス を使うと、ファイルへの保存が簡単です。

CImage img;
img.Attach((HBITMAP)bitmap.GetSafeHandle());
img.Save(_T("desktop.bmp"));
img.Detach();

デスクトップがコピーされた CBitmap の bitmap を CImage に選択(アタッチ)し、 カレントフォルダに desktop.bmp として保存しています。 保存したら関連付けを解除(デタッチ)しておきます。

保存されたファイルを見ると、サブモニタで不足している領域は黒になりました。 memDC.BitBlt でサブモニタの部分だけを切り出せば、サブモニタだけのキャプチャも簡単でしょう。

最後に、もしどうしても MFC が嫌なら、妥協して MFC DLL にして本体と切り離す、というのはいかがでしょうか?

▲ページ先頭へ
line
関連トピックス
line

FTP でファイルをアップ&ダウンロード

Visual C++/MFC で、サーバーに FTP 接続してファイルをアップロード、ダウンロードするコードを書いています。

タイムスタンプを自由に変更する

Windows のファイルにある 3 種類のタイムスタンプ、作成日時、更新日時とアクセス日時を書き換えられるコードについて、書いています。

_sprintf でリンクエラーを回避する

古い Visual C++ プロジェクトから新しい環境に移行したとき、_sprintf でエラーが出る場合の回避方法について、書いています。

VS Community 2022 をインストールする

すでにインストールされている VS 2019 をアンインストールし、VS Community 2022 をインストールしなおしています。

Visual Studio Community 2019 を共存インストールする(デスクトップ)

VS 2019 をメイン デスクトップ機に共存インストールした様子を、書いています。 システムドライブの容量を節約し、データドライブにインストールされるようにしています。

line
その他のおすすめ
line

Android 開発トップ

Android 開発関連の情報を、書いています。

Windows 開発トップ

Windows 開発関連の情報を、書いています。

アプリ開発ブログ

本サイトの新着情報を紹介しています。



© 2017-2024 StraightApps.com 無断転載を禁じます。No reproduction without permission.