CreateCompatibleDCやCreateCompatibleBitmapについて – プログラミング – Home

通知
すべてクリア

[解決済] CreateCompatibleDCやCreateCompatibleBitmapについて

固定ページ 1 / 2

亀山
 亀山
(@亀山)
ゲスト
結合: 18年前
投稿: 133
Topic starter  

あるウィンドウの描画用にメモリビットマップを用意しようとしています。
その際、CreateCompatibleDCやCreateCompatibleBitmapを使って
メモリDCやメモリビットマップを作ることになりますが、
これらの引数にはコピー元のDCを渡しますよね。

このコピー元のDCって、CClientDCなどを使って
描画先ウィンドウのDCを持ってこないといけないのでしょうか?
それとも、こういうケースでは常にNULLを渡して、
スクリーン全体を指定してしまってもよいものなのでしょうか?
(メモリDCやメモリビットマップを作成する際、
ウィンドウのDCを指定するのとNULLを指定するので、
なにか結果が変わってくるものなのでしょうか?)

また、もう一つ自信が持てないものがあるのですが、
CWnd::GetDCExなどの説明には
「共通デバイスコンテキストは最大5つしかない」と書かれてあり、
使い終わったらすぐに解放しなくてはいけないと理解しています。
CreateCompatibleDCなどで作成したメモリDCは、
この問題とは無関係ということでよいのでしょうか?
(何個も作ったり終了までずっと持ってたりしてもよいのでしょうか?)


引用未解決
トピックタグ
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

ウインドウに対して画像転送したり、ウインドウから画像転送する場合には
基本的にcompatibleなDCとBitmapを使うべきという認識なので
対象ウインドウのDCを使った方が良いのではと思います。
多分、コンパチブルな方が転送の負担が軽くなるのではと言うのが
主な理由ですが、実際に確認したわけではないので確信はありません。
この辺はもっと深く調べてみないとはっきりとは言えないですね。

CreateCompatibleDCで作成したDCは、システムリソースが許す限り作成できたと思います。
アプリケーション開始時に作成して終了するまで保持していても問題ないはずです。
そもそも画面に直接結びつくDCではなくてメモリDCですし。

毎回、作成して開放を忘れるよりも安全だし、効率も良いではないかと思いますし。
一時的にしか使わないようなものならその度に作って開放でも良いかもしれません。
画面描画に使うのであれば、頻繁に使うものなので作っておいて使いまわした方が
良いと思います。
ただし、無限に作成できるわけではありませんから無駄に作成するべきではありません。

CWnd::GetDCExはメモリDCを返すわけではなくてウインドウに直接結びついているDCを
取得する物なのでメモリDCとは違います。どういうものなのかは、CWnd::GetDCExの
説明に書いてある通りなのでそっちで確認してください。


返信引用
亀山
 亀山
(@亀山)
ゲスト
結合: 18年前
投稿: 133
Topic starter  

解説ありがとうございます。

> ウインドウに対して画像転送したり、ウインドウから画像転送する場合には
> 基本的にcompatibleなDCとBitmapを使うべきという認識なので
> 対象ウインドウのDCを使った方が良いのではと思います。

なるほど、やはりそういうものなのですか…。
デスクトップのDCからCreateCompatibleDCやCreateCompatibleBitmapしたものは、
任意のウィンドウとはCompatibleにはならないのでしょうか…。

だとすると、実際にウィンドウを作成するまでは
そのウィンドウに画像転送するためのメモリビットマップは
用意できないということになりますし、
画像を別のウィンドウにも転送したいいうことになれば、
そのウィンドウ用のメモリビットマップを別途用意して
もう一度描き直さなければいけないのですよね?

> CreateCompatibleDCで作成したDCは、
> システムリソースが許す限り作成できたと思います。

「メモリDC」と「共通デバイスコンテキスト」の違いということですよね。
メモリビットマップの内容を描画しなおすたびに
CreateCompatibleDCをやらなければいけないのかと疑問に思っていたので、
その必要が無いということで安心しました。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> デスクトップのDCからCreateCompatibleDCやCreateCompatibleBitmapしたものは、
> 任意のウィンドウとはCompatibleにはならないのでしょうか…。

なるんじゃないですかね。
同じ画面に表示している以上、色数とかはどんなウィンドウでも同じですから、ディスプ
レイのデバイスコンテキストに限らず、赤の他人のウィンドウから取ってきたデバイスコ
ンテキストでもきっと互換性はあります。

互換性とは何なのか、MSDN ではすぐには見つかりませんでしたが、

> この 互換性 とは、以下の条件をすべて満たすものを言いいます。
> ・ビットマップ中のビットの 1 ピクセルあたりのビット数が同じ
> ・ビットプレーンが同じ
> ・カラー値が同じ

だそうです(from http://www.onicos.com/staff/iz/amuse/wapi/wapi.html)

> 「共通デバイスコンテキストは最大5つしかない」と書かれてあり、
> 使い終わったらすぐに解放しなくてはいけないと理解しています。

GetDCEx の英語版のドキュメントには

> Windows 95/98/Me: There are only 5 common DCs available per thread,
> thus failure to release a DC can prevent other applications from
> accessing one.

とあります。
「Win9x 系では、1つのスレッドにつき5つの DC しか持てない」…まではいいんですケ
ド、その先に「従って、DC をリリースしないと、他のアプリケーションが(DC に)アク
セスするのを妨げる」というようなことが書いてあるんだと思います。…Excite 様がそ
うおっしゃってました。
6つ確保しようとすると失敗するのか、それとも他のスレッドが4つまでしか確保できなく
なるのか…まぁ、9x 系限定の制限みたいなので、あまり気にする必要もないかも?

ちなみに「共有DC」とは、「ディスプレイDCのうち、CS_OWNDC を指定していないウィン
ドウクラスのウィンドウから取得したDC」らしいです。CS_OWNDC を指定して登録したウ
ィンドウのDCは「プライベートDC」と呼ぶみたい。
CreateCompatibleDC で作るのは「メモリDC」であって「ディスプレイDC」ではないの
で、数制限はありません。空きメモリ量だけに縛られます。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

>> デスクトップのDCからCreateCompatibleDCやCreateCompatibleBitmapしたものは、
>> 任意のウィンドウとはCompatibleにはならないのでしょうか…。
>
>なるんじゃないですかね。
>同じ画面に表示している以上、色数とかはどんなウィンドウでも同じですから、ディスプ
>レイのデバイスコンテキストに限らず、赤の他人のウィンドウから取ってきたデバイスコ
>ンテキストでもきっと互換性はあります。
>
>互換性とは何なのか、MSDN ではすぐには見つかりませんでしたが、
>
>> この 互換性 とは、以下の条件をすべて満たすものを言いいます。
>> ・ビットマップ中のビットの 1 ピクセルあたりのビット数が同じ
>> ・ビットプレーンが同じ
>> ・カラー値が同じ
>
>だそうです(from http://www.onicos.com/staff/iz/amuse/wapi/wapi.html)

直感的には多分同じなんではないかなぁとは思ったんですが、
同じだと言う確信が持てなかったので安全側に振るという意味合いもあって
対象ウインドウを使ってますね。
ウインドウが出来てからしかDCやビットマップが作成できないというのは
確かにあるんですが、私が通常行っている処理では対象のウインドウが無い
状態でDCやビットマップを予め作成しておくというケースはないので
困ったケースと言うのはないですね。


返信引用
亀山
 亀山
(@亀山)
ゲスト
結合: 18年前
投稿: 133
Topic starter  

> 同じ画面に表示している以上、色数とかはどんなウィンドウでも同じですから、
> ディスプレイのデバイスコンテキストに限らず、
> 赤の他人のウィンドウから取ってきたデバイスコンテキストでも
> きっと互換性はあります。

解説ありがとうございます。

ということは、基本的にはどんなウィンドウでも
描画用メモリビットマップを作成する際には、常に
CClientDC dc(NULL);
などを使って取ってしまっても大丈夫で、
さらにそれらはどんなウィンドウ用のメモリビットマップとしても
使い回せるということなのですよね。

たとえば、CButton::SetBitmapを使って複数のボタンに表示させる
ビットマップ配列を動的に事前に作成する際などに、
いちいち各ボタンごとにCompatibleなDCを
用意してやらなければいけないのかなと疑問に思っていました。

PATIOさんも言われていますが、Windowsが出て何年も経っているのに、
「メモリビットマップと、それを選択するメモリDCを作成するために渡すDCは、
描画先ウィンドウのDCじゃなくてもOKかどうか」
という疑問に対しての公式情報が見つからないですね…。


返信引用
kure
 kure
(@kure)
ゲスト
結合: 19年前
投稿: 48
 

> ということは、基本的にはどんなウィンドウでも
> 描画用メモリビットマップを作成する際には、常に
> CClientDC dc(NULL);
> などを使って取ってしまっても大丈夫で、

いやこれはちょっとどうだろう。

この辺の挙動は実はWindows98や2000とXPとで違うらしく、
MSDNによれば98/2000だとNULLを指定した場合は
プライマリモニタのデバイスコンテキストを返すとあります。
かたやXPや2003では画面全体を現すデバイスコンテキストを返すとあります。

これが事実であれば、98/2000環境でGDIでの描画を行う場合に、
・セカンダリモニタが存在する
・セカンダリモニタにWindowが存在する
・プライマリモニタとセカンダリモニタの色数の設定などが異なる
を満たすケースで、BitBltなどのパフォーマンスが
落ちるようなことが起きるはずです。

# XP/2003の画面全体のデバイスコンテキストって?
# プライマリモニタが32bitでセカンダリモニタが16bitの場合どうなるんでしょうね?
# どっかにドキュメント転がってないかなぁ。。。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> MSDNによれば98/2000だとNULLを指定した場合は
> プライマリモニタのデバイスコンテキストを返すとあります。
> かたやXPや2003では画面全体を現すデバイスコンテキストを返すとあります。

情報の出所はどちら?
日本語版 MSDN だとしたら、おそらくは誤訳かと。

原典
http://msdn2.microsoft.com/en-us/library/ms533241.aspx
では、2003/Vista に関する記述こそありませんが、98/Me/2000/XP のすべてについて同
じことが書かれていますし、「プライマリモニタ」などという言葉は出てきません。
おそらく、すべての環境で、すべてのモニタの表示域を結合した仮想スクリーン全体の
DC が取れるのではないかと。

さて、それはそれで問題。
俺の

> 同じ画面に表示している以上、色数とかはどんなウィンドウでも同じですから

発言は撤回します。申し訳ない。

MSDN には

> Each monitor can have its own color depth. The system automatically adjusts
> colors as windows move across monitors with different color depths.
> In general, this produces good results. However, this is not always optimal.

とあります( http://msdn2.microsoft.com/en-us/library/ms534811.aspx)。
訳せば
「各々のモニタは異なる色深度を持つことができます。システムは、ウィンドウが異な
る色深度を持つモニタ間を移動するとき、自動的に色の調整を行います。これは大抵の
場合によい結果をもたらしますが、常に最適とは限りません」
てトコですか。

> BitBltなどのパフォーマンスが落ちるようなことが起きるはずです。

はい。どうやらありうるようです。
ではどうすればよいかというと、やはり、ウィンドウがどのモニタにあるかを判別し
て、適切な描画を行う必要がありそうです。
よって、

> 実際にウィンドウを作成するまでは
> そのウィンドウに画像転送するためのメモリビットマップは
> 用意できないということになりますし、
> 画像を別のウィンドウにも転送したいいうことになれば、
> そのウィンドウ用のメモリビットマップを別途用意して
> もう一度描き直さなければいけないのですよね?

Yes。
そうしなくても失敗することはありませんが、パフォーマンスとか質が若干落ちるでし
ょう。
ただし、これは予想以上に厄介かと。
たとえば、24bit カラーのモニタの画像を 16bit カラーのモニタに転送しなければいけ
ない場合、減色処理が必要になるでしょう。

ついでに、GetDeviceCaps は

> On a multiple monitor system, if hdc is the desktop, then GetDeviceCaps
> returns the capabilities of the primary monitor.

だそうです( http://msdn2.microsoft.com/en-gb/library/ms533266.aspx)。
CreateCompatibleDC に仮想スクリーンの DC 渡したら、どんなんが出来てくるんですか
ネ?


返信引用
kure
 kure
(@kure)
ゲスト
結合: 19年前
投稿: 48
 

> 情報の出所はどちら?
> 日本語版 MSDN だとしたら、おそらくは誤訳かと。

ご指摘どおり日本語版MSDNですね。
英語版を確認したところ確かにXPもGetDCの結果は、
特定のディスプレイモニタのデバイスコンテキストを返す
となっていますね。

訂正ありがとうございました。

# 特定のディスプレイが実際どれなのかは試してみないとわからなそうですね。。。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> 英語版を確認したところ確かにXPもGetDCの結果は、
> 特定のディスプレイモニタのデバイスコンテキストを返す
> となっていますね。

え? 「特定のモニタ」って何です?
「特定のモニタの DC が欲しければ EnumDisplayMonitors しなさい」とは書いてあるけ
ど、「GetDC に NULL 渡したら特定のモニタの DC を返す」とは書いてませんよね。


返信引用
kure
 kure
(@kure)
ゲスト
結合: 19年前
投稿: 48
 

specific display monitorしか見てなかったorz
シャノンさんの指摘どおりですね。

ついでにNULL渡したときはentire screenだそうで。
スクリーン全体のDCってどうなってるんだろう?


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> スクリーン全体のDCってどうなってるんだろう?

こう。
http://msdn2.microsoft.com/en-US/library/ms534613.aspx


返信引用
kure
 kure
(@kure)
ゲスト
結合: 19年前
投稿: 48
 

これってDCというより仮想画面のマッピングの話かと。
で、ちょっと探してみたものの、
スクリーン全体のDCがどうなってるよという話は見つからず。

スクリーン全体のDCに描画した場合については
(記事中では複数モニタにまたがるWindowの描画となってるけど)

http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/gdi/monitor_7ywj.asp

にシステムが勝手にやるよーと書いてあるくらいと。
しかも、モニタ毎にきちんとやりたければEnumDisplayMonitorsを使って
モニタ毎のDCへの描画処理をしろということらしい。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> これってDCというより仮想画面のマッピングの話かと。

うーん…
「スクリーン全体の DC の『何が』どうなってるよ」というのが特定されてないから、
あながち間違いでもない気がするけれど。

> スクリーン全体のDCがどうなってるよという話は見つからず。

スクリーン全体の色の話だったら、GetDeviceCaps じゃうまくいかないし、やっぱり
DC 全体としての色深度っていう情報は無いんじゃないかと思われ。あっても無意味だ
し。
あとは、マルチモニタ環境がある方に、複数モニタにまたがる DC から
CreateCompatibleDC した時に何ができるか試していただきたい、ってところかな。

> スクリーン全体のDCに描画した場合については ...

揚げ足を取るようで申し訳ないけれど、そんなことを 13:31:34 に書いたつもり。


返信引用
亀山
 亀山
(@亀山)
ゲスト
結合: 18年前
投稿: 133
Topic starter  

解説ありがとうございます。
かなり難しい問題なのですね…。

CreateCompatibleDCやCreateCompatibleBitmapに渡すDCが
特定ウィンドウのものかCClientDC(NULL)のものかに関係無く、
メモリDCやメモリビットマップを最初に一度作成しておいて使い回す
という方法はやってはいけないことになりますし、
描画のたびに毎回Createし直さないといけないということになるのですよね?

ということは、前回書かせいていただいたCButton::SetBitmapのケースだと、
画面のプロパティが変わったりモニタ位置が変わったりするたびに
ビットマップも作り直してセットするということなのでしょうか?


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました