MFCにてリモートオートメーションを実装したいと思っています。
~~~~~~~
流れは以下のイメージです。
1.CoCreateInstanceEx()により、AAA.exeがBBB.exeを起動。
2.BBB.exeが起動したら、CoCreateInstanceEx()にてAAA.exeにアクセスできるように
する。
※それぞれ別PCに1プロセスづつ生成されるイメージです。
AAA.exe・BBB.exe共にCOMサーバーという事になります。
これを実現しようとした所、既にBBB.exeが生成されている状態で、AAA.exeが
CoCreateInstanceEx()をコールした所、別のBBB.exeが生成されてしまいました。
(BBB.exeが2匹になってしまいました)
上記、Visual C++ 2005にてMFCアプリケーション(オートメーションあり)として
プロジェクトを生成致しました。
※試しにATL-COMにて同様のものを作成した所、意図する動きになりました。
(=更に生成はされず、双方向通信可能となりました)
本来、CoCreateInstance()/CoCreateInstanceEx()を使用した場合、
PC内に複数のアプリケーションが起動しないものだと思っております。
MFCによりCOMアプリケーションを作成した場合、何か特別な前処理が
必要なのでしょうか?(例えばOLE関連のAPIを呼ぶ必要があるとか)
ご存知の方がいらっしゃいましたら、コメントをお願い致します。
※ちなみに…ローカルPC内にて上記を試してみましたが、結果は同じでした。
また、COleDispatchDriverクラスのメソッド(CreateDispatch())による接続も
試してみましたが、こちらも同様でした。
#MFC で COM を作ったことが無いので、外していたら申し訳ない。
BBB.exe 内で CoRegisterClassObject の第4引数には何を渡していますか?
この値によって、複数起動するかどうかが決まったと思います。
詳細は[HomePage]を参照。
MFCの場合ですと、COleTemplateServer::ConnectTemplateの第3引数に
相当します。
シャノンさん、Kerryさん、有用な情報をありがとうございます。
CoRegisterClassObject 及び COleTemplateServer を調べた所、
COleObjectFactoryのコンストラクタに渡すbMultiInstance値が
TRUEの場合、オブジェクトの作成が要求されるたびに、
複数のインスタンスが起動してしまうようです。
COleObjectFactory::COleObjectFactory
→ http://msdn2.microsoft.com/ja-jp/library/dw3tah1k(VS.80).aspx
オートメーションありでMFCアプリケーションを作成すると、stdafx.hに
以下のマクロが定義されます。
// このマクロは IMPLEMENT_OLECREATE と同じですが、COleObjectFactory コンストラ
クタに bMultiInstance パラメータとして
// TRUE を渡します。
// オートメーション コントローラによって要求される各オートメーション プロキシ
// オブジェクトが実行されるように、このアプリケーションの別のインスタンスが必
要です。
#ifndef IMPLEMENT_OLECREATE2
#define IMPLEMENT_OLECREATE2(class_name, external_name, l, w1, w2, b1, b2, b3,
b4, b5, b6, b7, b8) \
AFX_DATADEF COleObjectFactory class_name::factory(class_name::guid, \
RUNTIME_CLASS(class_name), TRUE, _T(external_name)); \
const AFX_DATADEF GUID class_name::guid = \
{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } };
#endif // IMPLEMENT_OLECREATE2
何故かデフォルトでこのマクロを使用するようになっていました。
このマクロを使用している箇所を、IMPLEMENT_OLECREATE に書き換えた所、
意図する動作に近づきました。
(AAA.exeが複数回BBB.exeを作成要求しても、BBB.exeは1匹のみ。
しかしBBB.exeからAAA.exeに接続しようとしたら別のAAA.exeが立ち上がってしまう…。)
あと一息といった感じになりました。本当にありがとうございます。
調査後、最終結果を報告させて頂きます。
※それにしても、上記マクロがデフォルトで作成されてしまうのが腑に落ちませんね…。
AAA.exeとBBB.exeそれぞれが1匹づつで動作するようになりましたので
報告させて頂きます。
1.AAA.exe/BBB.exe それぞれの BOOL CServer1App::InitInstance() を
以下のように変更。
// アプリケーションがスタンドアロンまたは/Register や /Regserver などの
// スイッチで起動されました。
// タイプ ライブラリを含むレジストリ エントリを更新します。
else
{
// ★コレを追加(なんか無理やりな感じもするけど…)
COleTemplateServer::RegisterAll();
COleObjectFactory::UpdateRegistryAll();
AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid);
if (cmdInfo.m_nShellCommand == CCommandLineInfo::AppRegister)
return FALSE;
}
2.DlgProxy.cpp のIMPLEMENT_OLECREATE2(...)を、IMPLEMENT_OLECREATE(...)に変更。
もっとスッキリした対処方法があるのかもしれませんが…。
ひとまず解決とさせて頂きます。
シャノンさん、Kerryさん、ありがとうございました。
もし『コレの方がいいよ!』『普通はこうやるよ!』的なご意見をお持ちの方が
いらっしゃいましたら、引き続きコメントをお願い致します。
修正します。
上記、対処を2つ書きましたが、2のみでOKでした。
デバッガで検証していた為、1の対処を入れておりましたが、よくよく考えたら
(Visual Studio 2005の場合)
IDEのプロジェクトタブ
→XXXのプロパティ
→構成プロパティ
→デバッグ
→コマンド引数
…に、『/Embedding』もしくは『/Automation』を設定すればOKです。
実際の実行時も、AAA.exeの起動時に『/Embedding』もしくは『/Automation』を
渡すようにすれば良いようです。
(AAA.exeから起動されるBBB.exeは、自動的に/Embeddingが渡されます)
これでスッキリです!!
皆様、ありがとうございました。