ページ 11

BitBltについて

Posted: 2006年9月29日(金) 23:00
by BingoMan
学校の文化祭も終わり、部活を引退したところで久しぶりの投稿です。

BitBlt関数がメモリ内デバイスコンテキストのビットマップのビット配列を別のデバイスコンテキストのビットマップのビット配列にコピーするメカニズムが知りたくなっていろいろ調べたのですが、結局きちんと解説されているページが見つからなかったのでここで質問させていただきます。具体的には

コード: 全て選択

Dim hOrgDC    As HDC
Dim hOrgBmp  As HBITMAP
をコピー元メモリ内デバイスコンテキストとビットマップのハンドルとして、

コード: 全て選択

Dim hCpyDC    As HDC
Dim hCpyBmp  As HBITMAP
にコピーすることを考えています。

自分なりに考えてみたのですが、
  • 1.コピー元ビット配列のアドレスを調べる
    2.コピー先ビット配列のアドレスを調べる
    3.コピー元ビット配列にアクセスする
    4.コピー先ビット配列に書き込む
という方向で考えています。現在は3がうまくいかないので、おそらく1から失敗しているのではないかと思います。

というわけで、デバイスコンテキストのハンドルからそのデバイスコンテキストに関連付けられたビットマップの、ビット配列のアドレスを取得する方法を教えてください。

長くてわかりにくい質問で申し訳ございません...

Re: BitBltについて

Posted: 2006年9月29日(金) 23:22
by イグトランス
> 1.コピー元ビット配列のアドレスを調べる
> 2.コピー先ビット配列のアドレスを調べる
> 3.コピー元ビット配列にアクセスする
> 4.コピー先ビット配列に書き込む
Windowsが内部でやっていることはおそらくこうでしょう。

GetObjectすればBITMAP構造体のbmBitsには内部のビットマップへのポインタが入っています。

しかし,一体なぜ3がうまくいかないと言うのでしょうか。
どういうコードを書いて,どうなったからそうだと結論付けたというのを是非書いてください。
実は別のことがうまくいっていなかったということがあるかもしれませんよ。

Posted: 2006年9月30日(土) 00:13
by BingoMan
イグトランス様、早速のご返事ありがとうございます。
具体的なコードを出していなかったのでここに掲載します。
まず先頭で次のグローバル変数を定義しています。

コード: 全て選択

' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。

Dim hOrgDC			As HDC
Dim hOrgBmp			As HBITMAP

Dim hCpyDC			As HDC
Dim hCpyBmp			As HBITMAP

'GetObject関数で取得する情報を格納するための変数
Dim OrgBitmap		As BITMAP
Dim OrgBits			As BytePtr

Dim CpyBitmap		As BITMAP
Dim CpyBits			As BytePtr
そしてウィンドウ生成時に次の処理を行っています。

コード: 全て選択

Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
	Dim hDC		As HDC
	Dim i As Long,j As Long

	hDC=GetDC(hMainWnd)
	hCpyDC=CreateCompatibleDC(hDC)
	hCpyBmp=CreateCompatibleBitmap(hDC,200,200)
	SelectObject(hCpyDC,hCpyBmp)
	hOrgDC=CreateCompatibleDC(hDC)
	hOrgBmp=LoadImage(GetModuleHandle(0),XXX_BMP1,IMAGE_BITMAP,200,200,LR_DEFAULTCOLOR)
	SelectObject(hOrgDC,hOrgBmp)
	ReleaseDC(hMainWnd,hDC)

	GetObject(hOrgBmp,SizeOf(BITMAP),OrgBitmap)
	OrgBits=OrgBitmap.bmBits'bit配列の先頭アドレスをBytePtr型変数に格納

	GetObject(hCpyBmp,SizeOf(BITMAP),CpyBitmap)
	CpyBits=CpyBitmap.bmBits'bit配列の先頭アドレスをBytePtr型変数に格納

	/*デバッグ時にここの部分でエラーが発生
	For i=0 To 199
		For j=0 To 199
			SetByte(CpyBits+i*200+j,GetByte(OrgBits+i*200+j))
		Next
	Next
	*/
	'代わりにGetObjectで取得したbit配列の先頭アドレスを表示
	MessageBox(hMainWnd,Hex$(OrgBits),"",MB_OK)
End Sub
このプログラムを実行したところ、表示されるアドレスが常に0でした。
つまり先ほど質問した内容の1の時点でうまくいっていないようです。

このプログラムの間違いを教えてください。よろしくお願い致します。

Posted: 2006年9月30日(土) 09:04
by マティ
動作確認等は行っていません!!!
APIを見ただけの印象でお答えします。(赤字の部分)
hDC=GetDC(hMainWnd)
hCpyDC=CreateCompatibleDC(hDC)
hCpyBmp=CreateCompatibleBitmap(hCpyDC,200,200)
//SelectObject(hCpyDC,hCpyBmp) //hCpyDCで作成すると必要ない
hOrgDC=CreateCompatibleDC(hDC)
hOrgBmp=LoadImage(GetModuleHandle(0),XXX_BMP1,IMAGE_BITMAP,200,200,LR_DEFAULTCOLOR)
SelectObject(hOrgDC,hOrgBmp)
ReleaseDC(hMainWnd,hDC) //※hDCを開放すると、hDCで作成したビットマップは使えない!
依存関係のあるオブジェクトは、生成した順番が新しい物から開放してください。
メモリーリークや不思議な動きをする原因になります。

Posted: 2006年9月30日(土) 11:04
by イグトランス
元のビットマップがLoadImageやCreateCompatibleBitmapで作成しているからだと思います。
bmBitsは,CreateBitmapやCreateBitmapIndirectで作成し(そこでビットマップへのポインタを指定し)たときしか使えなかった気がします。
それ以外の方法でビットマップを作るとビットマップのメモリはシステムが管理するのでユーザにはこうして見せてくれないというのではないでしょうか。

なお,CreateCompatibleBitmapの引数にメモリデバイスコンテキストであるhCpyDCを渡すのは良くないです。
http://msdn.microsoft.com/library/ja/jp ... bitmap.asp
またメモリDCから互換ビットマップを作ればSelectObjectの必要がないということは,記述されていません。
またそこでhDCをReleaseDCによって返しても問題ないです。
メモリDCを作るための情報を得るためだけに使われており,
作ってしまえばメモリDCは元のDCがReleaseDCされても問題無いはずです。