Excelを外部から操作する(interopサービスを使う)時の問題点と利点
目次
interop問題
.netを使って作業の自動化をしていているのですが、以前Excelの操作をPowershellで行う記事を書きました。
これ、開放されないプロセスが残ってしまう問題が有名なんですがそれとは別にタスクスケジューラでバックグラウンド実行するとエラーが頻発します。
ComObject自体が動的に生成されるので、現在の状態を把握しないとうまく動きません。
例えばこんなscriptを作って作業を自動化しようとしたとします。
1 2 3 4 5 6 7 8 9 10 11 12 |
$BookPath = "C:\User\Owner\Documents"
$BookName = "Book.xlsx"
$DataSheetName = "データ"
$SettingSheetName = "環境設定"
$DataSheetIndex = 1
$SettingSheetIndex = 2
$BookFullPath = Join-Path $BookPath $BookName
$Excel = [System.Runtime.InteropServices.Marshal]::GetActiveObject("Excel.Application")
$Book = $Excel.Worksheets.Item($BookName)
If($Book.path -ne $BookPath){$Book.close();$Book= $Excel.Workbooks.Open($BookFullPath)}
#Excelが掴めない場合は、新しいExcelプロセスを作って開きます。
if($null -eq $Excel){
$Excel = New-Object -ComObject Excel.Application
Start-Sleep 10
$Book= $Excel.Workbooks.Open($BookFullPath)
}
$SettingSheet = $Book.Worksheets.Item($SettingSheetName) |
Excelオブジェクトがつかめない。
1 2 |
"1" 個の引数を指定して "GetActiveObject" を呼び出し中に例外が発生しました: "操作を利用できません (HRESULT からの例外:0x800401E3 (MK_E_UNAVAILABLE))" |
→起動直後にはオブジェクトがROTに登録されておらず、一旦フォーカスを他のアプリに移して再度フォーカスをEXCELに移すとROTに登録されるという情報が見つかります。やりたいことはバックグラウンド実行なので、そもそも「フォーカス」というものがあるのかどうかから謎です。
どうやらPowershellを管理者として実行していると、GetActiveObjectしようとするときに管理者として実行しているExcelプロセスしか掴めないようです。
シートがシート名でつかめない
1 |
"Item" の取得中に例外が発生しました: "インデックスが無効です。 (HRESULT からの例外:0x8002000B (DISP_E_BADINDEX))" |
→シート名で指定しようとするとインデックスがないというエラーが発生します。英語で検索すると「名前ではなくインデックスで指定してください」という情報が見つかりました。
$Excel.Sheetsもしくは$Excel.Worksheetsオブジェクトに目的のシートがない
→アクティブなBookのシートが格納されるようです。どのBookがアクティブなのか把握する必要があります。
バッチジョブでファイルがオープンできない
タスクスケジューラに登録したジョブからファイルがオープンできない事があります。タスクスケジューラでそのままExcelをオープンするときにはいいのですが、VBScript,PowerShell,外部のVBAから開こうとするとファイルが無いもしくはアクセスが拒否される旨のエラーが発生します。
MSDNの記事によると、systemprofileにDesktopを作成すれば回避できるとあります。
Unable to open excel files using a cscript in SQL Server Jobs
x86 – C:\Windows\System32\config\systemprofile\Desktop
x64 – C:\Windows\SysWOW64\config\systemprofile\Desktop
さらにここで言及されているヘルプを見ると、明確に非推奨・非サポートとなっています(ー_ー;)
マイクロソフトは、現在のところ、無人の非対話型クライアント アプリケーションまたはコンポーネント (ASP、ASP.NET、DCOM、および NT サービスを含む) からの Microsoft Office アプリケーションのオートメーションに関して、推奨もサポートも行っていません。それは、このような環境で Office を実行した場合、Office で不安定な動作やデッドロックが発生する可能性があるためです。
代わりに、xlsxファイルを操作するライブラリを使いましょう、と書いてあります。
ここでMicrosoftが推奨しているOpenXML SDKは使いにくいと評判なので、違うものを使いましょう。
NPOI,ClosedXML,ExcelPackagePlus(EPP),PowerShellであればEPPを元にモジュール化したImportExcelもあります。
Microsoftがオープンソースで作っているClosedXMLは記法がVB.Netに似ていて直感的にわかりやすいということなので、Powershellに導入方法を別記事にまとめています。
それでもinteropを使う利点
Excelを外部から操作するだけなので、Excelができることはすべてできます。
xlsファイルを使いたい
古いシステムとの連携でxlsファイルを使わないければいけないことがあるかも知れません。そんなときでも問題なく開けます。NPOIならxlsファイルを開けますが、.netプログラミングとは随分記法が違うので戸惑うかも知れません。
有償のサードパーティ製ライブラリを購入したほうが良い、という情報もあります。
Web上のファイルをそのまま開ける
Web上にファイルを格納できるサービスが増えてきました。ダウンロード&修正&アップロードすればいい話なのですが、ロック機構が不備だったりするとサーバ上のファイルをそのまま開きたい事があるかも知れません。
上記に上げたライブラリを試しましたが、Web上のファイルをそのまま開けるのはExcelだけでした。
Windowsマクロとして使う
対話型作業の自動化としては使えるということなので、複数のOfficeアプリケーションやMailなどをまたぐWindowsマクロのような使い方ができます。
まとめ
- xlsxファイルを読み書きしたいだけならオープンソースのライブラリを使う。
- Officeアプリケーションを外部から操作するならinteropサービスもまだ有効。ただし、その際は対話型ログインで行う。
“Excelを外部から操作する(interopサービスを使う)時の問題点と利点” に対して2件のコメントがあります。