[開発環境:WinXP/98,VB6SP6]
いつもお世話になります。
今回は、メール受信についてお尋ねします。
こちらでもBASP21に関する記事が過去投稿されていますが、今回の質問に
相当するような記事が見つからなかったので質問させて頂きます。
メール受信手段として、現在BSMTP.DLLを使用していろいろと実験していますが、
ここで一般的な話しとしてアドバイス頂けないでしょうか。
大まかに下記のようなコードにより実験しています。
■Form1での処理
Private Sub Command1_Click() '「受信」ボタンをクリック
Form2.Show vbModal 'メール受信用のフォームをオープン
End Sub
■Form2での処理
Private Sub Form2_Activate() 'Form2オープンと同時にメール受信処理開始
'処理1:メールサーバー内の受信メッセージの数やタイトル等を確認。
'処理2:受信ログデータベースに問い合わせて、受信すべきメールを確定します。
' 受信後のメッセージは、メールサーバーにそのまま残しておくことにします。
'処理3:メール受信開始
' 受信すべきメッセージのみを受信し、
' 受信状況を逐次スクロールバーにて表示します。
' 同時に、受信したメッセージの持つ諸情報(タイトルや送信者名等)をデータ
' ベースに書き込みます。
'処理4:なんらかのエラーが発生したら、その旨の
' メッセージをForm2内の表示エリアに表示します。
'処理5:無事受信できたら自動でForm2を閉じ、エラーが発生したら手操作
' でForm2を閉じます。
End Sub
以上のような流れです。
さてここで質問なのですが、今回のように外部のDLLを使ってメールサーバーにアクセスして
いる最中に、仮にForm2を強制的に閉じてUnloadしたい場合、Form2の中のすべての処理を
破棄してForm1に戻るよい方法はないでしょうか。
今の現象としては、
1.メール受信時のコールバック関数で受信キャンセルを有効にしてForm2を×ボタンで閉じる
2.メールサーバーへのアクセスはまだ続いている
3.受信処理が終了してユーザーキャンセルが認識される
4.ユーザーキャンセル時に呼ばれるエラーメッセージ表示のためのサブルーチンが呼ばれる
5.Form2は既に閉じられているので、VBのエラーメッセージが表示され、プログラムが強制終了
あるいは、処理3のデータベース書き込みエラーのメッセージが表示されるが、OKボタン
を押してもプログラムを終了することができない。
5は、Form2を閉じるタイミングにもよるかと思います。
また、メール受信の最中にForm2を強制的に閉じてForm1でプログラムそのものを終了しても、
VBはまだ開放されずに動いています。そして、最後に5と同様の状態になります。
あまり要領を得ない説明で恐縮ですが、エラーの回避方法など是非アドバイス頂けないでしょうか。
えーと。ざっと読んでるし、外部との通信は専門外なので見当外れの部分は
ご指摘下さい。
ざっと読んだ感じ、メール受信と外部DLLは関係ないように思います。
要は Form2 から呼び出した処理の戻り値が Form2 で処理を続けようとした
時に Form2 がアンロードされてて存在しない…って事でいいのかな???
まず、設計が悪いですw。
さらにその前に強制終了という考え方が悪いですw。
前提となる概念を言います。
<<<強制終了は避ける。>>>
VBにも End ステートメントとかいう命令はありますが、使うべきでは
ないというのが常識です。アプリケーションを終了させる時にプロセスを
殺す。…するべきではありません。パソコンの電源を落とす時にコンセント
を引っこ抜く。…するべきではありません。…よね?。
過去ログ検索『強制終了』でどうぞ。
アンロードされてメモリ上から居なくなるのは、全ての処理が終わってから
必要無い状態になってからです。…ではどうするか?
案1:アンロード時のイベントでアンロードをキャンセルし、Form2 非表示状態で
処理を続け、全ての処理が終わった時にアンロードする。
過去ログ検索『アンロード』『Unload』など。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200504/05040129.txt
プログラムが終了しなくなる可能性もありますので、その記事も合わせてお読み下さい。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200406/04060126.txt
案2:Form2 で処理しない。→Form1・その他の生きているクラス・モジュールで処理する。
案3:Form2 の処理を続ける前に Form2 がアンロードされているか?
を調べて Form2 の処理を呼び出さない。
…でもその判定の処理はドコに書くのか?→案2…と同じか…意味ねぇにぁ(^w^;)
サーバーに迷惑です。きちんと終了時は、「QUIT」のコマンドで終わりましょう。
別EXEでメールの受信だけしたらどう?
「×」押されても、非表示にするだけですむし・・・
特攻隊長まるるうさん、id_rsa+さんありがとうございます。
Endを使った強制終了はするべきでないということは、この私も
承知しています。
実際、QueryUnloadにて後始末処理をさせているため、Endをやっちゃうと
それらが実行されないですもんね。
強制終了という言葉がまずかったかなと思いますが、要は、Form2で
処理をやっている最中に、「閉じる」ボタンで受信処理とその関連
の処理を途中キャンセルし、後始末をした上で正常終了したいと
いうことでした。
で、ご紹介のページを参考に検討したんですが、「閉じる」ボタンが
押されたらTimerを起動して終了作業を行い、その後にForm2を閉じる
という方法ではどうかなと思いましたが、もう少し調べてみたいと
思います。
id_rsa+さんがおっしゃるように、「QUIT」のコマンドでサーバーへの
接続が意図的に切断できればいいのですが、BSMTP.DLLのメール受信
関数を発行してしまうと、その処理が終了するまで待っているしか
ないのかなと思います。
この関数の処理を途中で正常キャンセルして、Form2の後始末をした上で
Form2を閉じることができないかと思った訳です。
Winsockを使ってサーバーへの接続をすべて自前でやっていれば、
その辺の操作というのは自分の考え次第でどうにでもなるのかなと思うのですが、
他人の作った関数なので、ブラックボックスとして使うしかない
のでしょうかね。
BSMTP.DLLのフリー版なので、サポートはないしそちらの掲示板でもあまり
動きがないようなので、質問しようにも手立てがありませんでした。
今回の件は、これまでのアドバイスを参考に、あと少し自分なりに検討して
解決を図りたいと思います。
ということで、なんらかの解決ができたらご報告します。
>強制終了という言葉がまずかったかなと思いますが、要は、Form2で
>処理をやっている最中に、「閉じる」ボタンで受信処理とその関連
>の処理を途中キャンセルし、後始末をした上で正常終了したいと
>いうことでした。
え?そうなの???それが
> 1.メール受信時のコールバック関数で受信キャンセルを有効にしてForm2を×ボタンで閉じる
…のように読めたんだけど?
> 3.受信処理が終了してユーザーキャンセルが認識される
この説明だと受信キャンセル処理は正常に終了してるように聞こえる。
> 4.ユーザーキャンセル時に呼ばれるエラーメッセージ表示のためのサブルーチンが呼ばれる
このサブルーチンは当然VB側のもの。そこでエラーが出るなら呼ばなきゃいい
…って解釈にしかならないと思いますが…。
[BSMTP DLL]
http://www.hi-ho.ne.jp/babaq/bsmtp.html
>受信バイト数確認やキャンセルができます
って書いてあるのは受信途中での正常キャンセルの事では無いんだ???
>押されたらTimerを起動して終了作業を行い、その後にForm2を閉じる
>という方法ではどうかなと思いましたが、
いや、そこは QueryUnload だけのサンプルなんてヘルプ見れば
いいだけなんだから過去ログ検索『アンロード』で QueryUnload
に辿り着く紹介で適当な過去ログが無かったからであって Timer
は別に重要じゃないよ(^^;)知ってらしたようなので意味無かったです。
受信途中で×が押されたとき、
QueryUnloadイベント内で、
グローバルなフラグを立てる
フォームのUnloadをキャンセルする
フォームを非表示にする。
コールバック内でグローバルなフラグを見て、受信をキャンセル。
エラーメッセージ表示のためのサブルーチンが呼ばれる
フォームをUnloadする。
って感じにしたいのかと思ってたけど、違うかなぁ??
すみません。
私の説明が要領を得ないために、回答をして頂くのに混乱を招いている感じですね。
> 〜
>> 1.メール受信時のコールバック関数で受信キャンセルを有効にしてForm2を×ボタンで閉じる
>…のように読めたんだけど?
>> 3.受信処理が終了してユーザーキャンセルが認識される
>この説明だと受信キャンセル処理は正常に終了してるように聞こえる。
はい、受信のキャンセルは正常に終了します。でもこれがタイムリーではないんです。
id_rsa+さんがおっしゃるように、コールバック関数の値はグローバルフラグで値を
切り替えて、キャンセルかそうでないかを判断させています。
で、グローバルフラグにキャンセルを設定してすぐさまForm2を閉じると、
コールバック関数により受信がキャンセルされるまでタイムラグがあるために、
Form2が閉じられた後にキャンセルが認識されて、既に閉じられているForm2内のエラーメッセージ
が表示される訳です。
>> 4.ユーザーキャンセル時に呼ばれるエラーメッセージ表示のためのサブルーチンが呼ばれる
>このサブルーチンは当然VB側のもの。そこでエラーが出るなら呼ばなきゃいい
>…って解釈にしかならないと思いますが…。
わかりました。Form2が閉じられていたら、受信キャンセル後のエラーメッセージは呼ばないという
処理を加えればいいということですね。
>[BSMTP DLL]
>http://www.hi-ho.ne.jp/babaq/bsmtp.html
>受信バイト数確認やキャンセルができます
>って書いてあるのは受信途中での正常キャンセルの事では無いんだ???
いえ、正常キャンセルのことを言っています。(はずです)
ただ上述しましたように、タイムリーではないということですね。
メールを受信している最中に「受信停止」ボタンでグローバルフラグをキャンセル
有効に切り替えても、メールのサイズが小さくて受信の速度が速いと、受信箱から
全部受信してしまったりします。
(これは仕方ないのかな?)
>>押されたらTimerを起動して終了作業を行い、その後にForm2を閉じる
>>という方法ではどうかなと思いましたが、
>いや、そこは QueryUnload だけのサンプルなんてヘルプ見れば
>いいだけなんだから過去ログ検索『アンロード』で QueryUnload
>に辿り着く紹介で適当な過去ログが無かったからであって Timer
>は別に重要じゃないよ(^^;)知ってらしたようなので意味無かったです。
はい、わかました。
ところで現在では応急処置として、一連の受信およびデータベースへの書き込み作業が
終了するまで、QueryUnloadや「閉じる」ボタンは無効にし、すべてが済んでから
Form2を閉じれるようにしています。
id_rsa+ さんへ
>受信途中で×が押されたとき、
>
>QueryUnloadイベント内で、
> グローバルなフラグを立てる
> フォームのUnloadをキャンセルする
> フォームを非表示にする。
>
>コールバック内でグローバルなフラグを見て、受信をキャンセル。
>エラーメッセージ表示のためのサブルーチンが呼ばれる
>フォームをUnloadする。
はい、だいたいそのような流れです。
グローバルなフラグは、「停止」ボタンクリック時にキャンセル有効の値を
設定していました。
その直後にForm2を閉じると、これまで話しているような結果になるので、Unloadを
キャンセル→フォームを非表示→エラーメッセージ表示or非表示
とうことになりますでしょうか。
長くなりますので、別記事であと書きます。
あれ? 投稿不能でした。
掲示板がなんかおかしかったので、しばらく投稿を遠慮していました。
今回の件は根本的な解決がまだ図れていませんが、取り合えずForm2で
一連の作業が終了するまでは、×ボタンや「停止」ボタンを無効にする
ことにしました。
すべての処理が正常終了したら自動的にForm2を閉じ、なんらかのエラーが
発生した場合にはその旨のメッセージを表示して、手動でForm2を閉じるようにしました。
ということで、とりあえず今回は解決ということにさせて頂きます。
状況がきちんと整理できましたら、改めて質問させて頂くかも知れません
ので、その時はまたよろしくお願いします。
特攻隊長まるるうさん、id_rsa+さんありがとうございました。
ツイート | ![]() |