【VSTO】選択中のメールアイテムを取得する

(VSTO Outlook selected mail item)
OutlookのメールをCSVに出力したいって話が出たのでやってみました。

その話は突如やってきた要件
Outlookで受信したメールをCSVに出力してExcelで管理したい」

(゚Д゚;)

(;つД⊂)ゴシゴシ

(゚Д゚)え?

なんか、いろいろ間違った業務設計をされているようですが、面倒なのでスルー
とりあえず、選択したメールをCSVに出力するものを作りました。

実装(ビジュアルデザイナ)

ビジュアルデザイナで簡単にボタンイベントを実装しました。

private void button1_Click(object sender, RibbonControlEventArgs e)
{
  var explorer = base.Context as Microsoft.Office.Interop.Outlook.Explorer;
  foreach (var item in explorer.Selection)
  {
    if (item is MailItem)
    {
      var mail = item as MailItem;
      
      //mailオブジェクトから必要な項目をCSVファイルに出力する処理
    }
  }
}

実装(XML

XMLでやる場合には、Explorerの取得方法が異なるので注意

private void OnSelectedSave(Office.IRibbonControl control)
{
  var explorer = Globals.ThisAddIn.Application.ActiveExplorer();
  foreach (var item in explorer.Selection)
  {
    if (item is MailItem)
    {
      var mail = item as MailItem;
      
      //mailオブジェクトから必要な項目をCSVファイルに出力する処理
    }
  }
}

(∩´∀`)∩ワーイ
簡単につくれるけど、なんだろ。
高確率でこれを使うような業務か負けな気がする。
なんだよ、メールをCSVに出力してExcelで管理するって・・・

Nugetパッケージでリリース前のパッケージ

Nugetから取得するパッケージは基本的には、安定バージョンですが、プレリリース版(β版とか)も取得出来ます。

プレリリース版は、その名の通り次期バージョンで、公開する側からするとβ版やα版の位置づけです。
プレリリース版の便利なところは、使う側が任意で選択しない限り選択肢として出てこないとこです。
そして、安定版が公開されたらパッケージのアップデートを行えば最新になる楽チン仕様

検証では、自分の環境にNugetサーバーを立てて行いました。
使用したバージョンは下記の通り

NuGet.Server v2.8.60318.667
Nuget.exe v2.8.5

VisualStudioからみたリリース前バージョン

f:id:orzmakoto:20150524144349p:plain

リリース前バージョンの公開方法

リリース前のパッケージとして認識させるには、バージョンの末尾にプレフィックスを付与するだけです。

例)
1.0.0-prereleace
ここでは、-prereleaceとしていますが"-beta"や"-dugfix"などで任意の文字列で構いません。

ただし、Nugetパッケージ管理上のバージョニングと.netのバージョニングの仕様が異なるので不都合が生じることがあります。

Nugetのバージョニング
[メジャー].[マイナー].[パッチ]

.Netのバージョニング
[メジャー].[マイナー].[ビルド番号].[リビジョン]

Nugetのバージョニングは、"Semantic Versioning 2.0.0"とやらに準拠しており3項目から構成されています。
この違いを無視して、プレリリース版用に末尾にプレフィックスをつけると、パッケージファイル(.nupkg)を作成する段階でエラーになります。

警告: パッケージ 'ClassLibrary1' に 1 個の問題が見つかりました。

問題: セマンティック バージョンの使用
説明: バージョン "1.0.0.0-beta" は、セマンティック バージョンのガイドラインに従
っていません。
ソリューション: nuspec ファイルを更新するか、AssemblyInformationalVersion アセン
ブリ属性を使用して、http://semver.org の説明に従ってセマンティック バージョンを
指定してください。

誤) 1.0.0.0-beta
正) 1.0.0-beta

それを踏まえてリリース前のパッケージを作成します。

プロジェクトファイルからパッケージを作成する場合(.nupkg)

AssemblyInfo.csに"AssemblyInformationalVersion"を追加します。

// すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を 
// 既定値にすることができます:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0-beta")]

nuspecファイルをからパッケージを作成する場合(.nupkg)

メタデータ(XML)ファイルを作成する際に、バージョンの末尾にプレフィックスを付与します。

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
    <metadata>
        <id>ClassLibrary1</id>
        <version>1.0.0-beta</version>
        <title>ClassLibrary1</title>
        <authors>Ninomiya</authors>
        <owners>Ninomiya</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Description</description>
        <copyright>Copyright © Ninomiya 2015</copyright>
    </metadata>
    <files>
        <file src="lib\net451\ClassLibrary1.dll" target="lib\net451\ClassLibrary1.dll" />
    </files>
</package>

パッケージ(.nupkg)をパブリッシュ

nuget push ClassLibrary1.1.0.0-beta.nupkg -s http://********/ {apikey}

(∩´∀`)∩ワーイ

ただこのリリース前のパッケージバージョン問題って抜け道がありました(´・ω・`)
パッケージ(.nupkg)を作成するのに、コマンドラインではなくNuGet Package Explorerからメタデータを編集して、[FILE] > [Export...]とすれば、”1.0.0.0-beta”でもパッケージファイルが作成出来てそのままパブリッシュできるんですよね。

NuGet Package Explorer
f:id:orzmakoto:20150524160158p:plain

VisulaStudio パッケージの管理
f:id:orzmakoto:20150524160410p:plain


検証には、自分の環境にNugetサーバーを立てて検証しました。
簡単でいいですね。とってもいい。

MSBuildを使ってクロスターゲットビルド

(Msbuild .net version target)
常に最新の.Net環境を使う事ができればいいのですが、どーしても未だに.Net3.5の環境とか残っています。
もちろん、最新の4.5.2の環境もあります。

そんな時どうします?

1つは、ターゲットランタイム別にプロジェクトを作成してリンクファイルでCSファイルを共有する方法。
ちょっと手間はかかりますが、バージョン別に新機能を盛り込めたり、一般的な方法だと思います。

とは別にMsBuilsを使用してバージョンを指定しビルドすることも可能です。

そもそも.Netバージョンってどこで決まるの?

正確には、ターゲットフレームワークバージョンといいます。
VisualStudio上で確認
f:id:orzmakoto:20150517011731p:plain

csprojファイルで確認
f:id:orzmakoto:20150517012020p:plain

VisualStudioでビルドしてできたDLLをデコパイルしてみる
f:id:orzmakoto:20150517013334p:plain

な感じ。
4.5ってなってますね。

Msbuildでターゲットフレームワークバージョンを指定する

ターゲットフレームワークバージョンを4.0に変更してビルドしてみます。

SET MSBUILD="C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"

%MSBUILD% ClassLibrary1.csproj /p:TargetFrameworkVersion=v4.0 /p:Configuration=Release /t:Rebuild

/p:TargetFrameworkVersion=v4.0
ビルドパラメーターでTargetFrameworkVersionを指定します。

ビルドしてできたDLLをデコパイルしてみる
f:id:orzmakoto:20150517142438p:plain

ちゃんと4.0になっていますね。
(∩´∀`)∩ワーイ

ただ、この方法だと、開発時に4.0と4.5での言語バージョンを意識しないといけません。
4.5で導入されたasync/awaitを使用していると当然ですが、4.0でビルドした時には構文エラーになります。

そろそろ4.0は卒業したい。
まだ3.5もやっている。



ちなみに、デコンパイラはJustDecompileを使用しています。www.telerik.com
ILSpyも軽量シンプルでいいですがこっちのほうが好きです。

【VSTO】既存のリボンにグループを追加する

(VSTO Outlook idMso Customize Ribbon TabMail GroupMailNew)

新規にカスタムリボンをOfficeアプリに追加する場合には、リボンの追加をします。
そうではなく、元々あるタブにボタンの追加など行うこともできます。

そして残念ながら、Ribbon(XML)でしかできません。

新規作成の横にグループを追加

グループ追加イメージ

f:id:orzmakoto:20150511003610p:plain

Ribbon1.cs

public string GetCustomUI(string ribbonID)
{
  if (ribbonID == "Microsoft.Outlook.Explorer")
  {
    return GetResourceText("OutlookAddIn.Ribbon1.xml");
  }
  return "";
}

Ribbon1.xml

<ribbon>
  <tabs>
    <tab idMso="TabMail">
      <group id="MyGroup" insertAfterMso="GroupMailNew" 
           label="MyGroup" autoScale="true">
        <button id="MyButton" label="ボタン" 
            size="large" onAction="RibbonTest"/>
        <button id="MyButton2" label="ボタン2" 
            size="large" onAction="RibbonTest"/>
      </group>
    </tab>
  </tabs>
</ribbon>

ここで大事なのが、idMsoです。

idMsoは、Officeアプリの中でユニークなオブジェクトIDです。Officeアプリの中では、idMsoによって動き(挙動、表示箇所、アイコンなど)が決められています。

<tab idMso="TabMail">

と指定しているので、タブの中に記述したGroupやその中のButtonがOutlookのホームタブに表示されるようになります。
Outlookに表示される内容は、元々のタブメニューXMLで記述したタブになります。

MyGroupが新規作成の隣に来ているのは、insertAfterMsoを指定しているためです。
リファレンスを見ると

insertAfterMso:後に挿入するビルトイン コントロールの ID。InsertBeforeMso、InsertAfterQ、InsertBeforeQ とは相互排他的関係。

となっています。指定したidMsoのあとに表示されますってこと。
逆に、指定したidMsoの前に表示させたい場合には、insertBeforeMsoを使います。

idMsoの値の一覧はMSからダウンロードできます。
Download Office 2013 Help Files: Office Fluent User Interface Control Identifiers from Official Microsoft Download Center
Outlookにかぎらず拡張可能なすべてのOfficeアプリのidMsoが載っています。


(´・∀・`)ヘー
Outlook添付ツールもタブの追加じゃなくてグループの追加のほうが良かったかもしれない。