STEP
ExcelVBAのプロジェクトへアクセスできるように設定を行う
Excelのオプション⇒トラストセンター⇒マクロの設定で表示される「VBAプロジェクトのオブジェクトモデルへのアクセスを信頼する」にチェックを入れる。
これをしておかないと外部からVBAにアクセスすることができない。
STEP
Excelマクロには表示用にパスワード保護がかけれていた
対象のファイルにはExcelVBAの表示用パスワードが掛けられていた。Office関係のアプリケーションはActieXオブジェクトとして外部から操作が可能だが、保護解除のためのメソッドやプロパティが用意されていない。これが少し面倒。
結局のところメソッドやプロパティがないため、キー操作を模倣して解除することになる。
Excelへの参照設定を行い、アプリケーションが操作できる状態を前提に下記コードを記述する。
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
excel.Visible = true;
excel.EnableEvents = false;
Microsoft.Office.Interop.Excel.Workbooks books = excel.Workbooks;
Microsoft.Office.Interop.Excel.Workbook book = books.Open("★対象ファイル");
book.Activate();
//ロックされている場合は解除
if (book.VBProject.Protection == vbext_ProjectProtection.vbext_pp_locked)
{
excel.OnKey("%{F11}"); //Alt+F11
Thread.Sleep(1000);
excel.SendKeys("%{F11}%TE" + "★パスワード" + "~~%{F11}", true);
Thread.Sleep(1000);
}
【注意点】キー入力を行うため、途中でフォーカスが外れるとうまく機能しなくなる。フォーカスを奪うようなアプリや他のExcelが起動していたりすると動きがおかしくなるので要注意だ。
Sleepを挟んでいるのはキー入力の結果を少し待機するためだが、このあたりは適当に調整してもらえればと思う。
STEP
VBAコンポーネントの出力
保護が解除されていれば、モジュールの出力はメソッドが用意されているので書き出すだけでOK。
Microsoft.Vbe.Interop.VBComponents modules = book.VBProject.VBComponents;
string pathName;
foreach (Microsoft.Vbe.Interop.VBComponent module in modules)
{
pathName = Path.Combine("★出力先フォルダ", module.Name);
switch (module.Type)
{
case Microsoft.Vbe.Interop.vbext_ComponentType.vbext_ct_ClassModule:
pathName += ".cls";
break;
case Microsoft.Vbe.Interop.vbext_ComponentType.vbext_ct_MSForm:
pathName += ".frm";
break;
default:
pathName += ".bas";
break;
}
module.Export(pathName);
}
STEP
Excelオブジェクトの後始末
Excelオブジェクトを使用した後は決まった手順でリリースしなければならない。
ぱっとみ冗長的に感じられるが、段階的に確実にリリースする必要がある。
excel.DisplayAlerts = false;
book.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(book);
book = null;
GC.Collect();
GC.WaitForPendingFinalizers();
books.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(books);
books = null;
GC.Collect();
GC.WaitForPendingFinalizers();
excel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
excel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
と、こんな感じにコーディングすればマクロの書き出しができます。