お世話になっております。
以前こちらでお世話になって解決した問題の続きでまだ困っております。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200801/08010015.txt
VC6で作ったActiveXでビットマップを表示しています。
また、それをC#で作ったアプリに乗せています。
ActiveXで表示しているビットマップの返し方が分からずに以前に質問したのですが
その方法は以前の質問で解決いたしました。
テストも行い、正常に返せています。
しかし、実際に返したいビットマップを返したらアプリ側(C#)でエラーが出て止まります。
エラー内容は
'System.Runtime.InteropServices.ExternalException' のハンドルされていない例外が
System.Drawing.dll で発生しました。
追加情報: GDI+ で汎用エラーが発生しました。
という物です。
ActiveXの内容としては、OnDrawの中でpdcにSetPixel関数を使って画像を描画していま
す。ここはライブラリを使っているので変えられません。
そして、オートメーションで作った関数でビットマップを返そうとしています。
LPPICTUREDISP ActiveX::xxx()
{
CPictureHolder pictureHolder;
CBitmap *ptmpBmp;
ptmpBmp = testDC.GetCurrentBitmap(); // OnDrawでtestDC.CreateCompatibleDC(pdc);
pictureHolder.CreateFromBitmap(ptmpBmp, NULL, TRUE);
return pictureHolder.GetPictureDispatch();
}
これで返すとこの関数の呼び出し側アプリでエラーが発生します。
testDC = GetDC();
とするとActiveXの画像のみが取れるかな?と思ったのですがWindows全体のハードコピー
が取れてしまいました。
リソースのビットマップを
ptmpBmp = LoadBitmap(IDB_BITMAP1);
として、それを上記方法で返すときちんと取得できます。
何とか現在ActiveXで表示している画像のみを取得して返したいのですが、どのようにし
たら良いのでしょうか?
説明が下手で申し訳ないのですが、よろしくお願いします。
それは、testDC.GetCurrentBitmap()で失敗しているのではないでしょうか。
CreateCompatibleDCで複製できるのは、デバイスコンテキストです。
デバイスコンテキストはビットマップを持っているわけでは有りません。
GetCurrentBitmap()を使うならば、ビットマップを自分で生成して、複製したデ
バイスコンテキストにSelectObjectで結び付ける必要があると思います。
その条件ならば、
・まず裏画面としてビットマップを作る。
・描画内容変更の際は、裏画面ビットマップに描画する。
・描画の際は、OnDrawで与えられたDCの複製DCを作成して、複製DCと裏画
面ビットマップを結びつけて、DCへ複製DCからBitBltする。
・ビットマップを返す時にはCreateFromBitmapに裏画面ビットマップを与える。
などとした方がいいように思います。
ビットマップへの描画は
・作成時に予めビットデータに直接アクセスできるビットマップを作り、それを編集
する。
・描画時にDCを作成し裏画面ビットマップを結びつけて、それによって描画する。
等の選択肢があります。
OnDrawで与えられたDCからビットマップを作らない理由は、他のウィンドウと共
有するところから画像を取得すると変な画像になる場合があるからです。
毎回DCを作らなくてもいいですが、途中でデスクトップDCの設定が変わる可能
性を考慮しましょう。
麩 様
詳しい解説ありがとうございます。
良く理解できました。
CreateCompatibleDCでデバイスコンテキストが保持しているビットマップ等も全てコピー
されるのだと思っていました。
そこで、アドバイスを参考に複製したデバイスコンテキストに同じくビットマップを作り
SelectObjectで結び付けました。
そちらにも同様にSetPixel関数にて描画しました。
それを同じく上記のActiveX::xxx()で返したのですが同様のエラーが出ました。
GetCurrentBitmap()
CreateFromBitmap()
でエラーが出ていないか戻り値をメッセージボックスで出して見たのですが正常に行われ
ているようです。
色々と試しているのですが、何が悪いのかイマイチ分かりません。
> ptmpBmp = testDC.GetCurrentBitmap(); // OnDrawでtestDC.CreateCompatibleDC
(pdc);
> pictureHolder.CreateFromBitmap(ptmpBmp, NULL, TRUE);
ピクチャオブジェクトがビットマップの所有権を持つのであれば、
DCに選択されているビットマップをそのまま渡すのは危険な気がします…
以下のようにビットマップをコピーして渡してみてはいかがでしょう?
CBitmap bmp;
bmp.CreateCompatibleBitmap(&testDC, width, height);
CDC memDC;
memDC.CreateCompatibleDC(&testDC);
CBitmap* oldbmp = memDC.SelectObject(&bmp);
memDC.BitBlt(0, 0, width, height, &testDC, 0, 0, SRCCOPY);
memDC.SelectObject(oldbmp);
pictureHolder.CreateFromBitmap(&bmp, NULL, TRUE);
Kerry さん
返事が遅れてすみません。色々と試していたもので。
結果から言いますと、Kerryさんのおっしゃる様にコピーしてやってみるとエラーも出ず
にリターンすることができました。
ライブラリの中でオブジェクトを消してしまっている所があって、それに気付かず時間が
かかってしまったのですが。。。
おっしゃるようにDCに直接使っている物をリターンするよりはこの方法でコピーするのが
一番良いし、分かり易いですね。
Kerryさんには何から何までお世話になって本当に感謝しています。
本当にありがとうございました!!