野暮用で必要になったんだけど、どうも納得いくものがなくて悩んだ。
レジストリから取得するのが一番手取り早いんだけど、レジストリの名前が変わったらメンテしないといけない。
かといって、xlsxみたいなファイルの拡張子からたどるのは、(もうないとは思うけど…)2003から2007で拡張子が変わったときみたいに変わる可能性があるので都度メンテしないといけない。
他に変わらなさそうなものは…商品名は変わらんだろうってことになり。
ってことで、今回のポイントはこんなとこ。
※Microsoft.Office.Interop.Excel.Application.PathはExcelのモジュールがあるフォルダーしか取得できないので今回は見送り…。
- Microsoft.Office.Interop.Excel.ApplicationクラスをnewしてExcelのプロセスを作成する
※Excelのプロセスは必ずCOMの解放処理を行うこと!でないと、Excelのプロセスが残っちゃう… - System.Diagnostics.Process.GetProcessesByNameの引数に”Excel”を指定してExcelのプロセスを名前で検索する
- 取得したプロセスのMainModule.FileNameプロパティで実行ファイルのフルパスを取得する
ExcelのCOMオブジェクトへの参照設定はあらかじめしておくこととして…コードはこんな感じ。
/// <summary>
/// エントリーポイント
/// </summary>
/// <param name="arguments">コマンドライン引数(今回は使わない)</param>
static void Main(string[] arguments)
{
Microsoft.Office.Interop.Excel.Application application = null;
string name = @"EXCEL";
try
{
// EXCELを起動する
// ※ApplicationのPathプロパティだとフォルダーパスまでしか教えてくれない...
application = new Microsoft.Office.Interop.Excel.Application();
// 起動したEXCELのプロセスからexeのフルパスを取得する
// ※EXCELのプロセスが1つ以上あればフルパスが取得できる
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(name);
System.Diagnostics.Process process = processes.First();
string module = process.MainModule.FileName;
// フルパスを表示する
Console.WriteLine(module);
}
catch(Exception exception)
{
Console.WriteLine(exception.Message);
}
finally
{
// EXCELを閉じる
if(application != null)
{
application.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(application);
application = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.ReadKey();
}
}
で、実行したらこんな感じ。
欠点はこんな感じ。
- Excelプロセスが必ず作成される
- Excelプロセスを破棄するときにCOMオブジェクトの解放を真面目にやらないといけない
ただ、同じような処理を考えればWordやPowerPointにも応用できそう。
そんなこんなで、明日への自分へのメモってことで。
