interopサービスを使う時の問題点

interop問題

.netを使って作業の自動化をしていて、以前Excelの操作をPowershellで行う記事を書きました。

これ、開放されないプロセスが残ってしまう問題が有名なんですがそれとは別にタスクスケジューラでバックグラウンド実行するとエラーが頻発します。

ComObject自体が動的に生成されるので、現在の状態を把握しないとうまく動きません。
例えばこんなscriptを作って作業を自動化しようとしたとします。

$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" 個の引数を指定して "GetActiveObject" を呼び出し中に例外が発生しました: 
"操作を利用できません (HRESULT からの例外:0x800401E3 (MK_E_UNAVAILABLE))"

→起動直後にはオブジェクトがROTに登録されておらず、一旦フォーカスを他のアプリに移して再度フォーカスをEXCELに移すとROTに登録されるという情報が見つかります。やりたいことはバックグラウンド実行なので、そもそも「フォーカス」というものがあるのかどうかから謎です。
どうやらPowershellを管理者として実行していると、GetActiveObjectしようとするときに管理者として実行しているExcelプロセスしか掴めないようです。

シートがシート名でつかめない

"Item" の取得中に例外が発生しました: "インデックスが無効です。 (HRESULT からの例外:0x8002000B (DISP_E_BADINDEX))"

→シート名で指定しようとするとインデックスがないというエラーが発生します。英語で検索すると「名前ではなくインデックスで指定してください」という情報が見つかりました。

$Excel.Sheetsもしくは$Excel.Worksheetsオブジェクトに目的のシートがない

→アクティブなBookのシートが格納されるようです。どのBookがアクティブなのか把握する必要があります。

…なんどもコケるので次回からは違うライブラリを使うと心に決めました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください