ビットマップをクリップボードにセット

[戻る]
お茶 2005/09/01(木) 17:15:10
クリップボードにCreateDIBSection()で作成したHBITMAPを送りたいのですが、
うまくいきません。
クリップブック(CLIPBRD.EXE)では
「現在の形式の情報は表示されないか、またはメモリ不足のため情報が表示されません」
と出ます。
実際、Paintに貼り付けようとするとエラーが出ます。
クリップボードに送るコードは以下のようになっています。


 BITMAPINFO bmpInfo;
 bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 bmpInfo.bmiHeader.biWidth = 32;
 bmpInfo.bmiHeader.biHeight = 32;
 bmpInfo.bmiHeader.biPlanes = 1;
 bmpInfo.bmiHeader.biBitCount = 32;
 bmpInfo.bmiHeader.biSizeImage = 32 * 32;
 bmpInfo.bmiHeader.biCompression = BI_RGB;

 DWORD *pBits;
 HDC hdc = GetDC(hWnd);
 HBITMAP hBitmap = CreateDIBSection(hdc, &bmpInfo, DIB_RGB_COLORS,
                    (void **)&pBits, NULL, 0);
 ReleaseDC(hWnd, hdc);

 ZeroMemory(pBits, sizeof(DWORD)*32*32);

 OpenClipboard(hWnd);
 EmptyClipboard();
 SetClipboardData(CF_BITMAP, hBitmap);
 CloseClipboard();


ご覧の通り、32bppの32*32の黒く塗りつぶしたイメージを送ってます。
この程度のサイズ、メモリ不足とは考えられません。
一体何が原因なのでしょうか?

環境はWinXP SP2 + VC++6.0SP6 MFC未使用です。

とおりすがり 2005/09/01(木) 18:50:55
CreateDIBSectionはよく知らないが、検索した使い方となんか違うような気がする。
CreateDIBSectionでぐぐってあなたの使い方と比較してみたらいいのでは?

確認だけどCreateDIBSectionがうまく動くかどうか、試してないってことはないよね。

シャノン 2005/09/01(木) 22:56:50
> bmpInfo.bmiHeader.biBitCount = 32;
> bmpInfo.bmiHeader.biSizeImage = 32 * 32;

32 * 32 ドットの画像で、各ドット 4 バイト(32ビット)ならば、SizeImage は 32 * 
32 * 4 では?

シャノン 2005/09/01(木) 23:01:48
あと、BITMAPINFO::bmiColors には色情報が入って無くてもいいんだっけ?

お茶 2005/09/01(木) 23:14:59
[[解決]]
お二人とも、ありがとうございます。

> 32 * 32 ドットの画像で、各ドット 4 バイト(32ビット)ならば、SizeImage は 32 
> *  32 * 4 では?

あ、確かにそうですね。
でも実はCreateDIBSectionはBI_RGBの場合、サイズは必要ないようです。
実際、上で作ったHBITMAPをCompatibleDCにSelectObjectして確認しております。

実は問題はそこではなく、DIBの場合はSetClipboardData()にCF_DIBで渡さなければ
いけないようです。(もちろんGetClipboardData()もCF_DIBで受け取ります)

という訳で問題は無事解決いたしました。

どうもありがとうございました。

シャノン 2005/09/01(木) 23:28:03
> でも実はCreateDIBSectionはBI_RGBの場合、サイズは必要ないようです。

そうなの?
じゃあ、確保するメモリのサイズは何を元に決まるのかしら?

> DIBの場合はSetClipboardData()にCF_DIBで渡さなければいけないようです

そうなの?
CF_DIB は BITMAPINFO 構造体をセットするように見えるんだけど。

http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/winui/winui/windowsuserinterface/dataexchange/clipboard/clipboardformats.asp

シャノン 2005/09/01(木) 23:29:09
> でも実はCreateDIBSectionはBI_RGBの場合、サイズは必要ないようです。

というか、現状、32 * 32 * 1、つまり1bpp モノクロビットマップになってない?
黒1色だからいいようなものの、3色以上だと破綻しない?

お茶 2005/09/01(木) 23:43:11
> そうなの?
> じゃあ、確保するメモリのサイズは何を元に決まるのかしら?

サイズはBITMAPINFOHEADERのWidthとHeightとBitCountから求められます。
MSDNにも

> Specifies the size, in bytes, of the image. This may be set to zero for
> BI_RGB bitmaps.

とあります。

CF_DIBですが、BITMAPINFOHEADERの直後にビットデータを置きます。
送るデータはHGLOBALです。
よってこんな感じになります。


 HGLOBAL = GlobalAlloc(GHND | GMEM_SHARE,
            sizeof(BITMAPINFOHEADER) + 32 * 32 * sizeof(DWORD));

 BITMAPINFOHEADER *pBmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(hGlobal);
 ZeroMemory(pBmpInfoHeader, sizeof(BITMAPINFOHEADER));
 pBmpInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
 pBmpInfoHeader->biWidth = 32;
 pBmpInfoHeader->biHeight = 32;
 pBmpInfoHeader->biPlanes = 1;
 pBmpInfoHeader->biBitCount = 32;
 pBmpInfoHeader->biCompression = BI_RGB;

 DWORD *pBits = (DWORD *)(pBmpInfoHeader + 1);
 for(int y=0; y<32; ++y){
  for(int x=0; x<32; ++x) pBits[y*32+x] = (red << 16) + (green << 8) + blue;
 }

 GlobalUnlock(hGlobal);

 if(OpenClipboard(GetHWND()) != 0){
    EmptyClipboard();
    SetClipboardData(CF_DIB, hGlobal);
    CloseClipboard();
 }


これでOKです。
まぁ、上下反転してますけど・・・

お茶 2005/09/01(木) 23:46:50
あ、分かると思いますが一応修正。

> HGLOBAL = GlobalAlloc(GHND | GMEM_SHARE,
>            sizeof(BITMAPINFOHEADER) + 32 * 32 * sizeof(DWORD));

HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE,
                   sizeof(BITMAPINFOHEADER) + 32 * 32 * sizeof(DWORD));

シャノン 2005/09/01(木) 23:50:46
> サイズはBITMAPINFOHEADERのWidthとHeightとBitCountから求められます。

これは失礼いたしました。


> CF_DIBですが、BITMAPINFOHEADERの直後にビットデータを置きます。
> 送るデータはHGLOBALです。

あ、CreateDIBSection 使うのやめちゃったんだ。

お茶 2005/09/02(金) 10:08:55
> あ、CreateDIBSection 使うのやめちゃったんだ。

はい、結局CreateDIBSection()で作ったHBITMAPをクリップボードに送る手段は不明で
す。(DDBに変換すればよさそうですが・・・)

上の方法は代替案ですが、今回はこれでOKです。
ありがとうございました。

古いスレッドには追加発言できません。