「猫でもわかるWindowsプログラミング」を参考に、ビットマップを表示するプログラムを作っています。
下記ソース(WM_PAINT部分のみ抜粋)のような感じで、
読み込んだビットマップをダブルバッファリングを用いて表示させたいのですが、
何も表示させることができず、困っております。
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
HBITMAP hBmp;
BITMAP bmp_info;
HDC hDC, hDC_mem;
PAINTSTRUCTps;
int w=0, h=0;
switch (msg) {
case WM_PAINT:
hDC = BeginPaint(hwnd,&ps);
hDC_mem = CreateCompatibleDC(hDC);
hBmp=LoadBitmap(hInst, TEXT("MYBMP"));
hBmp = (HBITMAP)LoadImage(hInst, TEXT("MYBMP"), IMAGE_BITMAP,
0, 0, LR_DEFAULTCOLOR);
GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info);
w = bmp_info.bmWidth;
h = bmp_info.bmHeight;
SelectObject(hDC_mem, hBmp);
BitBlt(hDC, 0, 0, w, h, hDC_mem, 0, 0, SRCCOPY);
DeleteDC(hDC_mem);
DeleteObject( hBmp );
EndPaint( hwnd, &ps );
break;
}
}
リソースですが、下記のように bitmap1.bmpを指定しており、画像はもちろんフォルダ内に入れ、
読み込める状態にはしています。
//
// Bitmap
//
MYBMP BITMAP "bitmap1.bmp"
#endif // 日本語 resources
しかし、hBmpの戻り値を調べると NULL の値が入っています。当然画像は表示されません。
当方、Microsoft visual studio 2005を使っておりますが、このプロジェクトは、
Win32コンソールアプリケーション⇒Windowsアプリケーション で作成はせず、
Win32コンソールアプリケーション⇒コンソールアプリケーション で作成していますので、
ここが問題になっているのでしょうか?
できれば、コンソールアプリケーションで作成したいですが、LoadImage関数は使えないのでしょうか?
それとも他に問題点があるのでしょうか?
以前は動画処理をしており、SetDIBitsToDevice関数を使って配列の中身を指定し、画像をウィンドウ上に表示していました。
しかし、画像のちらつきが気になったため、ダブルバッファリングに改良しようとし、
調べてみたところ、ビットマップを用いるやり方が一般的なようでした。
そこで、まずはビットマップの表示をさせるプログラムをつくってみようと思ったのですが、つまずいている状態です。
環境は、
Microsoft Windows XP Home Edition Version2002 Service Pack 3
Pentium(R) 4 CPU 2.80GHz 1.0GB RAM
Microsoft visual studio 2005(有料)
です。
何かアドバイスをよろしくお願いします。
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
SelectObjectは、デバイスコンテキストにビットマップなどを選択すると同時に、元々選択されていたビットマップなどのハンドルを返します。
メモリDCには、1×1ピクセル モノクロのビットマップが選択されているはずです。なので、このビットマップのハンドルを保存しておかないと、その後このビットマップの操作ができなくなる(リソースリーク)ということです。デバイスコンテキストに選択されているリソースは、元に戻してからデバイスコンテキストをリリースするなり、削除するなりしないといけません。
HBITMAP hbmpOld;
hbmpOld = (HBITMAP)SelectObject(hDC_mem, hBmp);
BitBlt(hDC, 0, 0, w, h, hDC_mem, 0, 0, SRCCOPY);
SelectObject(hDC_mem, hbmpOld); /* ここでSelectObjectが返すのはhBmpなので、保存する必要はない */
DeleteDC(hDC_mem);
DeleteObject(hBmp);
としましょう。
この回答への補足
回答ありがとうございます。
単純に1つのビットマップを表示させるだけのプログラムは、
正常に動作するようになりました。
これを動画処理でも行えるようにしたいのですが、動画処理した結果をビットマップで連続で表示しようとするプログラムでは、BitBlltでウィンドウにうまく転送できていないようです。
(ウィンドウに変化なし+ウィンドウをクリックしてもアクティブにならない)
動画は25fpsで、1フレームごとに処理結果をビットマップ画像に書き込み、
LoadImage関数でそのビットマップ画像を読み込み、読み込んだ画像をBitBltで転送することの繰り返しを行っています。
試しに50フレーム間、画像処理結果をビットマップ画像に書き込んでみましたが、書き込み自体は正常に動作していると思います。
LoadImage関数も戻り値がNULLではないので問題ないはず。。
問題があるとすれば、ウィンドウやインスタンスのハンドル?と思ったので、
コンソールアプリケーションでつくっていたものを、
Windowsアプリケーションとしてつくりなおしてみましたが、問題はそこでなかったためか効果ありませんでした。
下記は、プログラムのソースになります。
*************************************************
// (1)ビットマップ(MYBMP)に画像処理結果書き込み
out_bmmap("MYBMP"); //自作のプログラム
hdc = BeginPaint(hWnd, &ps);
hdc_mem = CreateCompatibleDC(hdc);
// (2)ビットマップ読み込み
hBmp = (HBITMAP)LoadImage(hInst,
TEXT("MYBMP"), IMAGE_BITMAP,
0, 0, LR_DEFAULTCOLOR);
GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info);
w = bmp_info.bmWidth;
h = bmp_info.bmHeight;
hBmpOld = (HBITMAP)SelectObject(hdc_mem, hBmp);
// (3)ビットマップをウィンドウに転送
BitBlt(hdc, 0, 0, w, h, hdc_mem, 0, 0, SRCCOPY);
SelectObject(hdc_mem, hBmpOld);
DeleteDC(hdc_mem);
DeleteObject( hBmp );
EndPaint( hWnd, &ps );
*************************************************
(1)~(3)の処理を1フレームごとに行うために、
http://okwave.jp/qa/q6366968.html
を参考にし、InvalidateRectとUpdateWindowを1フレームの処理ごとに使っています。
なかなかうまくいかないです;;
No.2
- 回答日時:
> wc.hInstance = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
wcとは何? また、デスクトップはユーザーごとに1つなので、実行しているインスタンスのハンドルにはならないのでは?
ビットマップが表示されないのとは関係ないかもしれませんが、
> hBmp=LoadBitmap(hInst, TEXT("MYBMP"));
> hBmp = (HBITMAP)LoadImage(hInst, TEXT("MYBMP"), IMAGE_BITMAP,
> 0, 0, LR_DEFAULTCOLOR);
どちらか一方にしたほうが良いのでは?
> SelectObject(hDC_mem, hBmp);
>
> BitBlt(hDC, 0, 0, w, h, hDC_mem, 0, 0, SRCCOPY);
>
> DeleteDC(hDC_mem);
> DeleteObject( hBmp );
hDC_memに最初に選択されていたビットマップのハンドルが保存されていません。
hBmpを選択後、選択を解除せずにhDC_memを削除しています。
この回答への補足
ビットマップなんですが、表示できました!
どうやらウィンドウハンドルを複数作成していたため、ごちゃごちゃになっていたのが原因みたいです。
表示はできたのですが、新たに教えていただきたいこともありますので、
以下、(1)~(3)に分けてコメントさせていただきます
。
(1)WNDCLASSEX wcは、ウィンドウのクラスです。
説明不足ですみません。
typedef WNDCLASSEXA WNDCLASSEX;
typedef struct tagWNDCLASSEXA {
UINT cbSize;
/* Win 3.x */
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
/* Win 4.0 */
HICON hIconSm;
}
(2)hBmpについては、試行錯誤していた際のソースを載せてしまいました;;
普段は、LoadImageのほうだけを書いていました。
(3)「hDC_memに最初に選択されていたビットマップのハンドルが保存されていません。hBmpを選択後、選択を解除せずにhDC_memを削除しています。」
とのことですが、私の理解力が足らずよく分かりませんでした。
申し訳ありませんが、もう少し詳しく教えていただいてもよろしいでしょうか?
私は、下記のような感じで、ダブルバッファリングをしているつもりだったのですが、まったく違うのでしょうか?
hDC = BeginPaint(hwnd,&ps);
hDC_mem = CreateCompatibleDC(hDC);
hBmp = (HBITMAP)LoadImage(hInst, TEXT("MYBMP"),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info);
w = bmp_info.bmWidth;
h = bmp_info.bmHeight;
SelectObject(hDC_mem, hBmp);
// ここに hDC_memを対象とした描画処理を追加していく
// [追加ソース]
BitBlt(hDC, 0, 0, w, h, hDC_mem, 0, 0, SRCCOPY);// 一度だけ転送
DeleteDC(hDC_mem);
DeleteObject( hBmp );
No.1
- 回答日時:
コンソールアプリで元を作ったのですか?
WinMainからこないと色々と面倒なことを自前でやら無ければいけなくなりますが ・・・
リソースを読み込むにしても HINSTANCEが不正なら読み込めませんよ
この回答への補足
コンソールがあったほうがデバッグしやすかったので。。
いろんな本を参考に自前で作成しました。
以前は、下記のようにSetDIBitsToDevice関数を使い、lpBmpDataの中身を
画面に表示していました。これについては、特に問題はなく表示できていたと思います。
//グラフィック用ウィンドウのデータをまとめた構造体
typedef struct
{
HINSTANCE hi;
int x;// 表示開始位置
int y;
HWND hwnd;// 自分のウィンドウハンドル
BYTE *lpBmpData; // BMPのデータ部分
BITMAPINFOHEADER bih;
} IMG0;
// ウィンドウクラス登録時にインスタンスハンドルの取得
wc.hInstance = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
//グローバル変数hInstに格納
hInst = wc.hInstance;
IMG0 * pimg;
hDC = BeginPaint(hwnd,&ps);
SetDIBitsToDevice( hDC, 0, 0,// コピー先x,y座標
pimg -> bih.biWidth,// DIBの幅
pimg -> bih.biHeight,// DIBの高さ
0, 0,// DIBの座標
0,// 走査線
pimg -> bih.biHeight,// 走査線数
pimg -> lpBmpData,// 画像処理後のデータをここにいれています
(BITMAPINFO *)&( pimg -> bih),// BITMAPINFOにキャスト
DIB_RGB_COLORS );
EndPaint( hwnd, &ps );
私自身プログラミング初心者ですので、どこかのソース記述が間違っており、HINSTANCEが不正ということもあると思います。
上記ソースでは、hInst使ってないですし。。
一度Windowsアプリケーションで作成してみます!!
アドバイスありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語の質問です。バイナリ形式で保存されたWindows Bitmap形式の画像ファイルを読み込み、 3 2023/07/19 14:58
- HTML・CSS 詳しい方に質問です。 早急に解決したいと思っています。 ポートフォリオをMacBook で作成したと 2 2023/05/12 17:40
- C言語・C++・C# 【C++】IDirect3DSurfaceのディープコピーは可能ですか? 1 2022/07/06 02:47
- Visual Basic(VBA) Vba LongPtrについて教えてください 2 2022/08/19 11:14
- Visual Basic(VBA) 【VBA】写真の貼り付けコードがうまく機能しません。 5 2022/09/01 18:43
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
- 飛行機・空港 ミルウォーキーツールHDC大阪から伊丹空港へ乗り換え無しで行く方法はありますか? できれば、空港直通 2 2023/05/12 06:44
- Visual Basic(VBA) エクセルマクロでアニメを作る方法を教えてください。 1 2023/02/07 14:27
- その他(プログラミング・Web制作) uwscとWinShotを使いスクリーンショットを撮る 1 2022/06/30 21:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
コントロール内の文字の背景色
-
VBでFD、USBの有効・無効...
-
SetWindowRgn()関数について。
-
Win32APIにて、アイコンの情報...
-
エクセルで作った新しいウイン...
-
「アイテムは収集されました」...
-
グラフの交点の求め方(Excel)
-
フォントの大きさ
-
VBAのフォント変更(エクセルか...
-
メッセージボックスの選択ボタ...
-
コントロールの書式設定で、“コ...
-
メッセージボックスを大きくす...
-
検索の画面がでなくなってしま...
-
コンボボックス内の文字サイズ変更
-
フォームでPDFを表示させた...
-
Excelの上下を固定したい
-
他のウィンドウのボタンを自動...
-
閉図形の座標の配列が右回りか...
-
ダイアログ内コントロールの位...
-
ゲームでは結局どっちが良いの?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
コンテキスト依存とは?
-
ダイアログにビットマップを貼...
-
GetDC()とCreateCompatibleDC()
-
画面がチカチカする
-
C 多角形を半透明に塗る方法
-
ピクチャーコントロールのデバ...
-
Rectangleで、リソースが解放さ...
-
画像処理 ビットマップ ダブ...
-
ウインドウ内全体を一定時間で...
-
TextOutについて
-
VBでFD、USBの有効・無効...
-
メモリデバイスコンテキスト&...
-
ハードコピーをプログラムから...
-
VC++のTextOutの再描画の仕方
-
PrintScreenしたあとに画像を保...
-
SelectObjectについて
-
ダブルバッファの作り方
-
VC++でBitmapとText文字を表示...
-
Windowsプログラミング 画面描...
-
GetPixelに使うHDCの作り方
おすすめ情報