ウインドウ上でペンによる描画を繰り返すと
プログラムは動き続けているのですが途中から描画ができなくなります
ウインドウハンドルやGetDCで取得したデバイスコンテキストを多用しすぎると
メモリオーバーになることはありますか
よろしくおねがいします
プログラムは
グローバルにウインドハンドルHWND hWndと
デバイスコンテキストHDC hMDC,hDC;と
ペンハンドルHPEN hPen に宣言しており
ウインドハンドルとデバイスコンテキストへの書き込みはそれぞれ一回きりで
そのハンドルと多用しています
解放はデストラクタで行っています
環境はwindows7, visual studio2010, office2010です
リソースの削除・解放・復元などに抜けがあった際に、
同じく画面の描画が出来なくなった経験があります。
念のためGetDC~ReleaseDCやSelectObjectの変更・復元が、
対になっているか確認してみてください。
HDC hdc = GetDC( hWnd );// HDCを取得 (#1)
HPEN hOldPen = (HPEN)SelectObject( hdc, hPen );// Penを変更 (#2)
// GDIの描画
SelectObject( hdc, hOldPen );// 変更したPenを戻す (#2)
ReleaseDC( hWnd, hdc );// HDCを解放 (#1)
それと、事前にCreatePenなどで生成されたPenオブジェクトが
きちんと対になってDeleteObjectされているかも、
再度確認してみてください。
簡単にGDIリソースの有無を判定する方法を紹介しますね。
タスクマネージャのプロセスタブを開いて、GDIオブジェクトのカラムを表示させるよ
うにして、GDIリソースを食いつぶしていないか確認してみてください。
確認質問
1:「多用」とはどのくらいか?
2:
>ウインドウハンドルやGetDCで取得したデバイスコンテキストを多用しすぎると
と
>ウインドハンドルとデバイスコンテキストへの書き込みはそれぞれ一回きりで
>そのハンドルと多用しています
この2つの文の意味するところは・・・
「GetDCやCreatePenなど、GDIオブジェクトの生成などを多用する」
それとも
「GetDCは一回だが、一度とったものに対し何度(描画する必要のあるとき)も、
利用している」
どっち?
おまけ:Aero切ってみたらどうなる?
他の回答者の方たちのおっしゃる通りなのですが、
一部確認したいことがあります。
1.「一回きりの書き込み」(描画)ですが、WM_PAINTでやってますか。
2.そうだとするとGetDC()は何のために使っているのでしょう。
一般にWM_PAINTで描画する場合は、BeginPaint()/EndPaint()ですよね。
3.「hMDC」とはメモリーデバイスコンテキストでしょうか。
それの、生成と破棄はどのタイミングでやってますでしょうか。
ちなみにGetDC()はこれのためですかね。
描画ができなくなる原因は色々と考えられます。
GDIリソースの不足(リーク)もその一つですが、他の原因も疑ってみましょう。
虚心坦懐で見直してみてはどうでしょう。
kinokoさん
ありがとうございます
ペンハンドルと、デバイスコンテキストは以下のように解放しています
hDC = GetDC( hWnd );
hPen=CreatePen(PS_SOLID, penbold ,pen.pen_color);
(HPEN)SelectObject(hDC, hPen);
//線を描画
MoveToEx(hDC, MyPoint.OldPoint.x, MyPoint.OldPoint.y, NULL);
LineTo(hDC, MyPoint.NowPoint.x, MyPoint.NowPoint.y);
ReleaseDC( hWnd, hDC );
DeleteObject( hPen );
具体的には私のプログラムは
プレゼンテーション用にパワーポイントを読み込みその上に透明ウインドを表示し、
下線引きを行うものです。
ペンは常に同じ色、太さで描画を行うのですが。
描画を行う度にCreatePenとDeleteObjectを繰り返すひつようはありますか?
描画はWM_MOUSEMOVE内で行っています
ARさん
ありがとうございます
確認してみたところ
メモリの食いつぶしは見られませんでした。
今後もタスクマネージャによる確認方法を参考にさせていただきます
ryoさん
ありがとうがざいます
GetDCは一回生成時に行っており、一度とったものに対し何度(描画する必要のあるとき)も、利用しています
私のプログラムでは
生成した透明ウインドウに下線を引くモードと消しゴム画像上書きして線を消すモード、矢印のアイコンを表示するモードが
あり、それぞれの描画時にデバイスコンテキストを利用しています
>hDC = GetDC( hWnd );
>hPen=CreatePen(PS_SOLID, penbold ,pen.pen_color);
>(HPEN)SelectObject(hDC, hPen);
>//線を描画
>MoveToEx(hDC, MyPoint.OldPoint.x, MyPoint.OldPoint.y, NULL);
>LineTo(hDC, MyPoint.NowPoint.x, MyPoint.NowPoint.y);
>ReleaseDC( hWnd, hDC );
>DeleteObject( hPen );
コードがこの通りだとすると、DeleteObject( hPen );の行は効果がありません。
多分、戻り値に0(失敗)が戻っていることでしょう。
正しく動作するようにするには、
HPEN hOldPen = SelectObject(hDC, hPen); //★ここを変更
//線を描画
MoveToEx(hDC, MyPoint.OldPoint.x, MyPoint.OldPoint.y, NULL);
LineTo(hDC, MyPoint.NowPoint.x, MyPoint.NowPoint.y);
SelectObject(hDC, hOldPen); //★ここを挿入
ReleaseDC( hWnd, hDC );
DeleteObject( hPen );
の様に選択を外さなければGDIオブジェクトを削除することはできません。
仲澤@失業者さんありがとうございます
無駄にGetDC()によりウインドハンドルを取得していたので
WM_PAINTで行うようにしました。
WM_PAINTは透明ウインドウ描画時のみ使用し、
ペンによる描画はWM_MOUSEMOVEメッセージにより行っています。
hMDCは使用していませんでした。
メモリ不足以外の他の原因も考えてみます
ん、すれ違ったかな(vv;)。
自分の直前の発言の、ペンの「選択外し」をちゃんとやればOKのような気がします。
再び仲澤@失業者さんありがとうございます
指示していただいたとおり
コードを挿入しました。
しかし
ウインドウへの描画ができまくなります。
他の原因も考えてみます
メモリ不足以外にもリソースの不足と言うのはありえますよ。
GDIリソースのハンドルを開放しそこなった状態で
次のハンドルを取得に行ってしまうと
ハンドル数の上限に達してしまう事になってしまいます。
基本的には、Penの生成と削除、Penを選択すると未選択にするは対になります。
Pen生成(ハンドルの取得)
Penを選択する
諸々描画処理
Penを未選択にする
Pen削除(ハンドルの開放)
この辺はGDIで描画する時の基本なので確認されたほうが良いと思います。
あと、WM_MOUSEMOVEで描画してしまうと他のウインドウが重なったりした時に
消えてしまうと思うのですが、大丈夫ですか?
WM_PAINTにその時の画面の状態を再現する為のコードが必要だと思いますけれど。
すいません、前の発言は蛇足だったかも。
PATIOありがとうございます
描画ウインドウは常に最前面に表示するようにしています
他のwindows vistaのパソコンでは問題なく動きました