メモリDCのビットマップ内容をHBITMAPへ渡す方法 – プログラミング – Home

メモリDCのビットマップ内容をHBIT...
 
通知
すべてクリア

[解決済] メモリDCのビットマップ内容をHBITMAPへ渡す方法


まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

お世話になります。
メモリ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


引用未解決
トピックタグ
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

DcPictに描画しているなら、DcPictに選択されているビットマップがあるはずですが。

別のビットマップにコピーするなら、
CreateCompatibleBitmapでコピー先ビットマップを作成し、
CreateCompatibleDCでコピー先デバイスコンテキストを作成し、
コピー先デバイスコンテキストにコピー先ビットマップを選択し、
DcPictからコピー先デバイスコンテキストにBlt。
後始末を忘れずに。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

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();
}

何かが間違っている、あるいは足りないのでしょうか…?
よろしくお願いします。


返信引用
ぬ
 ぬ
(@ぬ)
ゲスト
結合: 18年前
投稿: 39
 

とりあえずエラー処理はCreateCompatibleBitmap等でも、というかエラーを返す
可能性のある処理全てでやった方が良いと思います。
それと、メモリリークしていればメモリが1GBあろうが4GBあろうが駄目です。
そもそもメインメモリに収まらなくてもページファイルに収めたりするのでメインメモリ
の制約はそれほど高く無いです。

それと、HBITMAPはビットマップデータではなく、それを示すハンドルに過ぎませ
ん。
ビットマップハンドルを保存したグローバルメモリへのハンドルと、ピットマップハンド
ルは意味が大きく違います。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

ぬさん、返答ありがとうございます。
とりあえずエラーチェックを入れてみましたが、
特にエラーは起こっていないかったようです。
メモリリークも原因ではなさそうです。

どうやら他の部分でメモリを多く取りすぎていたようでした。
そちらの方のメモリを減らしたら、Wid=1024,Hei=2048でもコピーできました。
VC++2005は、使用可能なメモリに制限でも設けてるんでしょうか…?

またこれからいろいろとやるにつれ、問題とか出てきそうですが、
とりあえずこの件はこれで解決となりました。
どうもありがとうございました。


返信引用
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

解決されたようですが、SelectObjectしたら、元に戻したほうが良い気がします。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

SelectObjectしたら、やっぱ、戻さないとまずいですか…?
戻さなくても問題なく動くので、今まで戻さないでプログラム作ってました…。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

>SelectObjectしたら、やっぱ、戻さないとまずいですか…?
>戻さなくても問題なく動くので、今まで戻さないでプログラム作ってました…。
戻すのは、必修です。
CBitmapでなくCFontで同じようなことすると、システムフォントがウイルスに
感染したような感じでいろいろ変化して、最後「リソースが足りません」とも言うメッ
セージを表示してOSが暴走しました。

「CBitmap」だとはいえ、リソースは毎回きちんと元に戻しましょう。


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

関連付けられたままだと解放されないので、どんどんリークしていき、
最後にはリソースが足りなくなるわけです。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

ということはメモリリークしてたんですね…
グローバルのDCで、プログラム起動時に一度だけ
SelectObjectするような場合でも、
プログラム終了時には戻さないとまずいですよね、やっぱ。
今度からキチンとやるようにします。
(今まで、DereteDCすらやってなかった…)
教えていただきありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました