えちぜんといいます。
開発環境
VisualStudio2005 Visual C++
ActiveXコントロールをATLにて作成しています。
MFCは使用していません。
コントロール内のメソッドから_beginthreadを用いてあるデバイスを監視し、終了した
時点でFire_AnsMessageのメソッドを呼ぶようにしました。
ActiveXコントロールテストコンテナを用いて動作を確認したところ、ログウィンドウに
イベント発生時のメッセージが出力されていることを確認しました。
しかし、これをブラウザ(IE8)で動かすとイベントが発生しません。
スレッド内でFire_AnsMessageを呼び出さず、コントロール内のメソッドで呼び出せばブ
ラウザでも動作することを確認しましたので、スレッドが絡んだ問題だろうということ
はわかったのですが、どのような処理が必要なのでしょうか。
---- ソース -----
STDMETHODIMP CFingerCtrl::GetData(LONG no)
{
CFingerParam* param = new CFingerParam( this, no);
::_beginthread( AnsGetData, 0, param);
}
// スタティックメソッド
void CFingerCtrl::AnsGetData( void* obj)
{
CFingerParam* ctrl = (CFingerParam*)obj;
CFingerCtrl* p = ctrl->GetCtrl();
long no = ctrl->GetNo();
delete obj;
while( true)
{
if( !p->device->GetData())
::Sleep(1000);
else
break;
}
p->Fire_AnsMessage(no, L完了しました。);
}
スレッド側からイベントを発行しているので
STAスレッドでは補足できないということなのかもしれません。
メインスレッドからイベントを発行するようにしてみてはいかがでしょうか。
> subaruさん
メインスレッドからイベントを発行できればそれがいいのですが、
デバイスへの入力待ちなどがありますのでスレッド起こしすしかないかと考えていま
す。
メインスレッド側へ何らかのメッセージを送ることも考えたのですが、ウィンドウハン
ドルはNULL(m_hWndがNULLでした)になってるようで送り方もわからない状態です。
デバッグしていると、以下の部分までは動作していることを確認しました。
致命的なエラーらしいのですが・・・
HRESULT Fire_AnsMessage( LONG no, BSTR data)
{
・
・
・
ここでE_UNEXPECTED
-→ hr = pConnection->Invoke(1, IID_NULL,
LOCALE_USER_DEFAULT,DISPATCH_METHOD,
¶ms, &varResult, NULL, NULL);
}
}
return hr;
}
スレッド毎にCoInitializeして、
STAだったらインターフェースの生ポインタではなく、
プロキシを渡す必要があります。
それがいやなら、COMを所有しているスレッドに処理を依頼する手もありそうです。
IEではActiveXコントロールをSTAで動作させるため、そのままではスレッド間でやり取
りができないという認識でいいのでしょうか。(テストコンテナではMTAで動作させてい
る?)
> ロマさん
プロキシとは、接続ポイントで生成されたCProxy_***というクラスのことでしょうか。
CFingerCtrlの派生元にこのクラスがあるみたいなので、上記コードでも大丈夫のような
気がしますが、私なにか勘違いしてるでしょうか。
また、調べたところマーシャリングが必要らしいということはわかったのですが、やり
方はまだよくわかってません。
インターフェイスをマーシャルし子スレッドに渡し、アンマーシャル後イベントを発行
することでうまく動作しました。
subaruさん、ロマさん、ありがとうございました。
-- 親スレッド側 --
接続ポイント?(IDispatch*)をマーシャルしIStream*の配列にし子スレッドに渡しまし
た。
IStream* stream = NULL;
HRESULT hr = S_OK;
std::vector<IStream*> streames;
CProxy_IFingerCtrlEvents<CFingerCtrl>* pT =
static_cast<CProxy_IFingerCtrlEvents<CFingerCtrl>*>(this);
int nConnectionIndex;
int nConnections = pT->m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections;
nConnectionIndex++) {
Lock();
CComPtr<IUnknown> sp = pT->m_vec.GetAt(nConnectionIndex);
Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL) {
stream = NULL;
hr = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pDispatch,
(IStream**) &stream);
streames.push_back( stream);
}
}
-- 子スレッド側 --
IStream*の配列をパラメータとして渡し、IDispatch*にアンマーシャルしInvokeメソッ
ドを実行しました。
std::vector< IStream*> streams;
std::vector< IStream*>::iterator it;
std::vector< IDispatch*> dispatches;
std::vector< IDispatch*>::iterator itdispatch;
・
・
for ( it = streams.begin(); it != streams.end(); ++it){
IDispatch* dispatch = 0;
hr = CoGetInterfaceAndReleaseStream( *it, IID_IDispatch, (void**) &dispatch);
dispatches.push_back( dispatch);
}
・
・
hr = (*itdispatch)->Invoke(3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
¶ms, &varResult, NULL, NULL);