プロが教えるわが家の防犯対策術!

いつもお世話になっております。
VS2005でC++を用いてWindowsアプリケーションの作成をしています。

子ウィンドウにビットマップ画像(ファイル名:HELP.bmp)を
表示させようとプログラムを組んだのですが、
子ウィンドウを出してもビットマップ画像が表示されません。

以下のようなプログラムを追加しました。
---------------------------------
///リソーススクリプト/////////////////////////////////
 IDB_BITMAP1  BITMAP DISCARDABLE  "HELP.bmp"

///ヘッダースクリプト/////////////////////////////////
 #define IDB_BITMAP1   3000

///ソーススクリプト///////////////////////////////////
void ShowMyBMP(HWND hWnd, HDC hdc){
  HDC hmdc;
  HBITMAP hBitmap;
  BITMAP bmp;
  HINSTANCE hInst;
  int BMP_W, BMP_H;

  hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
  hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));  //インスタンスハンドル取得
  GetObject(hBitmap, sizeof(BITMAP), &bmp);  //ビットマップの情報を得る
  BMP_W = (int)bmp.bmWidth;  //画像の幅
  BMP_H = (int)bmp.bmHeight;  //画像の高さ

  hmdc = CreateCompatibleDC(hdc);  //メモリデバイスコンテキストハンドルを取得
  SelectObject(hmdc, hBitmap);
  BitBlt(hdc, 0, 0, BMP_W, BMP_H, hmdc, 0, 0, SRCCOPY);
  StretchBlt(hdc, 0, BMP_H, BMP_W / 2, BMP_H / 2, hmdc, 0, 0, BMP_W, BMP_H, SRCCOPY);
  DeleteDC(hmdc);//デバイスコンテキストハンドルを開放
  DeleteObject(hBitmap);
  return;
}
---------------------------------

ShowMyBMP関数は子ウィンドウを表示するときに実行されます。
全て載せられないので追加した部分のみプログラムを載せましたが、
この部分だけでも、プログラムの間違い等はありませんでしょうか。
ご教授お願いいたします。

A 回答 (7件)

>実はさらにグローバルにhWndが宣言されてて


本当はその可能性も考えなくもありませんでしたが、まさかそんな事はしないだろう、あり得ないだろうと、否定していました。

あり得るとして、その考えを推し進めると。
コンパイルエラーが起こる→hWndが宣言されていませんと出る。
それならば、hWndをグローバルで宣言してしまえと HWND hWnd;を記述
コンパイルエラーはなくなる。
※hChdWnd等はコピらず、コンパイルエラーが出なくなった事で満足していると仮定

で以下の個所では hWndに対して描画、初期化されていないウィンドウハンドルなので、実際にはどこに描画されているのかは不明。
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
ShowMyBMP(hWnd, hdc);
break;

そもそも有効なウィンドウハンドルではないため、エラーを返している可能性もあるのだが、エラー判定もしていないためそのことに気付いていない?

あるいは、以下のように=0として宣言しているため、デスクトップのウィンドウハンドルとして有効な値となっている。
HWND hWnd=0;
※VC++って、初期化されていない変数を参照しましたとかのWarningって出ましたっけ?出るなら適当な値で初期化するってあり得るかなと。

しかし、EndPaint(hWnd , &ps)を呼び出していないため、描画が更新されずにデスクトップ(あるいは偶然ウィンドウハンドルが一致したどこか別の場所)に描画されている事に気付いていない?


LongSecretさんの指摘や、aaaaaさんの答え見て、質問者様の力量を推測してみると、『あり得るぞ、大いにあり得るぞ』と思えてきたんですが。

まさかこんなことしてませんよね?と確認の意味で。
    • good
    • 0
この回答へのお礼

LongSecretさんのお礼欄にも書かせて頂いたとおり、
BellBellさんが指摘してくださった部分のミスでした。
まさかのまさかでした。ご指摘ありがとうございます。
・・・と共に、確認をするべきでした。ごめんなさい。

でも今回のことで、とても勉強になりました。
BellBellさんわかりやすいご回答、本当にありがとうございました。

お礼日時:2010/03/15 20:51

苦戦してそうですね~。



> WS_CHILD | WS_SYSMENU | WS_THICKFRAME | WS_CAPTION
普通、子ウィンドウを作成する時はスタイルにこんなに必要無いですよ。
WS_CHILD と WS_VISIBLE くらいなものです。

ところでデバッガを使えるようになるといろいろな問題を解決できるようになりますよ。
まずは、OutputDebugString("bbb\n");
とかで、デバッグウィンドウに何か出力できるようになるべきですね。
    • good
    • 0
この回答へのお礼

私の初歩的なミスによったものでした。
これからもっと勉強・確認をします。

また、子ウィンドウスタイルについてご指摘ありがとうございました。
訂正しておきます。
そして、デバッガを使いなれるようにしたいと思います。

ご教授ありがとうございました。

お礼日時:2010/03/15 20:55

あ、ほんとだw


どうせそうだろうと思ってそこは見てなかったですが
となると、正確には

case WM_PAINT:
hdc = BeginPaint(hChdWnd, &ps);
ShowMyBMP(hChdWnd, hdc);
EndPaint(hChdWnd , &ps);
break;

が推奨、となりますかw
BellBellさんナイス指摘ですw

…とみせかけて、実はさらにグローバルにhWndが宣言されてて、そこにhChdWnd をコピってるので実はコンパイルエラーになってないとか?(笑)

書き忘れましたが

>右クリック・左クリックをすると子ウィンドウは閉じます

ということはプロシージャはちゃんと呼び出されています。
また、WM_PAINTは、ウインドウが表示されている時点で、呼び出されているはずです。
現状だと、他のウインドウに隠れて再度表示されるときとか、サイズ変更するときとかも何度も呼び出されてるはずです。
    • good
    • 0
この回答へのお礼

こんばんは。
わかりやすいご説明、本当に感謝いたします。

>case WM_PAINT:
>hdc = BeginPaint(hChdWnd, &ps);
>ShowMyBMP(hChdWnd, hdc);
>EndPaint(hChdWnd , &ps);
>break;

はい、まさにここでした。
hChdWndと書き換えてEndPaintを追加することで画像の表示が可能となりました。

ん~
こんな初歩的なところでミスをしてしまうとは・・・
まだまだ自分は勉強・確認不足です。情けない。
しかし今回はLongSecretさんをはじめ皆さんのおかげで勉強になしました。
もっともっとプログラミングの勉強頑張ります!

本当にありがとうございました。

お礼日時:2010/03/15 20:45

ちょっと気になっただけなんだけど、


#1の方のお礼欄に書かれたソースコードの以下の部分。
~~~~~~~~
//ビットマップ画像表示
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);←ココ
ShowMyBMP(hWnd, hdc);←ココも
break;
~~~~~~~~

hWndってなってるのは、本当のソースではhChdWndとなってるのを写し間違えただけですよね?
普通ならコンパイルエラーになるわけだし。
    • good
    • 0

EndPaint(hw , &ps);→EndPaint(hWnd, &ps);でした(^^;

    • good
    • 0

私の環境でもリソースを使うと出来るときと出来ないときがあり、それがなぜなのかよく分かりませんが、とりあえずそれとは関係なしに



hdc = BeginPaint(hWnd, &ps);

ではじめたら

EndPaint(hw , &ps);

で終了しておくほうが無難(おそらくそれが基本)と思います。
そしてもし「リソースが」うまく働かないならば、実行ファイルに埋め込むのをやめてLoadImage等でファイルからの読み込みを試してみてください。(それでもできなければ、提示していただいたコードの範囲内だとちょっとわかりません。)
概要としては、一例としてこんな感じになります。


HBITMAP hBitmap = (HBITMAP)LoadImage(0, "ファイルのパス",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

HDC hmdc=CreateCompatibleDC(hdc);
SelectObject(hmdc,hBitmap);
BitBlt(hdc, 0, 0, BMP_W, BMP_H, hmdc, 0, 0, SRCCOPY);
StretchBlt(hdc, 0,BMP_H, BMP_W / 2, BMP_H / 2, hmdc, 0, 0, BMP_W, BMP_H, SRCCOPY);

DeleteDC(hmdc);
DeleteObject(hBitmap);


こういうイメージになります☆


これでできましたら
ここから先はパフォーマンスを追求する場合の余談(?)です

//////////////

現在「埋め込むという前提」なことから考えると、ファイルを動的に変更しない、ということになりますから、この場合は毎回サイズを求めずに

static const int BMP_W = 幅, BMP_H = 高さ;

とか、あるいはもっとシンプルに#defineなどで先に決め打ちしてしまって良いと思います。
(いずれも、毎回算出されないことが保証されます)

また、現在の状態だと毎回ロードされて…という具合になってしまいまが、WM_PAINT内では基本的にはBitBltのみだとかなりサクサクです。
(DDBのBitBltのみだと激速です
※ http://lamoo.s53.xrea.com/develop/gdiplus/gdiplu … など)

その場合、CreateCompatibleDCで作るHDC hmdc;
はローカルではなく別に長い寿命(staticなど)を持つように保持させておき、たとえばアプリケーション起動時に生成、その時一回だけビットマップをロードする、そして終了時にDeleteDC(hmdc);
などといった具合にすれば、実現可能です。

後から描画内容を変更する場合でも、そちらのHDCに対して書き換えし、あくまでWM_PAINT内ではそこからBitBltするようにしておけば、最小限の負荷でOKと思われます。(マルチバッファリング)

また、真っ白ということは、ウィンドウクラス登録時にhbrBackgroundに何かを指定していると思いますが、もし画面全部を自分で描画する場合は、そこにNULLを指定しておくとなおGOODと思います。
(どの道上書きされる部分に対して何も処理しないことが保証されるはず)
    • good
    • 0

ぱっと見たところ、間違ってなさそうに見えます。



引数は有効ですか?
その子ウィンドウがまだ作成されてない段階で呼んでませんか?
その子ウィンドウがまだ表示されていない段階で呼んでませんか?

ShowMyBMPが初期化ルーチンで呼ばれるようならば怪しいです。

この回答への補足

---------------------------------------
InitApp(g_hInst, ChildProc, "child");
hChdWnd = CreateWindow("child",
            "子供ウィンドウ",
            WS_CHILD | WS_SYSMENU | WS_THICKFRAME | WS_CAPTION,
           (rec.right - 650) / 2,  //X座標
           (rec.bottom - 450) / 2,  //Y座標
           650,  //幅
           450,  //高さ
           hWnd,  //親ウィンドウのハンドル
           NULL,  //メニューハンドル、子供のID
           g_hInst,  //インスタンスハンドル
           NULL);
ShowWindow(hChdWnd, SW_SHOW);
UpdateWindow(hChdWnd);
---------------------------------------

補足日時:2010/03/14 12:17
    • good
    • 0
この回答へのお礼

早速プログラムを見ていただきありがとうございます。
文字制限のため、aaaaaさんの補足部分にもまたがって関数を載せます。
ごめんなさい。

ShowMyBMPは子ウィンドウプロシージャ内で使用しています。
以下にプログラムを載せます。
---------------------------------------
LRESULT CALLBACK ChildProc(HWND hChdWnd, UINT msg, WPARAM wp, LPARAM lp){
  HDC hdc;
  PAINTSTRUCT ps;

  switch (msg) {
    //ビットマップ画像表示
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      ShowMyBMP(hWnd, hdc);
      break;
    
    //以下の操作が行われたらウィンドウを閉じる
    case WM_LBUTTONDOWN://左クリック
    case WM_RBUTTONDOWN://右クリック
    case WM_KEYDOWN://キーボードのキー押す
      DestroyWindow(hChdWnd);
      break;

    default:
      return (DefWindowProc(hChdWnd, msg, wp, lp));
  }
  return 0L;
}
---------------------------------------

また、子ウィンドウを表示する際のメインウィンドウプロシージャ内の
プログラムをaaaaaさんの補足部分に載せます。

InitApp関数では、ウィンドウクラス登録を行っています。
第1引数にインスタンス、第2引数にプロシージャ名、第3引数にクラス名です。
CreateWindowで作成したウィンドウは表示されるのですが真っ白なんです。

とても初歩的な質問かもしれないのですが、
この場合、ChildProcはいつ呼び出される?のでしょうか。
右クリック・左クリックをすると子ウィンドウは閉じますが、
見てみるとWM_PAINTが呼び出されてないような・・・?

勉強不足でごめんなさい。
ご教授お願いします。

お礼日時:2010/03/14 12:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!