投稿者「as」のアーカイブ

VisualStudio2013の拡張機能を作る4 -サブメニューとしてコマンドを追加する-

前回でコマンドを増やすことができましたので、これらのコマンドをサブメニューの中に入れたいと思います。

公式サイトの「サブメニューを追加する」をみると

  1. vsctファイルを開いて
  2. IDSymbolを追加して
  3. Menusセクションにサブメニュー用のMenuを追加して
  4. GroupsセクションにGroupを追加して
  5. Buttonsセクションにサブメニューコマンド用のButtonを追加しろ

と書いてあります。

実は社内用の拡張機能を作った際にはこの部分でひっかかり、1,2ヵ月放置していました。

この公式ページの説明どおりにTopLevelMenuという名前のVSPackageを作って、説明どおりにIDSymbolやらMenuやらを追加すれば良かったのですが、説明を斜め読みのまま、

  1. VSPackage1という名前で作ったプロジェクトのvsctファイルの内容を書き換えよう。
  2. とりあえずIDSymbleを追加。
  3. MenusセクションへのMenu追加はコピペしてguidを書き換えよう。
  4. GroupsセクションのGroupを書き換えよう。
  5. 最後のコマンド用Buttonは既に作ったコマンドのParentのidを書き換えて使おう。

ってな感じで進めた結果、まったくサブメニュー化できませんでした。

どこを間違えていたかというと、GroupsセクションにGroupを追加する部分です。「追加」しなければいけないのですが、説明ページの内容に置き換えてしまったわけです。

<Groups>
    <Group guid="guidVSPackage1CmdSet" id="MyMenuGroup" priority="0x0600">
        <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
    </Group>
</Groups>

これを

<Groups>
    <Group guid="guidVSPackage1CmdSet" id="MyMenuGroup" priority="0x0600">
        <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
    </Group>
    <Group guid="guidVSPackage1CmdSet" id="SubMenuGroup" priority="0x0000">
        <Parent guid="guidVSPackage1CmdSet" id="SubMenu"/>
    </Group>
</Groups>

こうしないといけませんでした。

ちなみにid=”SubMenu”はMenuなのでこんな感じです。

<Menus>
    <Menu guid="guidVSPackage1CmdSet" id="SubMenu" priority="0x0100" type="Menu">
        <Parent guid="guidVSPackage1CmdSet" id="MyMenuGroup"/>
        <Strings>
            <ButtonText>Sub Menu</ButtonText>
            <CommandName>Sub Menu</CommandName>
        </Strings>
    </Menu>
</Menus>

で、各コマンド用ButtonのParentをid=”SubMenuGroup”に変更します。

<Button guid="guidVSPackage1CmdSet" id="cmdidMyCommand" priority="0x0100" type="Button">
    <Parent guid="guidVSPackage1CmdSet" id="SubMenuGroup" />
    <Icon guid="guidImages" id="bmpPic1" />
    <Strings>
        <ButtonText>My Command name</ButtonText>
    </Strings>
</Button>
  1. メニュー「ツール」の中にサブメニュー(id=”SubMenu”)を配置するために必要なのがParentを id=”IDM_VS_MENU_TOOLS” にしたGroup(id=”MyMenuGroup”)。
  2. サブメニューの中にコマンドを配置するために必要なのがParentを id=”SubMenu”にしたGroup(id=”SubMenuGroup”)。
  3. 配置するコマンドのParentはGroup(id=”SubMenuGroup”)にする。

サブメニューを親にしてコマンド配置用のGroupを作らないといけないんですね。よく読まずにコマンドの親をそのままサブメニューにしていたためにサブメニュー化できずに放置していました。

こうしてめでたくサブメニューになりました。

2014-01-17_193310

同じようにMenuやGroup、Buttonをもうワンセット作成し、一番上の親になるGroupのParentを以下のようにすればコンテキストメニューへ追加も完了です。

<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>

ショートカットキーの設定は簡単でKeyBindingsセクションにKeyBindingを追加してidに目的のコマンドIDを指定するだけです。修飾キーとして使えるものは入力補完で表示されます。

<KeyBindings>
<KeyBinding guid="guidVSPackage1CmdSet" id="cmdidMyCommand" editor="guidVSStd97" key1="M" mod1="Control Shift" key2="A" mod2="Control Shift" />
    <KeyBinding guid="guidVSPackage1CmdSet" id="cmdidMyCommand2" editor="guidVSStd97" key1="M" mod1="Control Shift" key2="B" mod2="Control Shift" />
</KeyBindings>

こうしてメンバから要望のあったサブメニュー化、コンテキストメニュー化が実現できて、めでたく社内公開できました。

VisualStudio2013の拡張機能を作る3 -コマンドを追加-

引き続きVisual Studioの拡張機能を作ります。

正味の話、前々回のウィザードにしたがって作る部分は公式サイトをみれば一発です。

さて今回は公式サイトの「VisualStudioのメニューバーにメニューを追加する」や「サブメニューを追加する」あたりを参考にしてメニューコマンド増やしたいと思います。

メニューコマンドを追加するにはvsctファイルに記述する。

公式サイトをみると「TopLevelMenu.vsctを開いて編集~」とあり、vsctファイルに色々と書き込むことでメニューを追加したりしています。なので VSPackage1.vsct を編集します。

ちなみにvsctファイルのXMLスキーマリファレンスはこちら

2014-01-16_192532

実行すると、VisualStudioのメニュー「ツール」に My Command name という項目が追加されますが、Buttons にある Button で設定されます。追加される位置は Parent で指定されます。

id=MyMenuGroupを探してみると Groups にid=MyMenuGroupのGroupがあります。そしてその Parent は guid=”guidSHLMainMenu” id=”IDM_VS_MENU_TOOLS” 。

これはvsctファイルに記述が無いですが、VisualStudio上での位置を指定しています。これを変えることで好きな位置にコマンド追加することができます。

例えば、idをIDM_VS_MENU_EDITに変えるとメニューの「編集」にコマンドが追加されます。

<Group guid="guidVSPackage1CmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_EDIT"/>
</Group>

その他のguidやidはこちらをご参考に。

さて、サクッとコマンド「My Command name 2」を追加しましょう。

SymblosのGuidSymbolの中に My Command name のid、cmdidMyCommandがありますのでこれを参考に「My Command name 2」用のcmdidMyCommand2を追加します。

<GuidSymbol name="guidVSPackage1CmdSet" value="{0347ac17-ebae-4ec3-b6bb-72a5ba8a702c}">
    <IDSymbol name="MyMenuGroup" value="0x1020" />
    <IDSymbol name="cmdidMyCommand" value="0x0100" />
    <IDSymbol name="cmdidMyCommand2" value="0x0102" />
    <IDSymbol name="cmdidMyTool" value="0x0101" />
</GuidSymbol>

Buttonsにコマンドのボタンを追加。Iconのidを変えてアイコンも変更してみました。ButtonのpriorityはParentに追加される順番になります。試しにcmdidMyCommandのpriorityよりも前になるように設定しています。

<Button guid="guidVSPackage1CmdSet" id="cmdidMyCommand2" priority="0x0001" type="Button">

    <Parent guid="guidVSPackage1CmdSet" id="MyMenuGroup" />
    <Icon guid="guidImages" id="bmpPic2" />
    <Strings>
        <ButtonText>My Command name2</ButtonText>
    </Strings>
</Button>

vsctファイルを弄っただけでコールバックメソッド等を記述していませんが、実行してみます。

2014-01-16_200936

バッチリです。
ちなみにクリックしても何も起こりません。まずは「My Command name」と同じ動作をするようにしてみます。

コールバックメソッドが記述されている VSPackage1Package.cs を開いて Initialize() メソッドに追加。

CommandID menuCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet, 0x0102);
MenuCommand menuItem2 = new MenuCommand(MenuItemCallback, menuCommandID2);
mcs.AddCommand(menuItem2);

CommandIDに渡すIDはPkgCmdIDListに定義するのが正しいのでしょうが、とりあえずベタ書き。変数もこんなネーミングをしていると殴られます。気をつけましょう。コールバックメッソッドとしては「My Command name」と同じにしています。

前回、エディタにHello, World.と追加するように変更していましたが、メッセージボックスを表示するように戻しておきましょう。

実行して、「My Command name2」をクリック。

2014-01-16_202340

上手くいきました。

MenuCommandに渡すコールバックメソッド(イベントハンドラ)を変えればめでたくコマンドの追加完了です。

でも、メニュー「ツール」に自作コマンドがポコポコ追加されても邪魔なのでサブメニュー化したいものです。

というわけで次回はサブメニュー化とコンテキストメニューへの追加、ショートカットキーの設定を行いたいと思います。vsctファイルとの格闘です。

VisualStudio2013の拡張機能を作る2

前回はウィザードに従うだけでしたが、とりあえずコマンドが一つ追加される拡張機能ができました。

コマンドの中身はコールバックメッソッドを弄れば好きに変更できます。古式ゆかしく、”Hello, World.” してみましょう。といってもウィザードで自動生成されたコードがメッセージボックスを表示する様になっているので出力されるテキストを書き換えるだけですが。

ウィザードが生成したコードでは「MenuItemCallback」というメッソド名になっています。
2014-01-15_193751

MenuItemCallbackの中身、表示されるメッセージを変更して。

private void MenuItemCallback(object sender, EventArgs e)
{
    IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
    Guid clsid = Guid.Empty;
    int result;
    Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
               0,
               ref clsid,
               "VSPackage1",
               "Hello, World.",
               string.Empty,
               0,
               OLEMSGBUTTON.OLEMSGBUTTON_OK,
               OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
               OLEMSGICON.OLEMSGICON_INFO,
               0,        // false
               out result));
}

デバッグ実行。ツールメニューから「My Command name」をクリック。
2014-01-15_194206

2014-01-15_194223

メッセージボックスのテキストを書き換えただけでは寂しいので、エディタの現在行に出力してみます。

private void MenuItemCallback(object sender, EventArgs e)
{
    var dte = GetService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE)) as EnvDTE80.DTE2;
    var selection = dte.ActiveDocument.Selection as EnvDTE.TextSelection;
    selection.Insert("Hello, World.");
}
 

デバッグ実行して、適当なファイルを開き、コマンドを実行。
2014-01-15_195342

無事Hello, World.されました。
2014-01-15_195345

次はコマンドを増やしていきたいと思います。

VisualStudio2013の拡張機能を作る

社内の開発環境をVS2010からVS2013に乗り替えようかという話になりまして、そこで困ったのがマクロです。
VisualStudioのマクロ機能はVS2012から削除されているんですね。

数は多くないのですが、社内コーディングルールに合わせた入力補助機能をマクロで実現していたので使えなくなると少しばかり不便です。

そこで拡張機能を作成することにしました。

Visual Studio SDK をインストールする

拡張機能を作成するにはVSで新しいプロジェクトの作成で「その他のプロジェクトの種類」→「拡張機能」から「Visual Studio Package」を指定しますが、初期状態ではこのテンプレートが表示されません。

MicrosoftからVisual Studio SDKをダウンロードしてインストールする必要があります。
http://www.microsoft.com/en-us/download/details.aspx?id=40758

インストールが完了するとプロジェクトテンプレートにこんな感じで追加されます。

2014-01-14_185932

ウィザードにしたがって拡張機能プロジェクトを作成する

新しいプロジェクトとして「Visual Studio Package」を選択すると、ウィザードが開始します。

適当にNext。
2014-01-14_190318

開発言語を選択します。初期状態ではC++が選択されていますが今回はC#を選択。2014-01-14_190342

会社名や説明といった基本情報を入力。今回はそのままで。
2014-01-14_190354

機能の選択。「Menu Command」にチェックすると、メニュー「ツール」に項目が追加されます。「Tool Window」にチェックをつけるとメニュー「表示」→「その他のウィンドウ」に項目が追加されます。「Custom Editor」にチェックをつけると、ファイル新規作成時の「インストール済」項目にオリジナルの項目が追加されます。「Custom Editor」については詳しく調べていないので使いどころが分かっていません。
2014-01-14_190408

「ツール」に追加される名称とIDを指定。
2014-01-14_190416

「その他のウィンドウ」に追加される名称とIDを指定。
2014-01-14_190421

テストプロジェクトを追加するかを指定して、Finish。
2014-01-14_190450

ウィザードが終わると、こんな感じです。画像は「その他のウィンドウ」から表示されるツールウィンドウのデザイン画面です。XAML。
2014-01-14_191328

何も考えずにデバッグ実行。別のVSが立ち上がるので「ツール」メニューを確認するとウィザードの「Command Option」で指定した項目が追加されています。なぜかデフォルトのアイコンが「x1」なんですよね。
2014-01-14_191601

追加された項目をクリックするとメッセージボックスが表示されます。

今回のプロジェクトではVSPackage1Package.cs の MenuItemCallback() を変えればお好みのコマンドを実行できるわけですね。

こんな感じで開発にC#も使えるし、拡張機能の開発は意外と簡単。と思っていたのですが、ここからが…

以下次回。