VB6.0でActiveXEXEでイベントを発生させ、標準EXE側でイベント
を受信しています。
通常は、標準EXE側でイベントの受信が出来るのですが、まれに受信が
できないことがあります。
ActiveXEXEでイベントを発生させていることは確認済みです。
イベントが受信できない原因、または対処方法を宜しくお願いします。
受信側のメッセージループを阻害するようなコードを入れて
いませんか?もしくは、そういう行動(例えばタイトル上
でマウス右ボタンを押しっ放し、とか)を行っているとか。
もっとも、これらなら、App.OleServerBusy???プロパティ
やApp.OleRequestPending???プロパティをいろいろ使えば、
それなりの検出・対処ができるでしょう。
提示された情報だけでは、これ以上のことは言えません。
K.J.K.さん
回答ありがとうございます。
御指摘の通り、受信側ではEnumWindowsを使用し、コールバック
関数(ActiveXEXEの存在チェック関数)を呼び出しています。
それが「メッセージループを阻害するようなコード」に該当して
いるのかもしれません。
コールバック関数中に「DoEvents」をいれておくことで対応でき
るかもしれませんが、実は「イベントが受信できない」ときの条
件が明確になっていないため、対応できているかの確認ができな
いの状態です。。。
App.OleServerBusy???プロパティ等を使用して調査してみます。
どうも無駄で冗長な構造になっているように思えます。
そもそも、存在チェックをなぜするのでしょうか?
何か変化があったらサーバ側から通知する、とすべきでは。
で、受信側では極力メッセージを受け取る機会を用意しておかな
ければなりません。時間のかかる処理がある場合は、DoEventsを
使うとかする以前に、その処理を細かく切り分けて、メッセージ
ループそのものをブロックしないようにすべきでしょう。
ActiveX EXEでのイベントの通知は、COMを介してのメッセージの
やり取りですから、必ずしも成功するとは限りません。但しDDEに
比べれば、遥かに信頼できます。
一般的には、↑に合わせて、
1,DDEよりは頻繁に連絡をとる。
2,ActiveX DLLほどは頻繁には連絡をとらない。
ように組み立てます。ActiveX DLL並に頻繁にイベント通知を
受け取る必要がある場合は、プロジェクトの構造そのものを
見直すべきです。
> そもそも、存在チェックをなぜするのでしょうか?
これは、タスクマネージャでActiveX EXEを落とす意地悪テスト
対応のためで、実際には必要の無い処理です。
この処理は外すようにします。
> ActiveX EXEでのイベントの通知は、COMを介してのメッセージの
やり取りですから、必ずしも成功するとは限りません。
上記の件ですが、どのようなところからの情報でしょうか。
不勉強ですみません。
マイクロソフトがそのようなことを言うとは思えなかったので。
もともとActiveX EXEを使う理由は、データの送受信中に画面をブリ
ンク表示させる(VBで非同期処理をおこなう)ためです。
COM自体の信頼性が低いということであれば、ActiveX EXEでおこ
なっている処理を標準EXE側に組み込む方向で考えようと思います。
とりあえず、最初に提示したApp.OLERequestPendingTimeoutプロパティや
App.OLEServerBusyRaiseErrorプロパティなどについて調べましたか?
これらは、メッセージを介してのメソッドやイベントの通知に失敗する
ことがありえるからこそ、それに対応するために存在しているプロパティ
ですよ。
MSDNで、
Component Object Model (general)
COM SDK Documentation
COM
COM Fundamentals
Guide
COM Clients and Servers
Inter-Object Communication
辺りを読んでみるとか。他にIMessageFilterの説明などもヒントに
なるでしょう。
で、
データの送受信を、UIを持たないActiveX EXEで、
UIは標準EXEで、
という組み方そのものは、さほど問題がないと思われます。
プロセス間のやりとりの量・頻度を、それ相応にしておけば
大抵は大丈夫ですよね。
こういうときは、あまりUIにこらない、妥協する、ということ
も重要です。その画面の点滅というのはかなり気になる処理
ですが、そこでメッセージループに入るのを妨げている、と
いうことはありませんか?
別にActiveX EXEだけに限りませんが、非同期(スレッド・
プロセス)間通信にはゆとり・余裕が必要です。それなのに、
同スレッド内でのオブジェクト間の通信と全く同じ手法で
行っているように見受けられます。
K.J.K.さん
色々と助言を頂き、ありがとうございます。
> とりあえず、最初に提示したApp.OLERequestPendingTimeoutプロパティや
> App.OLEServerBusyRaiseErrorプロパティなどについて調べましたか?
> これらは、メッセージを介してのメソッドやイベントの通知に失敗する
> ことがありえるからこそ、それに対応するために存在しているプロパティ
> ですよ。
ヘルプを確認しましたが、「それに対応するために存在しているプロパティ」
と読み取ることができていませんでした。。。
また、提示されましたMSDNのCOMの部分ですが、翻訳サイトで和訳しつつで
苦戦しています。
> その画面の点滅というのはかなり気になる処理
> ですが、そこでメッセージループに入るのを妨げている、と
> いうことはありませんか?
確かに、ActiveX EXEからのイベントを受信待ちの間、forループに入って待機
しています。
この部分をforループではなく、ある程度の間隔でタイマー監視するように
修正したいと思うのですが、修正規模が大きくなるために躊躇しています。
今後の方針としては、以下の2つで考えています。
①ActiveX EXEの存在チェックを外す
②ActiveX EXEをActiveX DLLへ変更する、まはた標準EXE内へ組み込む
K.J.K.さんのおかげで、いくつかの原因が見えてきました。
また、何かありましたらコメントを頂ければと思います。
Forループで待機(Sleepもしくは空回し)というのは、
Windowsアプリとしてはかなり問題のあるコードです。
コンソールアプリではないのですから。
Windowを持っているスレッドでは、待機にはメッセージ
ループを止めないMsgWaitForMultipleObjects(Ex)を
用いてください。SleepやWaitForSingleObject(Ex)、
WaitForMultipleObjects(Ex)では、明示的に処理しない
限り、キューにたまったメッセージを処理する機会が
与えられません。
K.J.K.さん
何度もアドバイスを頂きありがとございます。
本件ですが、以下の理由により、一旦解決とさせて頂きます。
①修正すべき項目がある程度判明した
②再現条件が明確になっていない
上記②については、当方にて確認すべき内容であり、その上で修正作業
が必要と考えています。
また質問させて頂くこともあるかと思いますが、宜しくお願い致します。
解決マークを付け忘れました。。。
編集 削除