VSTO で追加したメニューの挙動がおかしい件の解決方法が何となく腑に落ちない件について

VSTOを使って、Officeのメニューバー・右クリックメニューに独自の項目を追加できるのですが、この子の挙動がどうもおかしい。 メニューを選択しても設定したコールバック関数が呼ばれない という謎のケースに遭遇。 何がどうなってるの…

// C# コードイメージ
// ctrls に メニューを1個追加する
private void AddMenu(Office.CommandBarControls ctrls)
{
	object missing = System.Type.Missing;

	Office.CommandBarButton button;
	button         = (Office.CommandBarButton)ctrls.Add(Office.MsoControlType.msoControlButton, missing, missing, missing, false);
	button.Caption = "かしら";
	button.Click  +=  new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(button_Click);
}

private void button_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
	MessageBox.Show("からし!!");
}

CommandBarControls.Add() によってメニュー項目が追加され、クリック時の挙動を Click イベントにセットしています。

見た目は正しいんです。 そして、動くんです…が、動かないんです。 私が把握している限り、Excel 2003/2007 で全く動かない、Word 2003 / PowerPoint 2003 だと動きはするんです…が、何回か項目を選択しているといつの間にかコールバック関数が呼ばれなくなります。 動いてたのに動かなくなるとかどういう事なの……


原因

Webで調べてみたところ、原因は……



 button がガベコレされちゃうから反応なくなっちゃうよ!



という話。 ………ってええええ ('A`) VSTO側が CommandBarControls.Add() の中で創った CommandBarButton インスタンス保持していてごにょごにょしてるんじゃないのコレー!? インスタンス管理してるから、VSTOフレームワークの中から Click イベント呼んでるんじゃないのコレー!?

つまりは、

  • 見た目メニューは残っているものの、その項目に対応した CommandBarButton インスタンスVSTO 側で管理していないのでガベコレされちゃう → メニューのコールバックがされない

という話でした。「こんなの絶対おかしいよ」

対策

CommandBarButton を メンバ変数として持たせて、ガベコレの魔の手から救ってあげましょう。

// C# コードイメージ

// クラスのメンバ変数とする
private Office.CommandBarButton button;

// ctrls に メニューを1個追加する
private void AddMenu(Office.CommandBarControls ctrls)
{
	object missing = System.Type.Missing;

	// メンバ変数に保持しておいてあげるのぉぉお"お"お" !!!
	button         = (Office.CommandBarButton)ctrls.Add(Office.MsoControlType.msoControlButton, missing, missing, missing, false);
	button.Caption = "かしら";
	button.Click  +=  new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(button_Click);
}

private void button_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
	MessageBox.Show("からし!!");
}

それだけ。

…エー ('A`)

というわけで

日本語ベースの情報源が無かったように思えたので書いてみた