【NetOffice】NetOfficeの注意点というかバグ?

  • 2012.12.11 Tuesday
  • 20:38
JUGEMテーマ:コンピュータ

----------------------------------------
Summary
Application.GetActiveInstances();
を実行すると、実行環境によって例外が発生する事がある。

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

英語が、中学生レベルというと中学生に失礼なぐらい英語が苦手なのですが、NetOfficeのバグだと思われるものを見つけたので、何とか報告をあげたいのですが、どうしたものか・・・というかすでに報告ずみなのかもしれないのですが、それすら確認できない(涙)

【NetOffice】方法:起動中の複数のExcelアプリケーションを取得する。
http://pro.art55.jp/?eid=1304139

起動中の複数のExcelアプリケーションを取得する。
Application[] applications = Application.GetActiveInstances();



で、紹介した方法なのです、管理者権限のない状態で、このコードを実行すると例外が発生します。原因はCOMオブジェクトでないものをリリースしようとして例外発生という流れなのですが、単にリリースする前にCOMオブジェクトであるかどうかのチェックが抜けているだけに見えます。

ということで、もう少し詳しく調査していくと、COMオブジェクトではなく、透過プロキシを返すモニカがROTに登録されているようです。

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies;
namespace Art55.NetOfficeDemo20121211_001
{
    class Program
    {
        static void Main()
        {
            object instance = GetNoComObjectInRunningObjectTable();
            var realProxy = (IRemotingTypeInfo) RemotingServices.GetRealProxy(instance);
            Console.WriteLine(realProxy.TypeName);
        }
        [DllImport("ole32.dll")]
        private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
        public static object GetNoComObjectInRunningObjectTable()
        {
            IBindCtx bindCtx;
            if (CreateBindCtx(0, out bindCtx) != 0)
            {
                return null;
            }
            IRunningObjectTable runningObjectTable;
            bindCtx.GetRunningObjectTable(out runningObjectTable);
            IEnumMoniker enumMoniker;
            runningObjectTable.EnumRunning(out enumMoniker);
            IntPtr fetched = IntPtr.Zero;
            enumMoniker.Reset();
            var monikers = new IMoniker[1];  // 一つずつ取得する。
            while (enumMoniker.Next(monikers.Length, monikers, fetched) == 0)
            {
                IMoniker moniker = monikers[0];
                string displayName;
                moniker.GetDisplayName(bindCtx, null, out displayName);
                object comObject;
                if (runningObjectTable.GetObject(moniker, out comObject) == 0)
                {
                    if (Marshal.IsComObject(comObject))
                    {
                        Marshal.ReleaseComObject(comObject);
                    }
                    else
                    {
                        string name = TypeDescriptor.GetClassName(comObject);
                        string component = TypeDescriptor.GetComponentName(comObject, false);
                        Console.WriteLine("Display Name: " + displayName);
                        Console.WriteLine("ClassName: " + name);
                        Console.WriteLine("Component: " + component);
                        Console.WriteLine("COMObject: " + Marshal.IsComObject(comObject));
                        Console.WriteLine();
                        Marshal.ReleaseComObject(enumMoniker);
                        Marshal.ReleaseComObject(runningObjectTable);
                        Marshal.ReleaseComObject(bindCtx);
                        return comObject;
                    }
                }
                Marshal.ReleaseComObject(moniker);
            }
            Marshal.ReleaseComObject(enumMoniker);
            Marshal.ReleaseComObject(runningObjectTable);
            Marshal.ReleaseComObject(bindCtx);
            return null;
        }
    }
}
上記のコードで試してみたなおですが、

Marshal.IsComObject(comObject))

でfalseになるオブジェクトをみると確かに私のPCではCOM以外のオブジェクトが帰ってきます。型を見る限り透過プロキシなので

object instance = GetNoComObjectInRunningObjectTable();
RealProxy realProxy = RemotingServices.GetRealProxy(instance);
Type type = realProxy.GetProxiedType();

リアルプロキシに変換して、Typeを見てみましたが、MarshalByRfObjectが帰ってくるので、うん・・・よくわからない。

実行結果は

-------------------------------------------------
Display Name: !{CC7C96DF-1942-4D46-9FCD-810EF1C56C2D}
ClassName: System.MarshalByRefObject
Component:
COMObject: False
System.MarshalByRefObject
-------------------------------------------------

DisplayName以外は役に立ちそうな情報はなさそうです。ググってみるとAMD Radeon HDのグラフィックカードが引っかかるので、おそらくその辺りで、ROTを使っていらっしゃるみたいです。つまり

http://store.sony.jp/Special/Computer/Vaio/Z/index.html

上記のPCを利用されている方は同一の現象が発生すると思います。

これを管理者権限で実行すると見えなくなるので、例外が発生しなくなるのですが、Excelも管理者権限で実行しているわけではないので、一緒にみえなくなります。それは悲しい(笑)

【NetOffice】Microsoft.Office.Interop.Excelに関して大きな勘違いをしていた。

  • 2012.12.10 Monday
  • 20:19
JUGEMテーマ:コンピュータ

----------------------------------------------
Summary
名前空間 Microsoft.Office.Interop.Excel に定義されているApplicationやWorkbookなどはクラスではなく、インターフェイスです。

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

ものすごくアホな勘違いをしていました。COMオブジェクトを調べて行くうちに腑に落ちない点が一つありまして、Microsoft.Office.Interop.Excel.Applicationは、クラスとして定義されているのでCOMオブジェクトではない、なのになんでMarshal.ReleaseComObjectで解放しなければならないのだろうと。そう思ったんです。知識と知識がどうしてもつながらない。
知ってる人は、アホだなーって思うでしょうけど、私はMicrosoft.Office.Interop.Excel.Applicationをクラスだと思い込んでいました。実は、これインターフェイスなんですね。Microsoft.Office.Interop.Excel.Applicationでラップとか書きましたけど、ラップじゃなくてキャストしてるだけなんですね。気づくの遅すぎた(笑)

Type excelApplicationType = Type.GetTypeFromProgID("Excel.Application");
            Application appliaction = (Application) Activator.CreateInstance(excelApplicationType);

上記のコードを実行すれば、ExcelアプリケーションのCOMオブジェクトをGUIDが000208D5-0000-0000-C000-000000000046で定義されたインターフェイスでキャストしているだけって事なんですね。Microsoft.Office.Interop.Excel.Applicationインターフェイスで定義されているメソッドやプロパティから関連するExcelモデルオブジェクトをたぐってやりたい操作とかできるわけなんですね。

dynamicでCOMオブジェクトをダックタイピング的に操作してるのを見て、なんでだろうなんでだろう不思議だなーって思いつつ、ようやく自分が誤解していることに気がつきました。

てか、今までの中にうそを書いているところがありそうなので、こっそり修正しておきます。



---------------------
昔、new できなのは何でだろうって思ってしらべて「あ!インターフェイスかー」って思ったのを思い出しました。でも、最近、そのことを忘れてしまった・・・または、別物だと思っていた。など、脳内に何らかの障害があったようです。

--------------------------------------
NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】【Excel】NetOfficeのまとめ

  • 2012.12.10 Monday
  • 19:00
JUGEMテーマ:コンピュータ

ここにNetOffice関連の投稿をまとめていきたいと思います。
----------------------------------------------------------------
COMアドイン開発

【NetOffice】【Excel】NetOfficeが利用できるCOMアドインを作成する。
http://pro.art55.jp/?eid=1304103

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

【NetOffice】COMアドインの読み込み。LoadBehaviorの詳細
http://pro.art55.jp/?eid=1304122

【NetOffice】COMアドインを読み込みを失敗させる。回復方法は?
http://pro.art55.jp/?eid=1304124

【NetOffice】リボンの実装からCOMテクノロジをのぞき見る。
http://pro.art55.jp/?eid=1304126

------------------------------------------------------
NetOffice・Excel・COM

【NetOffice】方法:起動中の複数のExcelアプリケーションを取得する。
http://pro.art55.jp/?eid=1304139

【NetOffice】【VSTO】方法:VSTOのExcelアプリケーションオブジェクトをNetOfficeのExcelアプリケーションに変換する。
http://pro.art55.jp/?eid=1304140

【NetOffice】起動中のExcelアプリケーションのCOMオブジェクトを取得し、NetOfficeで利用する。
http://pro.art55.jp/?eid=1304141

【NetOffice】【Excel】死なないExcelプロセスをKillする。
http://pro.art55.jp/?eid=1304142

【NetOffice】Rangeメソッドでセルを指定する(単一・範囲・複数)
http://pro.art55.jp/?eid=1304060

【NetOffice】RowDifferencesで違うセルを見つける。
http://pro.art55.jp/?eid=1304121

【NetOffice】Rangeを返すメソッド・プロパティをまとめてみた。
http://pro.art55.jp/?eid=1304120

【NetOffice】指定したセルの終端セルを探す。Range.Endメソッド
http://pro.art55.jp/?eid=1304129

【NetOffice】【WPF】Worksheet.UsedRangeとRange.Value2プロパティ値の出方を確かめる
http://pro.art55.jp/?eid=1304130

【NetOffice】Worksheet.UsedRangeプロパティから更に値の有無で絞り込むロジック組んでみた。(1)
http://pro.art55.jp/?eid=1304131

【NetOffice】Worksheet.UsedRangeプロパティから更に値の有無で絞り込むロジック組んでみた。(2)
http://pro.art55.jp/?eid=1304132

【NetOffice】Worksheet.UsedRangeプロパティから更に値の有無で絞り込むロジック組んでみた。(3)
http://pro.art55.jp/?eid=1304133

【NetOffice】Worksheet.UsedRangeプロパティから更に値の有無で絞り込むロジック組んでみた。(4)
http://pro.art55.jp/?eid=1304135

【NetOffice】Microsoft.Office.Interop.Excelに関して大きな勘違いをしていた。
http://pro.art55.jp/?eid=1304149

【NetOffice】COMテクノロジを覗きたい!(1)
http://pro.art55.jp/?eid=1304147

【NetOffice】COMテクノロジを覗きたい!(2)
http://pro.art55.jp/?eid=1304148

【NetOffice】COM関連の情報収集。
http://pro.art55.jp/?eid=1304146

【PowerShell】PowerShellからExcelを操作する。
http://pro.art55.jp/?eid=1304145

【NetOffice】方法:NetOfficeで利用したCOMオブジェクトを解放する。
http://pro.art55.jp/?eid=1304144

【NetOffice】方法:NetOfficeやPIAを利用せずdynamicでExcelをオートメーション。
http://pro.art55.jp/?eid=1304143

【NetOffice】【Excel】死なないExcelプロセスをKillする。
http://pro.art55.jp/?eid=1304142

【NetOffice】起動中のExcelアプリケーションのCOMオブジェクトを取得し、NetOfficeで利用する
http://pro.art55.jp/?eid=1304141

【NetOffice】【VSTO】方法:VSTOのExcelアプリケーションオブジェクトをNetOfficeのExcelアプリケーションに変換する。
http://pro.art55.jp/?eid=1304140

【NetOffice】方法:起動中の複数のExcelアプリケーションを取得する。
http://pro.art55.jp/?eid=1304139

------------------------------------------------------
■VSTOのHowToをNetOfficeで実現!
Excel のタスク
基本的なブック タスク

方法 : 新しいブックを作成する
http://pro.art55.jp/?eid=1304068

方法 : ブックを開
http://pro.art55.jp/?eid=1304069

方法 : テキスト ファイルをブックとして開く
http://pro.art55.jp/?eid=1304071

方法 : ブックをアクティブにする
http://pro.art55.jp/?eid=1304072

方法 : ブックを保存する
http://pro.art55.jp/?eid=1304073

方法 : プログラムを使用してブックを電子メールで送信する
http://pro.art55.jp/?eid=1304074

方法 : ブックを閉じる
http://pro.art55.jp/?eid=1304070

方法 : Excel ファイルを開くダイアログ ボックスを表示する
http://pro.art55.jp/?eid=1304076

方法 : ブックの既定の保存場所へのパスを取得および設定する
http://pro.art55.jp/?eid=1304078

方法 : 最近使用したブック ファイルを一覧表示する
http://pro.art55.jp/?eid=1304079

基本的なワークシート タスク
方法 : ワークシートのセルに文字列を表示する
http://pro.art55.jp/?eid=1304080

方法 : ワークシートを選択する
http://pro.art55.jp/?eid=1304081

方法 : 新しいワークシートをブックに追加する
http://pro.art55.jp/?eid=1304082

方法 : ブックからワークシートを削除する
http://pro.art55.jp/?eid=1304083

方法 : ワークシートを非表示にする
http://pro.art55.jp/?eid=1304084

方法 : ブック内のワークシートを移動する
http://pro.art55.jp/?eid=1304085

方法 : ワークシートをコピーする
http://pro.art55.jp/?eid=1304119

方法 : ブック内のすべてのワークシートを一覧表示する
http://pro.art55.jp/?eid=1304086

方法 : ワークシートを印刷する
http://pro.art55.jp/?eid=1304088

方法 : プログラムを使用してワークシート内のデータを並べ替える
http://pro.art55.jp/?eid=1304090

方法 : ワークシートのコメントを追加および削除する
http://pro.art55.jp/?eid=1304091

方法 : ワークシートのコメントを表示する
http://pro.art55.jp/?eid=1304095

方法 : ワークシート内にグループを作成する

方法 : ワークシート内のグループをクリアする
http://pro.art55.jp/?eid=1304096

方法 : コード内でワークシートの範囲を参照する
http://pro.art55.jp/?eid=1304098

方法 : ワークシートのセルに値を送る
http://pro.art55.jp/?eid=1304099

方法 : 現在のユーザーのログオン ID をセルに表示する
http://pro.art55.jp/?eid=1304100

方法 : Excel の範囲内のデータの値を格納および取得する
http://pro.art55.jp/?eid=1304101

ブックのセキュリティ

方法 : ブックを保護する
http://pro.art55.jp/?eid=1304107

方法 : ワークシートを保護する
http://pro.art55.jp/?eid=1304108

方法 : ワークシートの保護を解除する
http://pro.art55.jp/?eid=1304109

方法 : ブックのパスワードを設定およびクリアする
http://pro.art55.jp/?eid=1304110

書式設定
方法 : ブック内の範囲にスタイルを適用する
http://pro.art55.jp/?eid=1304111

方法 : ブック内の範囲からスタイルをクリアする
http://pro.art55.jp/?eid=1304112

方法 : 複数のワークシートにデータと書式設定をコピーする
http://pro.art55.jp/?eid=1304113

方法 : 選択されたセルを含むワークシートの行で書式を変更する
http://pro.art55.jp/?eid=1304114

範囲の使用
方法 : Excel の計算をプログラムで実行する
http://pro.art55.jp/?eid=1304115

方法 : ワークシートでスペルチェックを行う
http://pro.art55.jp/?eid=1304116

方法 : 増分するデータを範囲内に自動的に入力する
http://pro.art55.jp/?eid=1304117

方法 : ワークシートの範囲内のテキストを検索する 
http://pro.art55.jp/?eid=1304118
 
--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用しています。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/
--------------------------------------

【NetOffice】COMテクノロジを覗きたい!(2)

  • 2012.12.10 Monday
  • 00:01
JUGEMテーマ:コンピュータ

Source and Project

腹立たしいことに記事を書いた後に、投稿ボタンをおしたら記事が消えました(涙)書き直しなので、とてもやる気がしません。

-------------------------
Summary
ROT(Runnin Object Table)は、ホストとなるコンピュータで、一つだけ存在します。
ROTは、モニカと実際のオブジェクトを管理しています。
ROTに問い合わせれば、実行中のオブジェクトが何かわかります。

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

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Art55.NetOfficeDemo20121209_001
{
    class Program
    {
        static void Main()
        {
            DipsplayRunningObjectTable();
        }
        [DllImport("ole32.dll")]
        private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
        public static void DipsplayRunningObjectTable()
        {
            IBindCtx bindCtx;
            if (CreateBindCtx(0, out bindCtx) != 0)
            {
                return;
            }
            IRunningObjectTable runningObjectTable;
            bindCtx.GetRunningObjectTable(out runningObjectTable);
            IEnumMoniker enumMoniker;
            runningObjectTable.EnumRunning(out enumMoniker);
            IntPtr fetched = IntPtr.Zero;
            enumMoniker.Reset();
            var monikers = new IMoniker[1];  // 一つずつ取得する。
            while (enumMoniker.Next(monikers.Length, monikers, fetched) == 0)
            {
                IMoniker moniker = monikers[0];
                string displayName;
                moniker.GetDisplayName(bindCtx, null, out displayName);
                object comObject;
                if (runningObjectTable.GetObject(moniker, out comObject) == 0)
                {
                    string name = TypeDescriptor.GetClassName(comObject);
                    string component = TypeDescriptor.GetComponentName(comObject, false);
                    Console.WriteLine("Display Name: " + displayName);
                    Console.WriteLine("ClassName: " + name);
                    Console.WriteLine("Component: " + component);
                    Console.WriteLine("COMObject: " + Marshal.IsComObject(comObject));
                    Console.WriteLine();
                    if (Marshal.IsComObject(comObject))
                    {
                        Marshal.ReleaseComObject(comObject);
                    }
                }
                Marshal.ReleaseComObject(moniker);
            }
            Marshal.ReleaseComObject(enumMoniker);
            Marshal.ReleaseComObject(runningObjectTable);
            Marshal.ReleaseComObject(bindCtx);
        }
    }
}

上記、作成したプログラムで、COMオブジェクトの登録状況を見ていきたいと思います。

■Excelアプリケーションを起動せずに実行してみます。

Visual Studio関連のCOMオブジェクトが表示されますが、Excelっぽいやつは見当たりませんでした。

■Excelアプリケーションを起動して、プログラムを実行してみます。

Display Name: Book1
ClassName: Workbook
Component: Book1
COMObject: True
Display Name: !{00024500-0000-0000-C000-000000000046}
ClassName: Application
Component: Microsoft Excel
COMObject: True

Excelアプリケーションとその中で開かれているブックがCOMオブジェクトとして登録されているのがわかります。

■PowerShellを利用して、COMオブジェクトを操作してみます。
> $application = New-Object -ComObject "Excel.Application"
> $application.Visible = $true;
> $application.Workbooks.Add()
> $worksheet = $workbook.Worksheets.Item(1)
> $worksheet.Range("A1").Value2 = "A1"

Excelアプリケーション・ブック・シート・セルのそれぞれのCOMオブジェクト触っているので、COMとして登録されていると思われます。実際に登録状況をみると

Display Name: Book1
ClassName: Workbook
Component: Book1
COMObject: True
Display Name: !{00024500-0000-0000-C000-000000000046}
ClassName: Application
Component: Microsoft Excel
COMObject: True

Display Name: !{00024505-0014-0000-C000-000000000046}
ClassName: Application
Component: Microsoft Excel
COMObject: True

もっといっぱい出るかなと思いましたが、一つ何か増えただけでした。
ちなみに、00024500-0000-0000-C000-000000000046は、Excel ApplicationのCLSIDのようです。00024505-0014-0000-C000-000000000046はMicrosoft Excel Charting ApplicationのCLSIDです。

■今回、プログラムを作成するに辺り参考にさせていただいた先を紹介します。

Excel ファイルまたは Word 文書の IDispatch を OCX から取得する方法
http://support.microsoft.com/kb/190985/ja

NetOffice
NetOffice 1.5.1.2 [RC]¥Source¥NetOffice¥RunningObjectTable.cs

Source and Project

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】COMテクノロジを覗きたい!(1)

  • 2012.12.07 Friday
  • 06:48
JUGEMテーマ:コンピュータ

NetOfficeというカテゴリーから逸脱してるような気がしますが、NetOfficeのソースコードをかなりの部分で参考させていただいているので、NetOfficeにカテゴリー付けます。

最近、COMが気になって夜も眠れない!状態なのです(昨日、9時頃に寝て6時頃起きました)。で、COMが、まだ全然分かっていないのですが、とりあえずキーワードでもあげてみようかと思います。

COMサーバ
COMクライアント
IUnknown
ROT: Running Object Table
モニカ
COMオブジェクト
OLE

この辺りをきっちり理解して関連づけて話せるようになれば、プログラムが組めるレベルまでいけるのではないかと!と、思うのです。

参考になりそうなサイト
http://msdn.microsoft.com/ja-jp/library/windows/desktop/ms684004(v=vs.85).aspx
http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.comtypes.ibindctx.getrunningobjecttable.aspx


--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】COM関連の情報収集。

  • 2012.12.05 Wednesday
  • 22:26
JUGEMテーマ:コンピュータ

EternalWindows
http://eternalwindows.jp/

COMについて調べていて、見つけました。大昔に知り合いに紹介してもらったような気もしますが・・・
上記のサイト様のCOMの解説が詳細に書かれているのでとても参考になります。もちろんCOM以外も豊富な内容が沢山あります。

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】方法:NetOfficeで利用したCOMオブジェクトを解放する。

  • 2012.12.05 Wednesday
  • 20:03
JUGEMテーマ:コンピュータ

-----------------------------------
Summary
Application.Disposeメソッドを呼び出すとひもづく全てのCOMオブジェクトを適切な順序で解放してくれます。また、この操作ではExcelアプリケーションは終了しません。Excelアプリケーションをコードで終了させたい場合は、Application.Quiteメソッドを使用します。

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

NetOfficeフレームワークは、利用したCOMオブジェクトをフレームワーク上で管理してくれているため、トップレベルのアプリケーションからリリースアクションを起こすことで、関連する全てのCOMオブジェクトを解放してくれます。

やり方は簡単

Application application = ...
application.Dispose();

と、呼ぶだけです。このDisposeメソッドを呼び出すだけで、取得した数々のCOMオブジェクトがリリースされます。自分でここのCOMオブジェクトをリリース順序を気をつけながら、Marshal.ReleaseComObjectしてくなんて事を考え始めたら発狂しそうです。NetOffice様に感謝です。あと、Disposeメソッドを呼び出さなくてもExcelゾンビができないこともあります。この辺り理由は私には分かりませんが、明示的にDisposeは呼び出した方が無難かと思います。もちろんusingセグメントの利用も有効だと思います。

ちなみにDisposeメソッドを呼び出したからと言って、Excelアプリケーションが終了する訳ではありません。終了させたいのであれば、Application.Quiteメソッドを呼び出すと実現できます。

あえてExcelゾンビを作り出す方法。

            Type instanceType = Type.GetTypeFromProgID("Excel.Application");
            dynamic appliactionClass = Activator.CreateInstance(instanceType);
            dynamic application = appliactionClass.Application;
            application.Visible = true;
            dynamic book = application.Workbooks.Add();
            foreach (dynamic sheet in book.Worksheets)
            {
                sheet.Range["A1"].Value2 = "A1";
            }

上記のようにリリースしなければ確実にゾンビが生成できます。

他にもNetOfficeのラッパクラスを使用中にデバックを中止したりするとゾンビが出てきます。

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】方法:NetOfficeやPIAを利用せずdynamicでExcelをオートメーション。

  • 2012.12.05 Wednesday
  • 19:47
JUGEMテーマ:コンピュータ

----------------------------------------
Summary
dynamic変数にCOMオブジェクトを代入することで、ラッパークラスを利用することなく、COMオブジェクトを直接、操作できる。

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

Source and Project

今回は、NetOfficeやPIAを利用せずにdynamicを利用してExcelを操作する方法を紹介します。

using System;
using System.Runtime.InteropServices;
namespace Art55.NetOfficeDemo20121205_006
{
    class Program
    {
        static void Main()
        {
            Type instanceType = Type.GetTypeFromProgID("Excel.Application");
            dynamic appliactionClass = Activator.CreateInstance(instanceType);
            dynamic application = appliactionClass.Application;
            application.Visible = true;
            dynamic book = application.Workbooks.Add();
            foreach (dynamic sheet in application.Workbooks[1].Worksheets)
            {
                Console.WriteLine(sheet.Name);
                Marshal.ReleaseComObject(sheet);
            }
            Marshal.ReleaseComObject(book);
            Marshal.ReleaseComObject(application);
            Marshal.ReleaseComObject(appliactionClass);
        }
    }
}

■指定したプログラム ID (ProgID) に関連付けられている型を取得します。
Type instanceType = Type.GetTypeFromProgID("Excel.Application");

仮にExcel2010をターゲットとしたい場合は
Type instanceType = Type.GetTypeFromProgID("Excel.Application.14");
と書けばいけます。

■Activatorで、インスタンスを作成する。
dynamic appliactionClass = Activator.CreateInstance(instanceType);
これはよく使われる手だと思いますが、Avtivatorを利用すれば型からインスタンスが簡単に生成できます。戻り値はCOMオブジェクトになりますが、これをdynamicで受けるあら不思議。

dynamic book = application.Workbooks.Add();

メソッドの存在を知らなければ、到底書けるコードではありませんが、知っている人ならサクサク書けちゃいます。まあ、ちゃんと定義された型でラップして手堅くコーディングしたいものですが、できちゃんだぜ〜ワイルドだろうぅ〜・・・です。

■しっかりリリースする。
Marshal.ReleaseComObject(book);
COMオブジェクトなのでリリースすることを忘れないことですね。


Source and Project

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】【Excel】死なないExcelプロセスをKillする。

  • 2012.12.04 Tuesday
  • 21:37
JUGEMテーマ:コンピュータ

Source and Project

デバック中に中断したり、COMオブジェクトの解放を忘れたりするとExcelプロセスが残ったままになってしまうことがあります。何度もデバッグを繰り返していくと、手動でゾンビプロセスをKillするのは時間の無駄なのでプログラムをみました。

using System.Diagnostics;
using System.Linq;

namespace Art55.NetOfficeDemo20121204_004
{
    class Program
    {
        static void Main()
        {
            Process[] killTargets = Process.GetProcessesByName("Excel");
            killTargets
                .ToList()
                .ForEach(process => process.Kill());
        }
    }
}


あまりお勧めしませんが、私のPCに89個のExcelプロセスが動いていたので、致し方なくKillしまいた。

■ローカルコンピュータ内で、指定したプロセス名で動作しているプロセスを取得する。
Process[] killTargets = Process.GetProcessesByName("Excel");

■プロセスを終了する。
process.Kill()

そもそもこういう事態に陥らないようにコードで対処するべきです。べき論は言えますが、具体的にどうすれば良いのか的確に答えられません(涙)

Source and Project

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

【NetOffice】起動中のExcelアプリケーションのCOMオブジェクトを取得し、NetOfficeで利用する。

  • 2012.12.04 Tuesday
  • 21:01
JUGEMテーマ:コンピュータ

Source and Project

先に断って起きます。今回紹介する方法は、回避できない欠点があり実用性がありません。技術情報として紹介させていただきます。実用性を求めるのであれば、以下をご参照ください。

【NetOffice】方法:起動中の複数のExcelアプリケーションを取得する。
http://pro.art55.jp/?eid=1304139

Excelアプリケーションにはバージョンに関係なく「Excel.Application」というProgIDが割り当てられています。System.Marshal.GetActiveObjectメソッドを利用することで、Excel.ApplicationというProgIDで動作しているアプリケーションを取得することができます。
また、NetOffice.Excel.Applicationコンストラクタの第二引数に取得したCOMオブジェクトを渡すことで、取得したCOMオブジェクトであるExcelアプリケーションをNetOfficeから利用することができます。

サンプルコード

using System;
using System.Linq;
using System.Runtime.InteropServices;
using NetOffice.ExcelApi;
namespace Art55.NetOfficeDemo20121204_003
{
    class Program
    {
        static void Main(string[] args)
        {
            object comProxy = Marshal.GetActiveObject("Excel.Application");
            var application = new Application(null, comProxy);
            application
                .Workbooks
                .First()
                .Worksheets
                .OfType<Worksheet>()
                .ToList()
                .ForEach(sheet => Console.WriteLine(sheet.Name));
        }
    }
}

この方法は二つ問題があります。

■GetActiveObjectメソッドが複数同時起動アプリケーションに対応していない。
この方法には一つ問題があります。GetActiveObjectが返すインスタンスは一つだけです。Excelアプリケーションは複数起動できるので一つしかインスタンスを返さないというのは問題という事は明白です。調べてみると、GetActiveObject内で呼び出しているole32.dllの関数がそもそも一つしかインスタンスを返さないような実装になっているようです。

■管理者権限のあるなしで動作が異なる。
今回作成したアプリケーションを管理者権限で実行した場合、管理者権限のない状態で実行しているExcelアプリケーションは取得できません。両者を管理者権限で実行するか、両者を管理者権限なしで実行するか、または、UAC(User Account Control)を無効にする 必要があります。

■ExcelのProgIDは「Excel.Application」
バージョンに無関係の場合
アプリケーション ProgID
Microsoft Access Access.Application
Microsoft Excel Excel.Application
Microsoft Outlook Outlook.Application
Microsoft PowerPoint Powerpoint.Application
Microsoft Word Word.Application
Microsoft FrontPage FrontPage.Application

バージョンを指定したい場合
Excel2010の場合はExcel.Application.14

参考
Office アプリケーションのパスを調べる方法
http://support.microsoft.com/kb/240794/ja

Source and Project

--------------------------------------
本投稿は、CodePlexで公開されているNetOfficeを利用していませんが、紹介します。
NetOffice - MS Office in .NET
http://netoffice.codeplex.com/

NetOffice関連の記事は下記にまとめています。
【NetOffice】【Excel】NetOfficeのまとめ
http://pro.art55.jp/?eid=1304102
--------------------------------------

calendar

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      
<< March 2024 >>

あわせて読みたい

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

selected entries

categories

archives

recent comment

  • 【WPF】DataGridに編集可能なComboBoxを表示するには?
    art55 (07/16)
  • 【WPF】DataGridに編集可能なComboBoxを表示するには?
    arisa (07/16)
  • 【キーボード】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)

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