【NetOffice】COMアドインの読み込み。LoadBehaviorの詳細

  • 2012.11.20 Tuesday
  • 21:46
JUGEMテーマ:コンピュータ

Source and Project

-----------------------------------------------------------
Summary
アドインをユーザインターフェイスとして使う場合は、LoadBehaviorを3。読み込みに時間がかかるようであれば、16を試してみる。プログラムが呼び出す場合は1を指定すると良い。9は指定してはならない。0は1の無効化,2は3の無効化,8は9の無効化。

-----------------------------------------------------------

【NetOffice】【Excel】NetOfficeが利用できるCOMアドインを作成する。
http://pro.art55.jp/?eid=1304103
【NetOffice】【Excel】Comアドインでコントロールパネルを表示する。
http://pro.art55.jp/?eid=1304104

上記の投稿で、COMアドインを作成する方法を紹介させていただきました。今回は、COMアドインをExcelが読み込むタイミングを制御する方法を紹介させていただきます。ExcelがCOMアドインを利用には

1. COMアドインのdllを用意する。(開発)
2. レジストリーにCOMアドインの情報とExcelにそのCOMアドインの登録を行う。(デプロイ)
3. Excelを起動する。(運用)

3のあるタイミングでCOMアドインを読み込む事になるのですが、これがいくつかのパターンがあります。CodePlexで配布しているNetOffice.DeveloperToolboxを参考にすると



Decide when it has to be loaded
1. Not automatically
2. On demand
3. Load at startup
16. Load first time, then load on demand

と、選択できます。実際には選べる数値は、他に8と9というのもありMSDNを参考にすると

http://msdn.microsoft.com/ja-jp/library/bb386106(v=vs.90).aspx

0 アンロード
アプリケーションは起動時にアドインを読み込みません。ユーザーはアプリケーションの [COM アドイン] ダイアログ ボックスを使用してアドインを手動で読み込むことができます。
1 読み込み済み
アプリケーションは起動時にアドインを読み込みません。ユーザーはアプリケーションの [COM アドイン] ダイアログ ボックスを使用してアドインを手動で読み込むことができます。
2 スタート時に読み込む | アンロード
アプリケーションが起動時にアドインを読み込もうとします。
アドインの読み込みが成功した場合、LoadBehavior の値は 3 に変更されます。
3 スタート時に読み込む | 読み込み済み
アプリケーションが起動時にアドインを読み込もうとします。
アドインの読み込みが成功した場合、LoadBehavior の値は 3 のままです。アドインの読み込み中にエラーが発生した場合は、LoadBehavior の値が 2 に変更されます。
8 必要に応じて読み込む | アンロード
アプリケーションは、ユーザーがアドインの機能を使用するユーザー インターフェイス (UI) 要素をクリックしたときなど、必要な場合のみアドインを読み込みます。
アドインの読み込みが成功した場合、LoadBehavior の値は 9 に変更されます。
9 必要に応じて読み込む | 読み込み済み
アプリケーションは、ユーザーがアドインの機能を使用するユーザー インターフェイス (UI) 要素をクリックしたときなど、必要な場合のみアドインを読み込みます。
アドインの読み込みが成功した場合、LoadBehavior の値は 9 のままです。アドインの読み込み中にエラーが発生した場合は、LoadBehavior の値が 8 に変更されます。
16 最初のスタート時に読み込む
ユーザーが最初にアプリケーションを起動したときに、アプリケーションがアドインを読み込みます。ユーザーが次にアプリケーションを起動したときには、アドインによって定義された UI 要素は読み込まれますが、アドインはユーザーがアドインに関連付けられた UI 要素をクリックするまで読み込まれません。
ユーザーが次にアプリケーションを起動したときにアドインの読み込みが成功した場合、LoadBehavior の値は 9 に変更されます。


で、それぞれ何が違うのかとというところが重要になるので、今回は以下のサンプルコードを用意して実験してみました。

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Extensibility;
using Microsoft.Win32;
using NetOffice.OfficeApi;
using Application = NetOffice.ExcelApi.Application;
namespace Art55.NetOfficeDemo20121120_001
{
    [Guid("15071DAF-177C-4438-9129-4B4DB82BFF84"), ProgId(AddInProcId), ComVisible(true)]
    public class ExcelAddIn : IDTExtensibility2, IRibbonExtensibility
    {
        private const string AddInProcId = "Art55.Excel.ExcelAddIn";
        private const string SubKeyPath = @"Software¥Microsoft¥Office¥Excel¥Addins¥" + AddInProcId;
        private const string AddIName = "ExcelAddIn";
        private const int LoadBehavior = 1;
        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type type)
        {
            try
            {
                // add codebase value
                Assembly thisAssembly = Assembly.GetAssembly(typeof(ExcelAddIn));
                RegistryKey key = Registry.ClassesRoot.CreateSubKey("CLSID¥¥{" + type.GUID.ToString().ToUpper() + "}¥¥InprocServer32¥¥1.0.0.0");
                key.SetValue("CodeBase", thisAssembly.CodeBase);
                key.Close();
                key = Registry.ClassesRoot.CreateSubKey("CLSID¥¥{" + type.GUID.ToString().ToUpper() + "}¥¥InprocServer32");
                key.SetValue("CodeBase", thisAssembly.CodeBase);
                key.Close();
                // add bypass key
                // http://support.microsoft.com/kb/948461
                key = Registry.ClassesRoot.CreateSubKey("Interface¥¥{000C0601-0000-0000-C000-000000000046}");
                var defaultValue = key.GetValue("") as string;
                if (null == defaultValue)
                    key.SetValue("", "Office .NET Framework Lockback Bypass Key");
                key.Close();
                Registry.CurrentUser.CreateSubKey(SubKeyPath);
                RegistryKey regKeyExcel = Registry.CurrentUser.OpenSubKey(SubKeyPath, true);
                if (regKeyExcel != null)
                {
                    regKeyExcel.SetValue("LoadBehavior", Convert.ToInt32(LoadBehavior));
                    regKeyExcel.SetValue("FriendlyName", AddIName);
                    regKeyExcel.SetValue("Description", "デフォルトのシートの枚数が6枚になる。");
                    regKeyExcel.Close();
                }
            }
            catch (Exception)
            {
                Debugger.Break();
            }
        }

        [ComUnregisterFunction]
        public static void UnregisterFunction(Type type)
        {
            try
            {
                Registry.ClassesRoot.DeleteSubKey(@"CLSID¥{" + type.GUID.ToString().ToUpper() + @"}¥Programmable", false);
                Registry.CurrentUser.DeleteSubKey(SubKeyPath, false);
            }
            catch (Exception)
            {
                Debugger.Break();
            }
        }
        public void OnAction(IRibbonControl control)
        {
            if (_application == null)
                return;
            var workbook = _application.Workbooks.FirstOrDefault() ?? _application.Workbooks.Add();
            workbook.Worksheets.Add();
        }
        private Application _application;
        void IDTExtensibility2.OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            MessageBox.Show("OnConnection");
            _application = new Application(null, application);
        }
        void IDTExtensibility2.OnDisconnection(ext_DisconnectMode removeMode, ref Array custom)
        {
            if (null != _application)
            {
                _application.Dispose();
                _application = null;
            }
        }
        void IDTExtensibility2.OnAddInsUpdate(ref Array custom)
        {
            MessageBox.Show("OnAddInsUpdate");
        }
        void IDTExtensibility2.OnStartupComplete(ref Array custom)
        {
            MessageBox.Show("OnStartupComplete");
        }
        void IDTExtensibility2.OnBeginShutdown(ref Array custom)
        {
        }
        string IRibbonExtensibility.GetCustomUI(string ribbonId)
        {
            return ReadRessourceFile("RibbonUI.xml");
        }
        protected internal static string ReadRessourceFile(string fileName)
        {
            Assembly assembly = typeof(ExcelAddIn).Assembly;
            using (Stream ressourceStream = assembly.GetManifestResourceStream(assembly.GetName().Name + "." + fileName))
            {
                if (ressourceStream == null)
                    throw (new IOException("Error accessing resource file"));
                using (var textStreamReader = new StreamReader(ressourceStream))
                {
                    return textStreamReader.ReadToEnd();
                }
            }
        }
    }
}

サンプルコードを簡単に説明すると、

private const int LoadBehavior = 1;
 [ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
    ....
}

で、レジストリに書き込む初期値を指定しています。初期値であるため、後からregedit.exeなどでレジストリーを直接書き換えることも可能です。実験する場合は、レジストリーを直接書き換えた方が早いかもしれません(笑)

string IRibbonExtensibility.GetCustomUI(string ribbonId)
{
return ReadRessourceFile("RibbonUI.xml");
}

で、リボンUIの独自に用意しています。

それではLoadBehavior を変えてみて動きを見たいと思います。

0を使用した場合


Excelを起動しても、今回自作したCOMアドインはExcelAddInという名前なのですが、このCOMアドインは登録はされているものの、読み込まれておらず「アンロード」された状態になっていることがわかります。


1を使用した場合


Excelを起動すると、自作したExcelAddInが読み込まれていることが分かります。


しかし、Excelの画面を見る限りリボンUIが読み込まれていないことが分かります。


つぎは2を飛ばして3

3.を使用した場合


Excelを起動すると








と、Excelを起動した直後にIDTExtensibility2インターフェイスのOnAddInsUpdateメソッド・
OnConnectionメソッド・OnStartupCompleteメソッドとIRibbonExtensibilityインターフェイスで定義したリボンUIの読み込みであるGetCustomUIメソッドが呼ばれていることがわかります。これはExcelを起動するたびに、メッセージが出力されるので、Excelを起動するたびにCOMアドインを読み込んでいると言うことがわかります。

COMアドインダイアログで確認すると、スタート時に読み込むと書かれています。


このチェックを外すと2になり、起動時に読み込まれなくなります。また、起動時に何らかの失敗があった場合も3から2になります。



実際にレジストリの値をみると



スタート時に読み込むの設定でCOMアドインのチェックありが3でCOMアドインのチェックなしが2だということがわかります。

8と9を飛ばして16に行きます。

16を指定した場合
レジストリーの値は16であることが確認できます。


Excelを起動すると











と、ここまでは一緒なのですが、もう一回、Excelを立ち上げると

メッセージボックスは一切出ずに、いきなりExcelが立ち上がるようになります。UIリボンもしっかりと表示されています。(この時点ですでにLoadBehavorは9になっています)


ここでUIリボンのボタンをクリックすると、




と、ボタンを押すことではじめて、IDTExtensibility2インターフェイスのメソッドが呼び出されるようになります。この事からIDTExtensibility2で行っている処理、たとえばNetOfficeのApplicationをnewしたり、別ライブラリーで作成したWinFormのコントロールなどの読み込みがボタンをクリックするまで遅延かできるということがわかります。3は、Excelの起動中にアドインを読み込みをすべて行っていたのに対して、16-9は、1回目の起動は3と同じで、2回目以降は遅延処理して、Excelの起動処理を軽減化させることが可能です。

レジストリを見ると、LoadBehaviorが9になっていることがわかります。





「必要に応じて読み込む(現在は読み込まれていません)」でチェックありになっています。このチェックを外すとLoadBehaviorは8になります。

ということで、まとめると

LoadBehaviorを1にすると、起動時にCOMアドインは読み込まれない。1の無効化が0
LoadBehaviorを3にすると、Excelの起動するたびにCOMアドインを読み込む。COMアドインクラス側から見ると、読み込むとはIDTExtensibility2インターフェイスのOnConnectionメソッド・OnAddInsUpdateメソッド・OnStartupCompleteメソッドを呼び出すことであり、 IRibbonExtensibilityインターフェイスを通じてUIリボンのカスタマイズ設定を読み込む事である。3の無効化が2
LoadBehaviorを16にすると、16してから一回目のExcelの起動時は3と同じ評価がされる。ただし、2度目の起動ではLoadBehaviorは、9になっており、IDTExtensibility2インターフェイス・IRibbonExtensibilityインターフェイスの評価は起動のタイミングでは行われなり、カスタムリボンUIに設定したボタンなどをクリックしてはじめてIDTExtensibility2インターフェイスが評価される。
ちなみにいきなり9を指定して、レジストリー登録してしまうと、リボンUIが評価されないため、不完全な状態でインストールされてしまうので注意がひょつようです。そのため、NetOffice.DeveloperToolboxでは0,1,2,3,16が指定可能になっているものと思われます。

つまり、

アドインをユーザインターフェイスとして使う場合は、LoadBehaviorを3。読み込みに時間がかかるようであれば、16を試してみる。プログラムが呼び出す場合は1(あまり自身がない)を指定すると良い。

IDTExtensibility2は.NET Frameworkに含まれているクラスですが、IRibbonExtensibilityはNetOfficeのライブラリーなので、どうも腑に落ちないところもあるのですが、今回の動作検証では、なんか動いてるとしか言いようがありません。

以上

Source and Project
コメント
コメントする








    
この記事のトラックバックURL
トラックバック

calendar

S M T W T F S
1234567
891011121314
15161718192021
22232425262728
2930     
<< April 2018 >>

あわせて読みたい

あわせて読みたいブログパーツ

selected entries

categories

archives

recent comment

  • 【キーボード】6年前のRealForceを復活させることはできる!?その3
    art55 (05/22)
  • 【キーボード】6年前のRealForceを復活させることはできる!?その3
    分解大好き (05/18)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    art55 (02/04)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    Gen (02/04)
  • 【キーボード】RealForce が壊れて帰ってきた。
    art55 (04/29)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    art55 (02/23)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    かるあ (02/22)
  • 【C#】Dictionaryの実装・データ構造・アルゴリズムを観察する。
    art55 (01/16)
  • 【C#】Dictionaryの実装・データ構造・アルゴリズムを観察する。
    karuakun (01/16)
  • 【NetOffice】【Excel】死なないExcelプロセスをKillする。
    art55 (12/05)

recent trackback

recommend

recommend

recommend

C#プログラマのための.NETアプリケーション最適化技法 (Programmer's SELECTION)
C#プログラマのための.NETアプリケーション最適化技法 (Programmer's SELECTION) (JUGEMレビュー »)
Sasha Goldshtein,Dima Zurbalev,Ido Flatow,サシャ・ゴルドシュタイン,ディマ・ズルバレフ,イド・フラトー

recommend

ろんりと集合
ろんりと集合 (JUGEMレビュー »)
中内 伸光
とてもわかりやすいです。

recommend

recommend

シャノン・ノイマン・ディジタル世界
シャノン・ノイマン・ディジタル世界 (JUGEMレビュー »)
市川 忠男
4章がリレーショナルデータベースな内容になってます。ページ数があまりありませんが、ポイントがものすごく的確にまとまっていて、感動します。

recommend

recommend

東プレ Realforce91UBK-S 静音キーボード 静電容量無接点方式 変荷重 ブラック NG01BS
東プレ Realforce91UBK-S 静音キーボード 静電容量無接点方式 変荷重 ブラック NG01BS (JUGEMレビュー »)

テンキーレス、静音のRealForce91UBK-S。スコスコ感がたまらなく気持ちいいです。家と会社で2台持ってます。

recommend

recommend

プログラミング.NET Framework 第4版 (プログラミングシリーズ)
プログラミング.NET Framework 第4版 (プログラミングシリーズ) (JUGEMレビュー »)
Jeffrey Richter
発売予定美 2013年10月10日。.NET Frameworkとお付き合いする人のバイブルですね。

recommend

recommend

キャット・シッターの君に。
キャット・シッターの君に。 (JUGEMレビュー »)
喜多嶋 隆
私のイラストレータデビュー本です。

recommend

Essential .NET ― 共通言語ランタイムの本質
Essential .NET ― 共通言語ランタイムの本質 (JUGEMレビュー »)
ドン・ボックス,クリス・セルズ,Don Box,Chris Sells,吉松 史彰

links

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM