C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: C++(MFC)でモニタ情報の取得


(過去ログ 121 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■72681 / inTopicNo.1)  C++(MFC)でモニタ情報の取得
  
□投稿者/ nobb (44回)-(2014/07/04(Fri) 15:48:49)

分類:[C/C++] 

2014/07/04(Fri) 16:59:09 編集(投稿者)
2014/07/04(Fri) 15:50:49 編集(投稿者)

== 追記 ==
(device.StateFlags & DISPLAY_DEVICE_ACTIVE) != 1
という比較をしたところ、3番以降のモニタについては除外できるようになりました。
引き続き、型番の取得方法をお教えください。
==========

C++(MFC)でモニタの情報を取得する為に以下のソースを書きました
取得したい情報は、解像度・モニタの型番です。
解像度の取得は一応できていますが、
仮想モニタ(と言っていいのかわかりませんが・・)みたいなものまで取得され困っています。
(取得される文字列も最後にコピペしてあります。)

3番目以降は取得しなくてもいいので、どうやれば除外できるでしょうか?
また、型番の取得はどのように行えばいいでしょうか?
型番の取得については全く分からないので、出来たら詳しくお教え頂けたらうれしいです。


開発環境:Windows7、VS2013 Update2、C++(MFC)、デュアルディスプレイ
対象環境:WindowsXP以上、シングルディスプレイ以上

== ソース ==
CString CMFCApplication1Doc::GetInformation2()
{
  if (!m_str.IsEmpty()) m_str = _T("");
  int count = 0;
  int maxMonitorCount = 10;
  for (int i = 0; i < maxMonitorCount; i++)
  {
    DISPLAY_DEVICE device;
    ZeroMemory(&device, sizeof(DISPLAY_DEVICE));
    device.cb = sizeof(DISPLAY_DEVICE);
    
    if (EnumDisplayDevices(NULL, count++, &device, NULL) != 0)
    {
      HDC hDC = CreateDC(device.DeviceName, NULL, NULL, NULL);
      int x = GetDeviceCaps(hDC, HORZRES);
      int y = GetDeviceCaps(hDC, VERTRES);
      m_str.AppendFormat(_T("=== ディスプレイ(%d) ===\r\n"), count);
      m_str.AppendFormat(_T("%dx%d - %s\r\n"), x, y, device.DeviceName);
      m_str.Append(_T("\r\n"));
      DeleteDC(hDC);
    }
  }

  return m_str;
}

== 取得される文字列 ==
=== ディスプレイ(1) ===
1920x1080 - \\.\DISPLAY1

=== ディスプレイ(2) ===
1440x900 - \\.\DISPLAY2

=== ディスプレイ(3) ===
0x0 - \\.\DISPLAY3

=== ディスプレイ(4) ===
0x0 - \\.\DISPLAYV1

=== ディスプレイ(5) ===
0x0 - \\.\DISPLAYV2

=== ディスプレイ(6) ===
0x0 - \\.\DISPLAYV3

引用返信 編集キー/
■72682 / inTopicNo.2)  Re[1]: C++(MFC)でモニタ情報の取得
□投稿者/ 774RR (166回)-(2014/07/04(Fri) 17:44:46)
まず「型番」って何?
たとえばウチのノートPCの「モニター」には当然型番など無いわけだが・・・
デバイスマネージャのモニターの表示は汎用 PnP モニターとある。

> (device.StateFlags & DISPLAY_DEVICE_ACTIVE) != 1
たまたま DISPLAY_DEVICE_ACTIVE が1なので問題なく動くわけだが、限りなくバグなので
今のうちに修正しておくことを強く推奨する。

引用返信 編集キー/
■72683 / inTopicNo.3)  Re[2]: C++(MFC)でモニタ情報の取得
□投稿者/ nobb (45回)-(2014/07/04(Fri) 18:01:45)
No72682 (774RR さん) に返信
ご返信ありがとうございます。

> まず「型番」って何?
> たとえばウチのノートPCの「モニター」には当然型番など無いわけだが・・・
> デバイスマネージャのモニターの表示は汎用 PnP モニターとある。
ノートPCでどのように表示されるかまでは考慮できていませんでした。
一応私が「型番」と言ったものは、Windows7での操作になりますが、
デスクトップを右クリック、画面の解像度 で表示される「ディスプレイ」の項目の内容を指していました。


>>(device.StateFlags & DISPLAY_DEVICE_ACTIVE) != 1
> たまたま DISPLAY_DEVICE_ACTIVE が1なので問題なく動くわけだが、限りなくバグなので
> 今のうちに修正しておくことを強く推奨する。
ご指摘ありがとうございます。
現状、
if((device.StateFlags & DISPLAY_DEVICE_ACTIVE) != 1) //なにか処理
となっている部分を
if(device.StateFlags & DISPLAY_DEVICE_ACTIVE) //なにか処理
という形に修正しようかと考えていますが、合っていますでしょうか?
引用返信 編集キー/
■72684 / inTopicNo.4)  Re[1]: C++(MFC)でモニタ情報の取得
□投稿者/ とっちゃん (241回)-(2014/07/04(Fri) 18:07:23)
とっちゃん さんの Web サイト
No72681 (nobb さん) に返信

接続されているモニタの個数は
GetSystemMetrics(SM_CMONITORS) で調べられます。

自分で試した範囲では名、EnumDisplayDevices() が 0を返してきたところでループを終了すれば
余計なものは表示しませんでしたけど?

形としては、
while( EnumDisplayDevices( nullptr, count++, &device, nullptr ) )
{
/// ここでデバイスの内容表示とか
}
という感じですね。

モニター名(たぶん、ディスプレイの設定のところで出てくる識別名だと思いますが。。。)は
APIレベルでは取れないみたいです。
まず、何よりもデバイスマネージャが表示してくれないので。。。汎用的な手段では取得不可能ですね。

ディスプレイドライバ経由で情報は取れると思いますが、その場合はドライバメーカーさんに問い合わせてみないと
わかりません(APIとして公開しているかどうかのレベルから入るので、情報があってもNDAで公開されることはないでしょう)。

あと、こちらもとれる情報に変わりは大差ありませんが、
EnumDisplayDevices ではなく、EnumDisplayMonitors() APIを使うという方法もあります。

EnumDisplayMonitors( nullptr, nullptr, enumProc, 0 );
という、形で呼び出せば(enumProcは自前定義のコールバックプロシージャ)、接続されているすべてのモニタの情報にアクセスできます。
こちらは、モニタの接続情報をもとにいろいろ。。。というパターンで使えます。

モニター情報を取得して何がしたいのかを書くともう少し望む回答が得られるかもしれません。

が、もうちょっと自力で調べる努力はしたほうがいいと思います。
特に、APIとかの使い方については、リファレンスをまず読むという癖を今のうちにつけておかないと、後々苦労することになりますよ。
今回のようなマルチモニタあたりなら、それなりに調べたことがある人も多いと思いますが
これが、聞いたこともないようなAPIのこととなると、質問されても誰も答えてくれません。

引用返信 編集キー/
■72685 / inTopicNo.5)  Re[2]: C++(MFC)でモニタ情報の取得
□投稿者/ nobb (46回)-(2014/07/04(Fri) 18:36:40)
No72684 (とっちゃん さん) に返信
ご返信ありがとうございます。


> 接続されているモニタの個数は
> GetSystemMetrics(SM_CMONITORS) で調べられます。
これを使用すればループ回数を取得できる、という事になりそうですが、、、

> 自分で試した範囲では名、EnumDisplayDevices() が 0を返してきたところでループを終了すれば
> 余計なものは表示しませんでしたけど?
>
> 形としては、
> while( EnumDisplayDevices( nullptr, count++, &device, nullptr ) )
> {
> /// ここでデバイスの内容表示とか
> }
> という感じですね。
EnumDispDevices関数の成否で判断すればよかったんですね。
ここまで頭がまわりませんでした。

> モニター名(たぶん、ディスプレイの設定のところで出てくる識別名だと思いますが。。。)は
> APIレベルでは取れないみたいです。
> まず、何よりもデバイスマネージャが表示してくれないので。。。汎用的な手段では取得不可能ですね。
No72682 で774RRさんにお教え頂き、その後調べ直していましたら、こちらのページを見つけました。
http://fs-cgi-basic01.freespace.jp/~hsp/ver3/hsp3.cgi?print+201001/10040018.txt
何の言語かは分かりませんが、おおよそ私の希望の事をやっていそうなので参考にしてみました。
== 引用 ==
> EnumDisplayDevices Function
> http://msdn.microsoft.com/en-us/library/dd162609.aspx
>
> がキモで、日本語のサイトと書いてあることが全然違います。
> 第一引数、日本語のサイトには「使いません。NULLを指定します」と堂々と書いてますが、
> 実際はここに "\\.\DISPLAY1" を渡すと、モニタ名が得られるようです
== 引用ここまで ==
とあったので、とりあえずべた書きで"\\.\DISPLAY1"を渡したところ、DeviceStringに「汎用 PnP モニター」が取得されました。
ただし、HDCが正常に取得出来なくなったので、解像度が取得出来なくなってしまいました。
同じページにWMIでの話題もありましたが、そこまで手を出すのに躊躇している所です。


> モニター情報を取得して何がしたいのかを書くともう少し望む回答が得られるかもしれません。
ユーザーのPC環境を表示し、それを送ってもらえるアプリケーションの修正中です。
その際、「解像度も出して!」と言われたので、解像度を出そう。
でも、小さな解像度で使用してたら?じゃあ、モニターの型番でユーザーが使用可能な解像度が判断できるかな?
と思ったのでその部分の実験をしていました。


> が、もうちょっと自力で調べる努力はしたほうがいいと思います。
> 特に、APIとかの使い方については、リファレンスをまず読むという癖を今のうちにつけておかないと、後々苦労することになりますよ。
> 今回のようなマルチモニタあたりなら、それなりに調べたことがある人も多いと思いますが
> これが、聞いたこともないようなAPIのこととなると、質問されても誰も答えてくれません。
ご指摘ありがとうございます。(以前も同じような事を言われました。本当にすみません)
リファレンスも読みつつ、自分なりにやっていてそれでもだめだったのですが、もう少しがんばるべきでした。
次からはもっとがんばってみたいと思います。
引用返信 編集キー/
■72700 / inTopicNo.6)  Re[3]: C++(MFC)でモニタ情報の取得
□投稿者/ とっちゃん (242回)-(2014/07/07(Mon) 18:18:17)
とっちゃん さんの Web サイト
No72685 (nobb さん) に返信
>>モニター情報を取得して何がしたいのかを書くともう少し望む回答が得られるかもしれません。
> ユーザーのPC環境を表示し、それを送ってもらえるアプリケーションの修正中です。
> その際、「解像度も出して!」と言われたので、解像度を出そう。
> でも、小さな解像度で使用してたら?じゃあ、モニターの型番でユーザーが使用可能な解像度が判断できるかな?
> と思ったのでその部分の実験をしていました。
>
モニターの型番がわかっても、現在の解像度は分かりませんよ?

アプリに求められているものは、その環境で表示できる最大解像度の調査ですか?
そうではなく、現在の解像度の取得なのではありませんか?
小さな解像度の環境で利用していたとしても、その解像度を取得しないと意味がないのではありませんか?


表示可能な最大解像度と、現在の画面の解像度は必ず一致するというものではありません。
モニターが小さいから、解像度をピクセル面積を大きくして見やすくしているというご高齢の方もいらっしゃいます。

たとえば複数のモニターが接続されていても、片方しか表示していないということもあります(スクリーンに接続しているかもフラグで取れてますよね)。
実際にうちの開発メンバーがそういう状態にして使っていたことがあります(今はいないと思いますけど...)。

Win7とかになると、拡張画面で、2枚のモニターで同じ画像を出す(スクリーン上の座標は同じ)という機能もあります。
この形の場合、たとえモニターが1000枚つながっていたとしても、全部同じ画面なので、プログラム的にはモニターは1つとみなされます。

アプリに求められているものは、
実際の接続モニター数、モニターごとの現在の解像度、モニターごとのスクリーン表示位置(仮想スクリーン上の表示領域、含まれていないならそれなりに...)
というあたりではないのでしょうか?
拡張画面で複数接続されている状況も場合によっては必要かもしれませんね。
そのあたりもすでに取り出せていると思います。

若しくは、そのアプリが添付されている製品にとって必要になるモニタ情報なのでは?

引用返信 編集キー/
■72711 / inTopicNo.7)  Re[4]: C++(MFC)でモニタ情報の取得
□投稿者/ nobb (48回)-(2014/07/08(Tue) 11:52:45)
No72700 (とっちゃん さん) に返信
ご回答ありがとうございます。
また、私の書き方が悪く上手く伝えきれず申し訳ありません。

> モニターの型番がわかっても、現在の解像度は分かりませんよ?
現在の解像度については、最初のソースで取得しています。
その上で、低解像度で使用している人がいらっしゃるようなので、
補足的に最大解像度も分かれば、何かの役に立つかも?と思ったので、
型番からモニタを特定できれば、最大も(検索すれば)導き出せると踏みました。

対象となるモニターで使用できる解像度を列挙できる方法もあるようですが、
ユーザー側から送ってもらう形態がFAXのみとなるので、出来るだけA4用紙1枚に収まるようにしたいので
列挙する方法は用いません。
列挙のうち、最大のものだけ表示するという手段もあるかと思いますが、そちらに関しては検討段階です。


> アプリに求められているものは、
> 実際の接続モニター数、モニターごとの現在の解像度、モニターごとのスクリーン表示位置(仮想スクリーン上の表示領域、含まれていないならそれなりに...)
仰られるように、モニター数・現在の解像度が必要です。
さらに、モニターの型番が分かれば何かの役に立つのでは?と思いました。
現状そこまでの要求はないので、解像度取得する際に「ちょっと」手を加えれば取り出せたらいいなと思いましたが、
「ちょっと」では無さそうなので、型番取得はやめることにします。
(調べた所、レジストリに保存されているモニターのEDIDから取り出せそうですが・・)

一応、モニター数を取得し、それを基にループで各モニターの解像度を取得するという形で
修正をかけていこうと思います。
解決済み
引用返信 編集キー/
■72716 / inTopicNo.8)  Re[5]: C++(MFC)でモニタ情報の取得
□投稿者/ とっちゃん (243回)-(2014/07/08(Tue) 15:09:30)
とっちゃん さんの Web サイト
No72711 (nobb さん) に返信
> 現在の解像度については、最初のソースで取得しています。

もし、解像度が表示可能領域を意味しているのなら、
EnumDisplayDevices より EnumDisplayMonitors のほうがいいかもしれません。

ちなみに、モニターの表示領域は、画面サイズから、ワークエリア(タスクバーの領域と思ってもいい)を
引いたものになります。

この辺りは、その画面領域をどう扱うかによって大きく変わるので
単に情報として取り出せればいいという場合は必要ないかもしれません。


> その上で、低解像度で使用している人がいらっしゃるようなので、
> 補足的に最大解像度も分かれば、何かの役に立つかも?と思ったので、
> 型番からモニタを特定できれば、最大も(検索すれば)導き出せると踏みました。
>
アプリの性質にもよるので解像度を上げることで回避できるのなら。。。
という提案をしたいのかもしれませんが、なんとなく文面から対象者が不特定多数の
ような気がしました。

もし、市販ソフトのような不特定多数を相手にするソフトなのだとしたら、
おせっかい的な機能はつけないほうがいいと思います。

解像度が低いユーザーさんはそのマシンでより高い解像度で出力できる方法を知らないのではなく
その解像度じゃないと画面の文字が読み取りにくいのであえてそのサイズを設定している
のかもしれません。

もちろん違うかもしれませんが、それは我々開発サイドから推し量るのは絶望的に不可能に近いと
思っていいと思います。

実際、うちの製品ユーザーにはわざと画面サイズを小さくしてモニター上で大きく表示されるように
設定しているユーザーがいますので。。。


> 対象となるモニターで使用できる解像度を列挙できる方法もあるようですが、
> ユーザー側から送ってもらう形態がFAXのみとなるので、出来るだけA4用紙1枚に収まるようにしたいので
> 列挙する方法は用いません。
> 列挙のうち、最大のものだけ表示するという手段もあるかと思いますが、そちらに関しては検討段階です。
>
列挙というのがプログラム的にできるものなのであれば、列挙して最大値だけを出力すればいいのでは?
こちらについては私は調査してないのでどういう手段を指しているのかわかりませんが。


> 一応、モニター数を取得し、それを基にループで各モニターの解像度を取得するという形で
> 修正をかけていこうと思います。

一応。。。接続されているデバイスと、GetSystemMetrics で取れる値は一致するとは限りません。

モニターには、デバイスとして接続されていても表示対象にしないという状態と
複数のモニターで同じものを出力するという状態があります。

この辺りは、EnumDisplayDevices で StateFlags を見たからわかりますよね?


解決済みにしていたので、一応済のままで
解決済み
引用返信 編集キー/
■72720 / inTopicNo.9)  Re[6]: C++(MFC)でモニタ情報の取得
□投稿者/ kumatti (6回)-(2014/07/08(Tue) 18:46:36)
2014/07/08(Tue) 18:47:20 編集(投稿者)

#何か前回のコメントが勝手に削除されてるのが謎ですが。

VBAの例で恐縮ですが Vista以降なら型番取得は出来ますよ。
http://hpcgi1.nifty.com/MADIA/VBBBS/wwwlng.cgi?print+201202/12020009.txt
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -