EXEからActiveXDLLに処理を投げて、一定時間で処理が終わらなければ処理を中断させたいのですがどうすればいいのでしょうか?
また、処理の結果はどのようにすれば受け取れるでしょうか?
そのまま、
a = hoge(b)
aが結果を受け取る変数、hogeがDLL内の関数、bがパラメタ。
のようにしても型が違うト」エラーが出ます。
DLL内の関数ではLONG型しかつかってません。
よろしくお願いします。
環境
WINXP SP2
VB6
複数の箇所で認識に問題があるような。
VB6でActiveX DLLを作ると、それが外部に提供できるのは、
「動的な関数(メソッド、プロパティ)、イベント、コールバック」
ですよね。
> a = hoge(b)
だと、動的な関数の呼び出しになるのでしょうか?
解決策は2方向にあります。とりあえずInstancingプロパティなど
について調べてみてください。
で、一定時間で処理が終わらなければ...というのに部品として
足りない部分があります。
「一定時間」を認識するのは誰なのでしょうか?
これに対しても、2方向に解決策があります。
ActiveXコンポーネントの中で行うのならば、DoEventsなどを、
もしくはRaiseEventやコールバックインターフェースなどを、
外で行うのならばActiveX EXEについて調べてみてください。
# どちらにしてもそのままというわけにはいきません。
## 呼び出す側もVB6で作成するEXEであると仮定しています。
ActiveX EXE であれば、VB6 ヘルプで紹介されている
『Coffee2.vbp サンプル アプリケーション』の非同期通知処理を
真似ることができます。あるいは下記の手法ですね。
http://www.int21.co.jp/pcdn/vb/noriolib/vbmag/0008/com/
DLL ではなく、OCX での実装でも構わなければ、
AsyncRead メソッド
CancelAsyncRead メソッド
AsyncReadProgress イベント
AsyncReadComplete イベント
などを利用した非同期処理を実装できます。
魔界の仮面弁士さんありがとうございます。
教えていただいたページを参考にして、返り値を
受け取ることができました。
呼び出しもとのEXEはVB6で作成したものです。
一定の時間はこのVB6で作成したEXEで呼び出してから
タイマーを起動して一定時間でキャンセルしたいと考えています。
ActiveX EXEというのはActiveX DLLをActiveX EXEにするということでしょうか?
ActiveX EXE化するかどうか以前に、そのメソッドは
「途中でキャンセルできる」
ように作られているのでしょうか?
実はまだキャンセルできるような風にはできていません。
とりあえず非同期での動作とDLLからの返り値の取得ができてから考えようかと。。。
キャンセルもDLL自身のタイマーなどで終わらせるのではなくEXEから強制的に
キャンセルしたいと思っています。
WMIで起動していないマシンに対してconnectserverするとタイムアウトまでの2分ほど応答がなくなってしまうのでそれをどうにかしたいと思ってます。
CONNECTする前にPINGなどを打てばいいのですが2秒ほどかかってしまうのでそれは避けたいと思ってます。
最初にWNetOpenEnum と WNetEnumResourceでコンピュータ一覧を取得しているのですが、起動していないマシンがあったり処理をしている間にシャットダウンされたりでどうしても存在しないマシン相手に接続することになってしまいます。
ですので、すばやく死活確認ができる、WMIが固まるのをどうにかする、DLL化してDLLごとキャンセルをするのいずれかを実現したいと思っています。
DLL化してマルチスレッドで実行できれば処理も高速化できるのでベストです。
以下は、イベント通知型の非同期処理の処理イメージという事で。
1. コンポーネント側には、以下のメンバを用意。
・処理開始メソッド
・処理中止メソッド
・処理完了イベント
・(必要であれば)処理状況通知イベント
・(必要であれば)処理中かどうかの判定プロパティ
2. 処理開始メソッドは、即座に呼び出し側に制御を返す必要がある。
たとえば、メソッド自体は自身が持つ Timer を起動するだけで完了させ、
実際の処理は、その Timer 側で請け負うようにするなど。
3. 処理が完了したら、最後に「完了イベント」を呼び出して、呼び出し側に
処理が正常(or異常orキャンセル)終了した事を示す。
処理結果はイベント引数によって渡される。
4. 実際の処理中は、定期的に『処理中止メソッドが呼ばれたかどうか』を
チェックして、中止命令が発行されていたら、処理をそこで中止して、
キャンセルされたことを完了イベントにて通知する。
> DLL化してマルチスレッドで実行できれば処理も高速化できるのでベストです。
言語仕様上、その場面でマルチスレッド処理を実装するのは厳しそうです。
スレッドではなく、プロセスを分けるのでは駄目でしょうか?
> WMIで起動していないマシンに対して
なんだか突然、WMI やら ネットワークやらの話が出てきましたが…(汗)
ここでいう ActiveXDLL とは、自作のプロジェクトではなく、
WMI コンポーネントの事だった、というわけではないですよね。
WMIの処理を自作のActiveXDLLで行うということです。
4.の処理だとWMIの処理で反応がないときにはタイマーも動かないので
結局終了は2分後になってしまう気がします。DLL内でキャンセルの処理をする
ためにはWMIのConnectServerをキャンセルしないといけないですが、その方法が今のところわかりません。WQLであればキャンセルできるのですが。。。
今のところ3.間ではできている状況です。
プロセスを分けるということはどういうことでしょうか?
参考にあげていただいたHPで非同期処理にActiveXEXEを使用しているのでActiveXEXE
で作成しようかと思っています。
DLLだと非同期で動きませんでした。
> 結局終了は2分後になってしまう気がします。
処理自体が非同期にさえなっていれば、何分後に終了しても構わないのでは。
2分後に、処理完了イベントが(処理失敗を報告するために)発生するかどうかに
関係なく、呼び出し側が「待ちきれない」と思った時点で、中止メソッドを
発行して、直ちに次の処理を始めてしまえば良いのかな、と思うのですが…。
それとも、同時にひとつの通信しか行えない、という前提条件があるのでしょうか?
> プロセスを分けるということはどういうことでしょうか?
その処理部分を別の exe にしてみてはどうか、という意味です。
標準 exe にして、Shell 等で呼び出すも良し。ActiveX EXE にして呼ぶも良し。
また、その exe を複数同時に起動しても良し、ということで。
マルチスレッドと比べれば、効率面では落ちてしまうでしょうけれども、
VB6 でマルチスレッドプログラミングというのは、聊か無理があるので、
代わりにマルチプロセスにすることで代用できないのかな、と思った次第です。
話が破綻する方向へ引き摺られているような。
別EXEにする・しないに関わらず、
「途中でキャンセルを受け付ける」
構造になっていない限りは、話が先には進めません。
WMIに依存してそうなるのであれば、まずそこから見直すべきです。
安直な「強制終了」は、望ましからぬものですし。
処理自体はマルチプロセスで動かすことができ、現在5プロセスで考えてますが、結局1プロセスでも5プロセスでもWMIが止まるところがネックになって極端な高速化は望めないみたいです。。。。順調であれば数倍は早くなるんですけど。
SET hoge = New Class1
を
SET hoge = Nothing
Class1がActiveXEXEのclass
のようにしてキャンセルできないかと思いましたが、ダメでした・・・。
また、WMIが固まると『他のアプリケーションがサーバーを使用しているため、
この操作を完了できません。操作を続けるには、「切り替え」ボタンを選択して
他のアプリケーションを終了してください。』のエラーが出て手をつけることができないので、呼び出し元から中止メソッドを発行しても受け付けてもらえません。受け付けたとしてもWMIをキャンセルする方法がわかりません。
K.J.K. 様
確かにWMIに依存してますが、設定変更なども含んでいる関係上WMIははずせないんです。
ですので、ActiveXEXEに処理を渡してキャンセルするか、一方的に呼び出し元のEXEでキャンセルするかでないと処理が進みません。
どうしてもWMIを使うというのならば、
1,時間制限の機能を取っ払う。
2,ActiveX EXEではなく、DDE通信を使う。
というようにすべきでしょう。
# まぁ、ActiveXでもエラーとして検出はできますが。
K.J.K.様ありがとうございます。
時間制限の機能というのはどのようにすればいいのでしょうか?
ActiveX EXEにタイムアウトの設定ができるのでしょうか?
また、ActiveXのエラーの検出というのもぜひ教えていただきたいと思います。
いずれも今回もそうですが、今後開発する上で非常に役立ちそうですので覚えて置きたいと思います。
かなり誤解されているので書き直します。
「一定時間で処理が終わらなければ処理を中断させたい」機能を諦めて、
かつ、ActiveX EXEではなくDDEとして実装してください。
で、覚えるも何も、VB6用のMSDNの
「ActiveX コンポーネントの作成方法」
を読みましたか? そこに最低限度必要なことは書いてあります。
当然、ここまで展開したことの根拠も、です。
結局キャンセルはあきらめてPINGで死活確認をすることにしました。
最初はPINGコマンドをリダイレクトしていたので一台あたり2秒ほどかかるとおもっていましたが、
IcmpSendEchoでするとかなり早くなりました。
2000台弱の端末の情報を10分ほどで収集できるようになりました。
K.J.K.さま、魔界の仮面弁士さまありがとうございました。
ツイート | ![]() |