空談録

世界で5人くらいに役立ちたい

C# を使ってOneNoteで動作するアドインを作る(※)

最近OneNoteしか触ってません。Power Query……

VSTOではOneNoteで動作するアドインが作れません。ググると2010向けとか出てきますがいまいち2013向けで動くアドインの作り方…がわからず
そんなこんなで一度あきらめたのですがレジストリキーでググったら求めてた情報があったのでまとめときます
英語が読めるぜ!って方は OneNote programming をどうぞ
…forum = appsforofficeとは…??

プロジェクト関係は http://www.malteahrens.com/#/blog/howto-onenote-dev/ を参考に

先に言っときますが普通のVSTOアドインのように公開できません。
公開はできますけど…うーん、使用方法が不明
ただし日本は除きません

プロジェクトの作成

まずVisual Studioの新規プロジェクトから「クラス ライブラリ」を選択します。言語は今回はC#にしときます

出来上がったら参照の追加で次のものを追加しましょう

・Extensibility (アセンブリ/拡張)

Microsoft Office 15.0 Object Library (COM/タイプ ライブラリ)
Microsoft OneNote 15.0 Object Library (COM/タイプ ライブラリ)

・System.Drawing (アセンブリ/フレームワーク)
・System.Windows.Forms (アセンブリ/フレームワーク)

Extensibilityは必須。下2つはリボン操作で重要です。Office 15.0 Object Libraryを使わないなら不要
2,3個目は不要にもできる可能性があります。よくわからなければ追加

参照の追加をしたら適当にコードを書きましょう
下のコピペでもなんでも

[Guid("1A579710-5307-4ADC-BBE9-CA4227A00872"), ProgId("TestOneNoteAddin.Connect")]
public class Connect : IDTExtensibility2, IRibbonExtensibility
{
}

GuidAttributeの中には各自で変更してください。値についてはguidgenで
サンプルなので適当に突っ込んでありますが
ProgIdも同様にしてください

コピペするとusingが不足してると思いますのでVisual Studioさんに任せて追加します。インターフェースもそのまま実装してください。
このとき、NotImplementedExceptionを残さないでください。落ちます

IRibbonExtensibilityを追加した場合、GetCustomUIが実装されますが、ここではFluent UIのカスタマイズを行うためのXMLのstringを返す必要があります
中身はいつものxmlです。安心してググってください
え? idMsoがわからない? 
Download Office 2013 Help Files: Office Fluent User Interface Control Identifiers from Official Microsoft Download Center

こんな感じのXMLをリソースとかに置いといてください。resxにxmlファイルを入れる人とstringの中身をxmlにする人がいるらしいです。お好きなほうでいいです

<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" loadImage="OnGetImage">
  <ribbon>
    <tabs>
      <tab idMso="TabHome">
        <group id="testonaddingroup" label="test">
          <button id="testButton" label="test" size="large" onAction="OnTestButtonClick" screentip="addin test button" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

次にOnTestButtonClickを追加します。さっきのConnectのところに追加しましょう

public void OnTestButtonClick(IRibbonControl control)
{
    MessageBox.Show("Ribbon Button Clicked");
}

MessageBoxはSystem.Windows.Formsをusingしといてください
OnGetImage?今はいいです

あとはプロジェクトのプロパティの"ビルド"→"出力"→"COM 相互運用機能の登録"と"アプリケーション"→"アセンブリ情報"→"アセンブリを COM 参照可能にする"の2つにチェックを入れます
AssemblyInfoのGUIDについても書き換える…必要はあるんですかね? わからないので変えましたが

これで「Visual Studioを管理者権限で」ビルドすればプロジェクトの準備完了です
記事をコードと分けてもよかった気がします

追記:このままだとDLLが解放されなくてPCの再起動が必要になります
OnDisconectionに次のコードを足してください

public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
{
    // cli = Microsoft.Office.Interop.OneNote.ApplicationClass
    // cli = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

OneNoteのApplicationを使っている場合はnullにしとかないとたぶんだめです
(さすがに詰みそうなものを試したくはないです…)

レジストリへの登録

これはさっきのフォーラムコピペ

メモ帳なりを起動して次の文面を貼り付けましょう
32bit OSの場合は次のを使用します

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\AppID\{myguid}]
"DllSurrogate"=""

[HKEY_CLASSES_ROOT\CLSID\{myguid}]
"AppID"="{myguid}"

[HKEY_CURRENT_USER\Software\Microsoft\Office\OneNote\AddIns\progId]
"LoadBehavior"=dword:00000003
"FriendlyName"="TestOneNoteAddin"
"Description"="OneNote Ribbon AddIn Sample"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{myguid}]
"DllSurrogate"=""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{myguid}]
"AppID"="{myguid}"

64bit OSの場合は次のを使いましょう

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Wow6432Node\AppID\{myguid}]
"DllSurrogate"=""

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{myguid}]
"AppID"="{myguid}"

[HKEY_CURRENT_USER\Software\Microsoft\Office\OneNote\AddIns\progId]
"LoadBehavior"=dword:00000003
"FriendlyName"="TestOneNoteAddin"
"Description"="OneNote Ribbon AddIn Sample"

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\AppID\{myguid}]
"DllSurrogate"=""

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID\{myguid}]
"AppID"="{myguid}"

myguidにGuidAttributeに入れた値を、progIdにProgIdAttributeに入れた値を入れてください
myguidとprogIdで置換すればいい感じです
{}は消さないでください

置換したらその内容を*.regで保存します
保存したら実行しましょう。レジストリにいろいろ追加されます

.regを実行した後にOneNoteを起動してみます。うまくいけばHomeのところに新しいボタンが追加されるはずです

OnGetImageについて

アイコン追加したい場合これの実装が必要になります。とはいえいろいろとめんどくさいです

某所のサンプルをみるとこんな実装

    /// <summary>
    ///     Implements the OnGetImage method in customUI.xml
    /// </summary>
    /// <param name="imageName">the image name in customUI.xml</param>
    /// <returns>memory stream contains image</returns>
    public IStream OnGetImage(string imageName)
    {
        MemoryStream stream = new MemoryStream();

    // TODO : stream にimageNameに対応する画像を書き込む

        return new ReadOnlyIStreamWrapper(stream);
    }

ReadOnlyIStreamWrapperは ReadOnlyIStreamWrapper.cs - C# OneNote Ribbon addin (CSOneNoteRibbonAddIn) を使用しましょう
これで返すようにすればアイコン表示もできるようになります

WinFormsのフォームを出すのはさっきのところのCWin32WindowWrapperを使ってどうにかすればいいらしいです
こっちも面倒な気がしますが


というわけでとりあえず作り方でした
公開が本当にできません。regasmしたけど無意味だったのであれ
VSのCOM関係のプロパティを有効にしたときに処理が何なのか知らないです
その辺をどうにかできれば公開もできそうですけど現状ソースがないと使えない…

この辺で