たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

Visual Studioのビルド成功時にメモ帳を起動する

VisualStudioのビルド成功時にメモ帳を起動する

おいVSIX

Visual Studio拡張機能を少しずつ作ってる。なんもわからん

開発対象にしてるのはVS2017

Visual Studioのビルド成功時にメモ帳を起動する

今回はビルド成功時に発火するイベントを用いて色々するやつ。ビルド成功したときにメモ帳が出て何がうれしいんだ?って感じだけど分かりやすい例としてね

めちゃくちゃ分かりやすいリファレンス(怒)はここ
BuildEventsClass Class

OnBuildDone/Beginイベント

OnBuildDoneはビルドが終了したときに発火するイベントで、OnBuildBeginはビルドが始まったときに発火するイベント。まあそのままですね

この二つに登録できるメソッドは第一引数にvsBuildScope列挙型と第二引数にvsBuildAction列挙型を持ってるやつだけ。つまり以下みたいなやつ

private void OnBuildDoneEvent(vsBuildScope scope,vsBuildAction action){
    //なんかの処理
}

vsBuildScope 列挙型はリファレンスによると Represents the scope of the build. らしい。ふーんなるほどねすべて理解した。それとvsBuildAction列挙型は同リファレンスによるとRepresents the type of build action that is occurring, such as a build or a deploy action.らしい。なるほどなるほど

こういうのはインテリセンス見たほうがはやいんですよ

buildevent2.PNG

vsBuildScopeはどうやらバッチビルドなのかソリューションのビルドなのかプロジェクトのビルドなのかを示してるらしい。そのままだったw

buildevent3.PNG

vsBuildActionはどんなビルドだったのかが分かるらしい。これもそのままだったw ていうかよくみたらビルドメニューのドロップダウンと一緒だった

buildevent4.PNG

OnBuildProjConfigDone/Beginイベント

こいつらはOnBuildDone/Beginとほぼ同じタイミング(こっちのが先)で発生するが、ソースコードが変更されたなどでビルドし直さないといけないときにしか発生しない。つまり

buildevent1.PNG

こんな風にビルド時[出力ウインドウ]に正常終了が出てる時しか発火しない。1文字もソースを変更せずにビルドしたときは変更不要になるのでこのイベントは起きない

これに登録できるメソッドは引数が結構多いから下を見てくれ

private void OnBuildProjConfigDoneEvent(
                    string Project,
                    string ProjectConfig,
                    string Platform,
                    string SolutionConfig, 
                    bool   Success
) {
        //挟みこみたい処理
}

割と引数の名前が分かりやすいので何が入ってるかわかる。個人的に重要だと思ってるのは最後のbool値。変数名からわかると思うけどSuccessにはビルドが成功したかが入ってる。今回はこれがtrueの時にメモ帳を起動すればOKということ

というわけでビルド成功時にメモ帳を起動したいなら

private void OnBuildProjConfigDoneEvent(
                    string Project,
                    string ProjectConfig,
                    string Platform,
                    string SolutionConfig, 
                    bool   Success
) {
    if(!Success) return;
    new System.Diagnostics.Process { 
        StartInfo = { 
            FileName = "notepad.exe" 
        } 
    }.Start();
}

たぶんこんな感じになる

イベントハンドラを登録する

作ったメソッドをイベントハンドラとして登録して実際に動かしたい

上4つのイベントはEnvDTE.BuildEventsインターフェイスにあるのでそれをどこからか探してくる必要がある。これにはPackageクラスを継承しているクラスでGetService()メソッドをつかってEnvDTE.DTEインターフェイスを取得してそこから~~・・・・・文章書くのも難しいのでコードを張るね

protected override void Initialize() {
    var dte = (DTE)GetService(typeof(DTE));    //<--DTEインターフェイス取得
    //dteを辿って OnBuildProjConfigDoneにハンドラ登録する。
    dte.Events.BuildEvents.OnBuildProjConfigDone+=OnBuildProjConfigDoneEvent;
}

VSIXを作るとコンストラクタの代わりに上みたいなメソッドを書くのでそこで登録すればいいと思うんだけど、実はこれではダメなんですよ

BuildEventsを持っておかないとダメ

ぼくもこれで動くと思ってたがうんともすんとも言わなくて泣いた。でも色々調べてたら下のにたどり着いた

social.msdn.microsoft.comhttps://social.msdn.microsoft.com/Forums/vstudio/en-US/33ab218f-3e7b-4dd9-b2a2-d5df04fefa6f/why-is-onbuilddone-event-not-firing?forum=vsx

どうやらPackageクラスの継承先で参照を持ってないとダメらしい。VS2017のテンプレで作成したなら{ProjectName}Package.scってソースだ(たぶん)

なので

public BuildEvents BuildEvent {get;set;}
protected override void Initialize() {
    var dte = (DTE)GetService(typeof(DTE));    //<--DTEインターフェイス取得
    //dteを辿ってBuildEvents取得
    this.BuildEvents=dte.Events.BuildEvents;
    //はい
    this.BuildEvents.OnBuildProjConfigDone+=OnBuildProjConfigDoneEvent;
}

これでOK

img

おっ起動したな

OnBuildDoneのときもメモ帳起動したい

今のままだとソースが変更されていて、新たにビルドしたときしかメモ帳が起動しないのは簡単にわかると思う。
ぼくは変更不要の時もメモ帳起動してほしかったのでOnBuildDoneにも登録したかったけど二重起動しちゃうし、そもそもOnBuildDoneは失敗時にも発火するのでダメ!ぼくは成功時だけがいいの!

まあでもこれはboolをフィールドに持っていれば済む話で

private bool lastStatus = true;

private void OnBuildDoneEvent(vsBuildScope sc,vsBuildAction ac){
    if(lastStatus) WakeNotepad();
}

private void OnBuildProjConfigDoneEvent(/* 略 */){
    lastStatus=Success;
}

private void WakeNotepad() => new System.Diagnostics.Process { StartInfo = { FileName = "notepad.exe" } }.Start();

上にも少し書いたけどOnBuildDoneOnBuildProjConfigDoneより後に発火するのでこうやって書ける

これをそれぞれのイベントに登録すればおわり!
BuildEventsを持っておかないとだめっていう罠にどっぷりハマって死んでいたけど、これが分かってしまえば他のイベントでも同じようにすることになるのでやった~~~という感じですね

ちなみに他のイベントをまとめたクラスを作っておくとPackageクラスから参照を渡すだけでいいので楽です

今回はここまで