• ベストアンサー

Rectangleで、リソースが解放されない

只今 Borland C コンパイラ 5.5.1 においてプログラムを書いているのですが、(C言語) 仕様なのかどうなのか、ある処理でウィンドウのサイズを ぐりぐり動かしつづけるとリソースが減っていって フリーズしていしまいます。使用しているWindowsは98SEです。 そのプログラムは、ウィンドウプロシージャにおいて、 case WM_PAINT:  hdc = BeginPaint(hWnd,&ps);    hPen = CreatePen(PS_SOLID, 0, RGB(255,0,0));  hOldPen = (HPEN)SelectObject(hdc, hPen);  hBrush = CreateSolidBrush(RGB(0,255,0));  Rectangle(hdc, 10,10,100,100);  DeleteObject(hPen);  SelectObject(hdc, hOldPen);  DeleteObject(hBrush);  DeleteObject(hOldPen);    EndPaint(hWnd,&ps);  break; という風に、Rectangle関数で画面に四角形を描画しているのですが、どうも上記の処理を何度も行うことにより リソースが解放されずに大量に消費されてしまいます。 C言語においてはまだ少しわかるほどのレベルで、 殆どの関数の意味を今だに理解していなくプログラムの 文法になにかしらの間違いがあるかもしれませんが、 ご指摘いただければ幸いです。

質問者が選んだベストアンサー

  • ベストアンサー
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.1

原因が分かりました、というわけではないのですが、気になるところを2点。 (1) hPenがまだselectされている状態でDeleteObjectしています。hPenのselectを解除してから(hOldPenをselectしてから)DeleteObjectしましょう。もしかしたらselectされている状態でDeleteObjectできず、そのせいでリソースが消費されているのかもしれません。 (2) hBrushがどこにも使われていません。SelectObjectし忘れでしょうか。(使用しないことによる問題はありません。)

umimon
質問者

お礼

すいません、 すぐに回答いただいてそのあとすぐにお礼を言おうとしたのですが、どうやらエラーが起きたようで ちゃんと投稿されなかったようです。 hPenがselectされている状態ではDeleteOBjectにて削除することはできなかったんですね。 言われたとおりhPenをhOldPenに変えてから削除したところ リソースは消費されることはなくなりました。 それと、hBrushは確かにいらなかったですね^^; どうもありがとう御座いました。

その他の回答 (4)

  • furyfox
  • ベストアンサー率56% (58/103)
回答No.5

case WM_CREATE:  hPen = CreatePen(PS_SOLID, 0, RGB(255,0,0));  hBrush = CreateSolidBrush(RGB(0,255,0));  break; case WM_PAINT:  hdc = BeginPaint(hWnd,&ps);  SelectObject(hdc, hPen);  Rectangle(hdc, 10,10,100,100);  EndPaint(hWnd,&ps);  break; case WM_DESTROY:  DeleteObject(hBrush);  DeleteObject(hPen);  break; といった感じでどうですか?

umimon
質問者

お礼

この場合は hPenとhBrushの値が初期化されないように、 hPen と hBrush を staticで定義しておかないと ダメみたいですが、その手もありですね。 最初から最後までずっとhPenを登録してる方法なので、 少しだけでも動作は速くなると思うので、 やってみます。^^ 回答有難う御座いました。

  • buihyaku
  • ベストアンサー率29% (97/326)
回答No.4

1の方のいうとおりDCに選択された状態でDeleteObjectするとリソースリークします。 それと、描画系の処理をするときはSaveDC, RestoreDCを使用されることをオススメします。 現在の設定を保存して、あとで復元することができますので、いちいち以前設定されていたPenやBrushなどを覚えて復元する必要がなくなりミスが減ります。 上記コードですとこんな感じで使用します int nSaveDC; case WM_PAINT:  hdc = BeginPaint(hWnd,&ps);   nSaveDC = SaveDC(hdc); /* <-- 設定を保存 */  hPen = CreatePen(PS_SOLID, 0, RGB(255,0,0));  SelectObject(hdc, hPen);  hBrush = CreateSolidBrush(RGB(0,255,0));  Rectangle(hdc, 10,10,100,100); RestoreDC( hdc, nSaveDC ); /* 復元 */ /* DCに選択されていない状態で削除*/  DeleteObject(hPen);  DeleteObject(hBrush);    EndPaint(hWnd,&ps);  break;

umimon
質問者

お礼

以前から参考書などにもsaveDCとRestoreDCとい関数 の説明が載っていましたが全くどう働くのかわからず スルーしていたことがありましたが、こういうことだったんですね。 しかもいちいちもとのhdcの状態を保持し、 それを一括してもとにもどしてくれる関数があったとは、ほんとに脱帽物です。 回答ありがとうございました。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.3

DeleteObject(hOldPen); ←これが余計な処理では? これをコメントアウトして試してください。 システムのリソースをDeleteObjectしている気がします。 #2さんへ 「Borland C コンパイラ 5.5.1」 でVCL は使えないんじゃ?

umimon
質問者

お礼

>>DeleteObject(hOldPen); ←これが余計な処理では? 確かに余計でした(汗) SelectObjectによるハンドルとは明記されていたのですが、 これもリソースを消費するのでは?というような 妙な考えを持ってしまいつけていたようでした。 外して試したところリソースは消費されていなかったので、 外して処理致しました。 本当に取っていいのだろうかと心配してたので、 大丈夫だなんだとわかり有難うござした^^

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

質問とは直接関係ありませんが、お許し下さい。 このプログラムは演習用でしょうか? デバイスコンテキスト関連のAPI関数を呼ばなくても void __fastcall TForm1::FormPaint(TObject *Sender) {   Form1->Canvas->Pen->Style = psSolid;   Form1->Canvas->Pen->Color = (TColor)RGB(255,0,0);   Form1->Canvas->Brush->Style = bsSolid;   Form1->Canvas->Brush->Color = (TColor)RGB(0,255,0);   Form1->Canvas->Rectangle(10,10,100,100); } で済んでしまうのですが…。 (使う場所によっては、Form1->CanvasのPenとBrushを保存しておいて元に戻す必要がありますが) このようにしない理由があるのでしょうか?

umimon
質問者

お礼

すいません、C言語によるプログラムから始めたばかりで、 まだまだ分からない所も山ほどあるので、そういった方法は全く無知でした。 APIから少しでもソフトを作れるようになって、いろいろと スキル向上を目指したいと思います。 一応今開発しているツールの一部で、HSPのような プログラムの描き方にはなるんですが、背景用として Rectangleをこの場合は利用しています。 画面のちらつきを防ぐため、WM_ERASEBKGNDを処理しているので、その背景の変わりに利用してます。 回答ありがとうございました。^

関連するQ&A

  • 重なり z-index

    HWND hrs;//プロト hrs = CreateWindow( ... というのがあって  wsprintf(mojibuf,"色付けが実行された");  SetWindowText(hrs,cbuf);  hDC = BeginPaint(hWnd, &ps);  hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));//枠色  SelectObject(hDC, hPen);  hBrush = CreateSolidBrush(RGB(0, 255, 0));//中色  SelectObject(hDC, hBrush);  Rectangle(hDC, 10, 90, 150, 100);  DeleteObject(hBrush);  EndPaint(hWnd, &ps); これで、hWnd に文字と四角を表示しました。 表示位置を重なるようにしたら、ソースの後に書いた方の 四角が文字に隠れてしまいました。 四角を文字の上になるようにして、重なった部分の文字は 四角で消されるようにするにはどうしたらいいんですか?

  • SelectObjectについて

    SelectObject関数で例えば、 hbrush=SelectObject(hdc,CreatesolidBrush(RGB(0,0,0,)); Rectangle(hdc,0,0,100,100); SelectObject(hdc,hbrush); でやる場合、なぜ、SelectObject(hdc,hbrush);で前の色に戻るはずなのに 戻らないのでしょうか?この意味はあるのでしょうか? 環境はVC++2005です。

  • C言語・Windows RECTが渡せない

    C言語のWindowsプログラムで、左クリック後に四角形の描画をしたいのですがうまくいきません。 WM_LBUTTONDOWNイベントで定義したRECT構造体を、別の関数に渡しRectangleで描画したいのですが、その関数内でRECTの値を調べるととんでもない値になっています。 何度やってもどうして値がおかしくなるのかわかりません。 WM_LBUTTONDOWNもWM_PAINTも正常に反応していると思います。 どうか知恵をお貸しくださいm(_ _)m 以下ソースコードのメッセージ処理部分です。 ウィンドウ生成のひな型はサイトの物を丸写しし、正常に動作することを確認しています。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rcPos; switch (msg){ case WM_LBUTTONDOWN: rcPos.top =0; rcPos.left =0; rcPos.bottom =100; rcPos.right =100; InvalidateRect(hWnd, &rcPos, FALSE); break; //ウィンドウの描画 case WM_PAINT: hdc = BeginPaint(hWnd, &ps); DrawGr(hWnd, hdc, &rcPos); EndPaint(hWnd, &ps); break; //ウィンドウの削除 case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } return (0L); } //描画 int DrawGr(HWND hWnd, HDC hdc, RECT *rcPos) { int i; HBRUSH hBrush, hOldBrush; char *str_org = "rc.top=%d rc.left=%d rc.bottom=%d rc.right=%d"; char strx[256]; //四角形 hBrush = CreateSolidBrush(RGB(100, 100, 255)); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); //デバッグ用 wsprintf((LPSTR)strx, (LPCSTR)str_org, rcPos->top, rcPos->left, rcPos->bottom, rcPos->right); MessageBox(hWnd, (LPCSTR)strx, (LPCSTR)"終了確認", MB_OKCANCEL | MB_ICONQUESTION); Rectangle(hdc, rcPos->left, rcPos->top, rcPos->right, rcPos->bottom); SelectObject(hdc, hOldBrush); DeleteObject(hBrush); return 0; }

  • Windows API ペンを作るタイミング

    ゲームのプログラミングをしています。 テキストのサンプルプログラムではペンやブラシをWM_CREATEの中で hPen[1] = CreatePen(PS_SOLID, 2, RGB(50,70,0));    :    : のような感じで生成して WM_PAINT内でSelectObject(hdc, hPen[i]); として使っているのですが 自分のプログラムはPaintという関数を使っています。 その場合Paint(~)にそれらの配列を渡す形で良いのでしょうか? 一応今はそれで動いてます。 ただ描画の処理は1つの関数にまとめると書いてあったので Paint内で生成&削除をした方がよいのかとも思いまして・・・ どっちが一般的なのか、どういう場合はどうすればいいのかっていうのが 経験がなくて全然わからないので教えて欲しいです。 一応落ち物ゲームやシューティングゲームを想定してます。

  • VC++ ドラッグしながらの図の描画に関して

    描画に関して質問があります。 アクセサリのペイントツールのようにマウスドラッグしながら長方形を描画させたいのですが、 ドラッグの際に既に描画してあった長方形を消去する方法が理解できません。 具体的には以下のような方法です。 // ドラッグ中の描画処理 SetROP2( hDC, R2_NOT ); // 前景モードを変更 hPen = CreatePen( PS_DOT, 1, RGB(0, 55, 0) ); // 黒い点線のペンを作成 hBrush = (HBRUSH)GetStockObject( NULL_BRUSH ); // 空のブラシを取得 SelectObject( hDC, hPen ); // 作成したペンを使用するように設定 SelectObject( hDC, hBrush ); // 取得したブラシを使用するように設定 Rectangle( hDC, start.x, start.y, old_end.x, old_end.y ); // 四角形を描画 SetROP2とブラシは共に塗りつぶしを指定するものですが、これらを併用することによって何故既存の図形を消去していくことができるのかわかりません。 疑問になったのでブラシに関する記述を消去し実行してみると長方形内部の色が反転されましたが、これは理解できます。 しかし、これにブラシに関する記述を復元させることにより、なぜ内部が真っ白になるのかがわかりません。 また、塗りつぶしはSetROP2とブラシのどちらが先に行うのでしょうか?お手数ですが回答よろしくお願いします。

  • 【WinAPI】 四角形の色を選択して描画

    環境:VisualStudio2005、WinXP 目的:閉じた図形の内部の色を指定の色で塗りつぶしたい 現在 // 四角形を描画(Polygonバージョン) int x1 = 0, y1 = 0, x2 = 100, y2 = 100; POINT p[ 4 ]; p[ 0 ].x = x1, p[ 0 ].y = y1; p[ 1 ].x = x2, p[ 1 ].y = y1; p[ 2 ].x = x2, p[ 2 ].y = y2; p[ 3 ].x = x1, p[ 3 ].y = y2; Polygon( hdc, p, 4 ); や // 四角形を描画(Rectangleバージョン) Rectangle( x1, y1, x2, y2 ); などで四角形を描画するプログラムを作っています。 そしてこれに色を指定したいのですが、枠の部分に関しては HPEN hPen = CreatePen( PS_SOLID, 1/*線の厚さ*/, RGB(255,0,0) ); SelectObject( hdc , hPen ); // この後に四角形を描画 を指定することで色が変わりました。 しかし四角形の内側の部分の色に関しての色の指定方法が分かりません。 SelectObject(hdc , GetStockObject( GRAY_BRUSH ) ); でGRAY_BRUSH、BLACK_BLUSHなど数種類の指定ができるというのを調べましたが、 これだと好きな色を指定できません。 閉じた図形の内部の色を好きな色で塗りつぶす方法は無いのでしょうか・・?

  • なぜCreateHatchBushの設定が途中で喪失するのか

    いつもお世話になります。 縦縞の四角形を表示するプログラムですが、ある一定の四角形を描画すると四角形の中の縦縞がなくなり、白色になります。 原因が分かりません。アドバイスをお願い致します。 (四角形をマウスドラッグ中に小さくすると黒い線がたくさんでてきますが、これはアプリケーションの仕様です) プロシージャソースは以下の通り。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; static POINT start, end; static bool push; switch(msg) { case WM_CREATE: push = false; break; case WM_LBUTTONDOWN: start.x = LOWORD(lParam); start.y = HIWORD(lParam); push = true; break; case WM_MOUSEMOVE: if(push){ end.x = LOWORD(lParam); end.y = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); } break; case WM_LBUTTONUP: end.x = LOWORD(lParam); end.y = HIWORD(lParam); push = false; InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: HBRUSH hBrush; hDC = BeginPaint(hWnd, &ps); hBrush = CreateHatchBrush(HS_VERTICAL, RGB(255, 0, 0)); SelectObject(hDC, hBrush); Rectangle(hDC, start.x, start.y, end.x, end.y); DeleteObject(hBrush); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } よろしくお願い致します。

  • win32プログラム

    以下のコードで 1、CreateSolidBrush()で色設定しつつ 2、SelectObject()で、前のブラシのハンドルを受け取り 3、DeleteObject()で前の色を削除。     これらを一つの文で行っているんですか?  これらの記述は、一般的な方法ですか?  ブラシ(CreateSolidBrush()など)特に削除しなくても、  プログラム 出来る気がしますが、  削除しないと何か問題はありますか?  教えてください。 SelectObject ( hdc,CreateSolidBrush( RGB( 255,0,255))); Polygon(hdc,a,6); DeleteObject( SelectObject( hdc, CreateSolidBrush(RGB(55,77,33)))); PolyPolygon(hdc,b,d,2); DeleteObject( SelectObject(hdc, GetStockObject(WHITE_BRUSH)));

  • SelectObjectの戻り値

    SDKについて勉強中なのですSelectObject関数についてどうしても引っかかることがあります。 とあるサイトにはSelectObjectは、前に結びついていたハンドルを戻り値とすると書いてありました。 http://kerochan.no-ip.com/vcsdk/letsprog/chap14.htm に書いてある例で、 ******************************************* hBit = CreateCompatibleBitmap(hdc,ScrnSize.right,ScrnSize.bottom); SelectObject(memdc,hBit); SelectObject(memdc,hBit);*****(1) hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); hDefBrush = SelectObject(memdc,hBrush);*****(2) PatBlt(memdc,0,0,ScrnSize.right,ScrnSize.bottom,PATCOPY); ReleaseDC(hwnd,hdc); SelectObject(memdc,hDefBrush);*****(3) DeleteObject((HGDIOBJ)hBrush); ****************************************** となっているのですが、(1)でmemdcと関連付けたビットマップハンドル(hBit)は、(2)でmemdcに新たにブラシハンドル(hBrush)と関連付けることによって切り離されてしまうのでしょうか?それとも切り離されるものは種類単位なのでしょうか?ブラシハンドルを関連付けたら前のブラシハンドルが返って来るとか・・ SelectObject関数の戻り値に付いていまいちはっきりしていないのでわかる方がいらしたらよろしくお願いします。

  • C 多角形を半透明に塗る方法

    C#の、多角形を半透明に塗るプログラムがあります。 Point[] pa; SolidBrush brush1 = new SolidBrush(Color.FromArgb(128,Color.Black)); g.FillPolygon(brush1, pa); これと同じことをCで記載したいので http://www.geocities.jp/ky_webid/win32c/010.html や http://wisdom.sakura.ne.jp/system/winapi/win32/win29.html を参考にして、やっと多角形の塗りつぶし(赤)まではできました。 が、半透明にする方法がわかりません。 よろしくお願いします。 POINT pa[]; SelectObject(hdc , CreateSolidBrush(0xFF)); SetPolyFillMode(hdc , WINDING); Polygon(hdc , pa , n); DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));

専門家に質問してみよう