Outlook 2010のVSTOを作成しています(2010-2016で動作する必要があります)。私が知る限り、イベントハンドラは決して削除されないという奇妙な問題に遭遇しています。これは、愚かで無駄なイベントハンドラを繰り返し呼び出すことを避けることができないことを意味します。Outlook VSTOで重複イベントハンドラを呼び出さない
問題のコードは、エクスプローラのSelectionChange
イベントのイベントハンドラで発生します。ハンドラは、選択がMailItem
かどうかをチェックし、そうであれば、Reply
、ReplyAll
、およびForward
イベントにハンドラがあることを確認します。ある項目を複数回選択することができるので、hereのパターンに従って、SelectionChange
ハンドラは最初にReply
/ReplyAll
/Forward
イベントハンドラを削除します(イベントハンドラを2回フックしないようにします。クラス実装)。
問題は、これは、SelectionChange
イベントハンドラの起動時に1回呼び出されることを防ぐことではありません。これは、Reply
(または他の応答アクション)イベントハンドラが1回呼び出されることを防ぎません。これは急速に黙々と呼び出されます。私はそれが同期の問題かもしれないと思ったので、私はイベントハンドラを取り除いて、lock
ブロックに追加して無駄にしました。
private void SelectionChangeHandler()
{
Outlook.Selection sel = Application.ActiveExplorer().Selection;
// First make sure it's a (single) mail item
if (1 != sel.Count)
{ // Ignore multi-select
return;
}
// Indexed from 1, not 0. Stupid VB-ish thing...
Outlook.MailItem mail = sel[1] as Outlook.MailItem;
if (null != mail)
{
Outlook.ItemEvents_10_Event mailE = mail as Outlook.ItemEvents_10_Event;
lock (this)
{ // For each event, remove the handler then add it again
mailE.Forward -= MailItemResponseHandler;
mailE.Forward += MailItemResponseHandler;
mailE.Reply -= MailItemResponseHandler;
mailE.Reply += MailItemResponseHandler;
mailE.ReplyAll -= MailItemResponseHandler;
mailE.ReplyAll += MailItemResponseHandler;
}
ProcessMailitem(mail);
}
}
そして、あまりにも何度も呼び出されるイベントハンドラ:
private void MailItemResponseHandler (object newItem, ref bool Cancel)
{ // We need to get the responded-to item
// NOTE: There really needs to be a better way to do this
Outlook.MailItem old = GetCurrentMail();
if (null == old)
{ // No mail item selected
return;
}
MessageBox.Show(old.Body);
}
この関数は、最終的には、ダイアログボックスを開くよりも、はるかに有益な何かをするだろうが、それは "のための便利なチェックでした元の正しいメッセージが見つかりましたか? "私は同じダイアログボックスを何度も何度も繰り返してはいけません。
何か間違っていますか?これはOutlookまたはVSTOのバグですか?誰でも、重複したイベントハンドラの呼び出しを避ける方法を知っていますか?
OK、私はおそらく、変数が 'SelectionChangeHandler'の呼び出しの間にガベージコレクションを取得することと関係していると思います。これは、イベントハンドラの登録抹消が機能しないことを意味します。しかし、 'mailE'が別の' MailItem'を指し示すようになったらすぐにガベージコレクションを取得できませんか?いずれにしても 'ReleaseComObject'と何が関係しているのかよくわかりません。あなたは何が起こっているのか分かっているようですので、これらのステップがなぜ機能するのかをもう少し説明できますか?なぜ私は盲目的に変更を適用していないのですか?ありがとう! – CBHacking
いいえ、私が言っているのは、変数がローカルであり、予測不可能な時点でガベージコレクションされるということです。そうであれば、変数がクラスレベルにあることによって生きていなければイベントは発生しません。しかし、それがリリースされる前に、2つ目の通知を取得し、2つの変数(同じ項目を指す両方)から同時にイベントをシンクすることは可能です。それが修正しようとしている問題です。 –
ああ、私は見ていると思う。選択されたMailItemオブジェクトは、以前と同じ.NETオブジェクトではなく、同じOutlookオブジェクトを参照し、イベント処理はOutlookオブジェクトのレベルにあるため、イベントハンドラの削除は機能しません。古いCOMオブジェクトをリリースすることで、.NETオブジェクトを効果的に分解したり、少なくとも不活性化したりすることで、複数の「ライブ」.NETオブジェクトから離れることができます。私が正しいと分かっていれば、イベントハンドラの削除は必要ありません。私はこれを今正しく持っていますか? – CBHacking