お世話になります。
メモリDCのビットマップ内容を、クリップボードへコピーしたいのですが、
方法が分からず困っております。
分からないのは、メモリDC「DcPict」のビットマップ内容をHBITMAPへ渡す方法です。
以下、ソースコードです。
CDC DcPict;
// DcPictの内容をクリップボードへコピー
void ClipCopy(void)
{
HBITMAP hBmp;
if (!OpenClipboard(hwnd)) return;
EmptyClipboard();
// ここでDcPictのビットマップ内容をhBmpへ渡したい
SetClipboardData(CF_BITMAP, hBmp);
CloseClipboard();
}
ちなみに、ペースト処理は以下のソースコードで上手くいきました。
// クリップボード内容をDcPictへ貼り付け
void ClipPaste(void)
{
CDC DC;
CBitmap *Bmp;
HBITMAP hBmp;
if (!IsClipboardFormatAvailable(CF_BITMAP)) return;
if (!OpenClipboard(hwnd))
return;
hBmp = (HBITMAP)GetClipboardData(CF_BITMAP);
Bmp = CBitmap::FromHandle(hBmp);
DC.CreateCompatibleDC(&DcPict);
DC.SelectObject(Bmp);
DcPict.BitBlt( 0,0,1024,1024, &DC, 0,0,SRCCOPY);
DC.DeleteDC();
CloseClipboard();
}
初歩的な質問ですみません。そもそもHBITMAPについての
十分な知識がないのは重々自覚しておりますが、
なにとぞ、よろしくお願いします。
環境:VC++2005、WinXP Home
DcPictに描画しているなら、DcPictに選択されているビットマップがあるはずですが。
別のビットマップにコピーするなら、
CreateCompatibleBitmapでコピー先ビットマップを作成し、
CreateCompatibleDCでコピー先デバイスコンテキストを作成し、
コピー先デバイスコンテキストにコピー先ビットマップを選択し、
DcPictからコピー先デバイスコンテキストにBlt。
後始末を忘れずに。
ISLeさん、ありがとうございます。
一応、確認なのですが、
「コピー先デバイスコンテキストにコピー先ビットマップを選択し、」
というのはSelectObjectのことで、
「後始末を忘れずに。」といのは「DeleteDC」のことですよね?
以下のコードで、一応、クリップボードへ
ビットマップ内容を送ることができました。
// DcPictの内容をクリップボードへコピー
void ClipCopy(void)
{
CDC DC;
HBITMAP hBmp;
if (!OpenClipboard(hwnd)) return;
EmptyClipboard();
hBmp = CreateCompatibleBitmap(DcPict, Wid,Hei);
DC.CreateCompatibleDC(&DcPict);
DC.SelectObject(hBmp);
DC.BitBlt(0,0,Wid,Hei,&DcPict,0,0,SRCCOPY);
SetClipboardData(CF_BITMAP, hBmp);
DC.DeleteDC();
CloseClipboard();
}
しかし、Wid,Heiの値がともに512の場合は上手くいくのですが、
Wid=1024,Hei=2048にすると上手くいきません。
その前は、Wid,Heiともに1024でもうまくいかなかったのですが、
なぜか今はそれはうまくいくようになりました。
現象としては、クリップボードへコピーした後、
MSペイントにペーストしようとすると、
MSペイントで「クリップボードのエラーです」という
エラーダイアログが表示されてしまいます。
クリップボードビューアで確認したところ、以下のように表示されました。
「クリップブックでは、現在の形式の情報は表示されないか、
またはメモリ不足のため情報が表示されません。
アプリケーションをいくつか終了して、使用可能なメモリを増や」
「使用可能なメモリを増や」の先は表示されません。
メモリは1G積んでるので、低スペックPCというわけでもないのですが…。
GlobalAllocでメモリの確保をしないとならないのかな?
と思って以下のように変更してみたのですが、
これだとWid,Heiともに512でもうまくいきません。
(現象は同じです)
// DcPictの内容をクリップボードへコピー
void ClipCopy(void)
{
CDC DC;
HBITMAP hBmp;
HGLOBAL hMem;
HBITMAP *pBmp;
if (!OpenClipboard(hwnd)) return;
EmptyClipboard();
hBmp = CreateCompatibleBitmap(DcPict, Wid,Hei);
DC.CreateCompatibleDC(&DcPict);
DC.SelectObject(hBmp);
DC.BitBlt(0,0,Wid,Hei,&DcPict,0,0,SRCCOPY);
if (!(hMem = GlobalAlloc(GHND, Wid*Hei*4))) return;
pBmp = (HBITMAP*)GlobalLock(hMem);
memcpy(pBmp, &hBmp, sizeof(HBITMAP));
GlobalUnlock(hMem);
SetClipboardData(CF_BITMAP, hMem);
DC.DeleteDC();
CloseClipboard();
}
何かが間違っている、あるいは足りないのでしょうか…?
よろしくお願いします。
とりあえずエラー処理はCreateCompatibleBitmap等でも、というかエラーを返す
可能性のある処理全てでやった方が良いと思います。
それと、メモリリークしていればメモリが1GBあろうが4GBあろうが駄目です。
そもそもメインメモリに収まらなくてもページファイルに収めたりするのでメインメモリ
の制約はそれほど高く無いです。
それと、HBITMAPはビットマップデータではなく、それを示すハンドルに過ぎませ
ん。
ビットマップハンドルを保存したグローバルメモリへのハンドルと、ピットマップハンド
ルは意味が大きく違います。
ぬさん、返答ありがとうございます。
とりあえずエラーチェックを入れてみましたが、
特にエラーは起こっていないかったようです。
メモリリークも原因ではなさそうです。
どうやら他の部分でメモリを多く取りすぎていたようでした。
そちらの方のメモリを減らしたら、Wid=1024,Hei=2048でもコピーできました。
VC++2005は、使用可能なメモリに制限でも設けてるんでしょうか…?
またこれからいろいろとやるにつれ、問題とか出てきそうですが、
とりあえずこの件はこれで解決となりました。
どうもありがとうございました。
解決されたようですが、SelectObjectしたら、元に戻したほうが良い気がします。
SelectObjectしたら、やっぱ、戻さないとまずいですか…?
戻さなくても問題なく動くので、今まで戻さないでプログラム作ってました…。
>SelectObjectしたら、やっぱ、戻さないとまずいですか…?
>戻さなくても問題なく動くので、今まで戻さないでプログラム作ってました…。
戻すのは、必修です。
CBitmapでなくCFontで同じようなことすると、システムフォントがウイルスに
感染したような感じでいろいろ変化して、最後「リソースが足りません」とも言うメッ
セージを表示してOSが暴走しました。
「CBitmap」だとはいえ、リソースは毎回きちんと元に戻しましょう。
関連付けられたままだと解放されないので、どんどんリークしていき、
最後にはリソースが足りなくなるわけです。
ということはメモリリークしてたんですね…
グローバルのDCで、プログラム起動時に一度だけ
SelectObjectするような場合でも、
プログラム終了時には戻さないとまずいですよね、やっぱ。
今度からキチンとやるようにします。
(今まで、DereteDCすらやってなかった…)
教えていただきありがとうございました。