VC6.0を使用してActiveXを作成しています。
ActiveXの中のCBitmapオブジェクトを呼び出し元アプリにコピーするという事を行わなけ
ればなりません。
クラスウィザードのオートメーションのメソッドの追加から関数を作っているのですが、
戻り値のタイプの中にCBitmapがない為にどのようにしたら良いのか分かりません。
よろしくお願いします。
LPPICTUREDISP型を指定してIPictureDispインターフェイスを返せば良いでしょう。
CPictureHolderクラスを使えば比較的楽に実装できると思います。
早速のアドバイスありがとうございます。
LPPICTUREDISP・IPictureDisp・CPictureHolder
初めて見る言葉ばかりですので、調べてみました。
知識が無いので中々理解できません。
おっしゃっている方法ではLPPICTUREDISPを返す事になるのでしょうか?
呼び出し元のアプリは私が作るのではないのでCBitmap(ポインタでも不可)を返すとい
うのは変更できなのですが
その方法でCBitmapを返すことは可能なのでしょうか?
色々と調べたのですが、よく分かりませんでした。
とりあえずオートメーションで以下のようなメソッドを作り
LPPICTUREDISP xxx(){
CPictureHolder pictureHolder;
pictureHolder.CreateFromBitmap(tmpBmp); // tmpBmpがリターンしたいCBitmapです
return pictureHolder.GetPictureDispatch();
}
という関数を作り、呼び出し元で
void CTest999Dlg::OnButton1()
{
CBitmap bitmap;
bitmap = m_qr.GetBitmap();
}
としたのですが、エラー('operator '^=' 関数は '<Unknown>' 内では使用できませ
ん。)が出て使えませんでした。
LPPICUTUREDISPという型が何なのか良く分からないのですが、呼び出し元から
GetBitmap()を呼ぶと戻り値はCPictureと表示されていました。
何をどうしたら良いのか分からないのですが、ご教示願えないでしょうか。
呼び出し元関数をそのまま載せてしまっていました。
これでは分かりませんね。書き直します。
void CTestDlg::OnButton1()
{
CBitmap bitmap;
bitmap = ActiveX.xxx(); // ActiveXのオートメーションで作ったxxxメソッド
}
とても困っていて些細な情報でもいいので、よろしくお願いします。
CPictureクラスというのは、タイプライブラリから生成されたクラスですよね?
返されたCPictureクラス(COleDispatchDriver)からIPictureインターフェイスを
取得し、IPicture::Renderメソッドを使ってDCにレンダリングします。
下の例ではクライアントDCに直接描画していますが、メモリDCにレンダリング
すればビットマップとして取り出すことも可能です。
#include <afxole.h>
DEFINE_IPTR(IPicture)
void CTest999Dlg::OnButton1()
{
IPicturePtr pict = ActiveX.xxx();
OLE_XSIZE_HIMETRIC hmW;
OLE_YSIZE_HIMETRIC hmH;
pict->get_Width(&hmW);
pict->get_Height(&hmH);
CClientDC dc(this);
CSize size(hmW, hmH);
dc.HIMETRICtoDP(&size);
CRect rect;
GetClientRect(&rect);
pict->Render(dc, 0, 0, size.cx, size.cy, 0, hmH, hmW, -hmH, &rect);
}
Kerryさん、お返事ありがとうございます。
なるほど、そういう風にして受け取るのですね。
CPictureがMFCの階層図やヘルプにも載っていなかったので全く何のことか分かりません
でした。
IPicturePtrというので受け取れば良いのですね。
後の流れは大体理解できました。
ただ、仕様とは異なってしまうので、今回は使えないのが残念ですが。
受け取り元アプリはC#ですので、何か違う方法があるのかも知れないのでC#掲示板で
も聞いてみます。
今回は誠にありがとうございました。
C#でActiveXコントロールインポータを使えば、LPPICTUREDISP型のメソッドは、
System.Drawing.Image型としてインポートされます。
よって、C#では以下のように使えると思います。
Bitmap bmp = new Bitmap(ActiveX.xxx());
Kerryさん、勝手に解決してしまったのにありがとうございます。
早速おっしゃる方法でやってみました。
ビルドは通ったので早速動かしたんですが、エラーが出て止まってしまいました。
'System.Runtime.InteropServices.ExternalException' のハンドルされていない例外が
System.Drawing.dll で発生しました。
追加情報: GDI+ で汎用エラーが発生しました。
というエラーダイアログが表示されました。
VC側は以前と同じままです。
LPPICTUREDISP xxx(){
CPictureHolder pictureHolder;
pictureHolder.CreateFromBitmap(tmpBmp); // tmpBmpがリターンしたいCBitmapです
return pictureHolder.GetPictureDispatch();
}
C#のアプリ側、VCのActiveX側のどちらが悪いのでしょうか?
ActiveX側のコードは見たところ問題なさそうですが…
tmpBmpはメンバ変数ですか?ローカル変数であれば、関数を抜ける
ときにデストラクタで破棄されてしまうので問題が起こるでしょう。
ありがとうございます。
問題なさそうですか。。。
tmpBmpはPublicなメンバ変数です。
Privateでしたが、念のためPublicに移動しました。
更に念の為に
CPictureHolder pictureHolder
もメンバ変数にしてみましたが、同じエラーメッセージが出ます。
もう少しだと思うのですが、エラーの意味が分からず。。。
ローカル変数の場合でも以下のようにすればokなのですが…
LPPICTUREDISP ActiveX::xxx()
{
CBitmap tmpBmp;
tmpBmp.LoadBitmap(IDB_BITMAP1);
CPictureHolder pict;
pict.CreateFromBitmap(&tmpBmp, NULL, TRUE); // ピクチャオブジェクトが
// ビットマップの所有権を持つ
return pict.GetPictureDispatch();
}
私の環境では上のようなコードで問題なく動いてますが。
ビットマップの作成方法が問題なのかなぁ…
Kerryさん、重ね重ねありがとうございます。
Kerryさんの例のように、リソースのビットマップを返してみるとC#側アプリで受け取る
ことができました。
しかし、私の返したいCBitmapを返すとエラーメッセージが表示されます。
CBitmapに何か問題があるのかと思い、CDCから取る方法に変えました。
表示に使っているCDCからGetCurrentBitmap()を使いそれを返すようにもしたのですが、
同じエラーメッセージでした。
また、
CDC *pDC
pDC = this->GetDC();
tmpBmp = GetCurrentBitmap();
とするとエラーは起こらなかったのですが
画面全体のハードコピーが取れてしまいました。
プリントスクリーンと同じようにWindows全体(タスクバー等も含む)が取れました。
アクティブXで表示されている部分だけが取りたいのですが・・・
ちょっと話が脱線してきてしまいました。別スレ立てた方が良いかも知れませんね。
ここまでこれただけでも非常に感謝しております。恐らく私一人ではいつまでかかってい
たか。。。
本当にありがとうございます。