質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

Q&A

解決済

2回答

8685閲覧

COM オブジェクト が RCW から分割されていないか確認したい

kamikazelight

総合スコア305

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

0グッド

1クリップ

投稿2018/11/08 06:03

編集2018/11/09 03:04

前提・実現したいこと

Excelブックなどが格納されている変数を参照しようとしたときに
そのcomオブジェクトが閉じられていたり、解放されていたりすると
当然ですがエラーになってしまいます。

エラーが出てからの確認ではなく
エラーを出さずにCOM オブジェクト が RCW から分割されていないか確認したいのですが
可能でしょうか?

--追記--
Excelは完全にpowershellで操作するわけではなく
Excel業務の補助操作のために利用します。
そのためExcelのオープンやクローズは手動で行います。

発生している問題・エラーメッセージ

基になる RCW から分割された COM オブジェクトを使うことはできません。

該当のソースコード

powershell

1 2function _New_Excel(){ 3#新規プロセスのExcelを取得する 4 [outputtype([Microsoft.Office.Interop.Excel.ApplicationClass])] 5 $Excel = New-Object -ComObject Excel.Application 6 return $Excel 7} 8 9Function _ComQuit($Com){ 10#指定Comオブジェクトの破棄 11 while ($([System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($Com)) -gt 0){} 12 Remove-Variable Com 13} 14 15$App = _New_Excel 16$App.Visible = $true 17_ComQuit $App 18 19 20$App.Visible #エラー出さずにつながっているか確認したい

試したこと

Tryを使えば確認はできるのですが、
エラーは 出来れば想定外のものだけを拾いたいです。

powershell

1try 2{ 3 $null = $App.Visible 4 Write-host "切れてない" 5} 6catch 7{ 8 Write-host "切れてる" 9}

補足情報(FW/ツールのバージョンなど)

Win10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Marshal Class (System.Runtime.InteropServices) | Microsoft Docs

をざっと見る限りだと、確認できるようなメソッドはなさそうですね。


Tryを使えば確認はできるのですが、

エラーは 出来れば想定外のものだけを拾いたいです。

想定外のエラーはスルーするのではダメなのでしょうか?

エラーメッセージや、エラー発生後に$Error[0].Exception.GetType().FullNameを確認すると
InvalidComObjectException Class (System.Runtime.InteropServices)
が例外として投げられていることがわかります。

text

1基になる RCW から分割された COM オブジェクトを使うことはできません。 2発生場所 行:X 文字:X 3+ XXXXXXXXXXXXXX 4+ ~~~~~~~~~~~~~~ 5 + CategoryInfo : OperationStopped: (:) [], InvalidComObjectException 6 + FullyQualifiedErrorId : System.Runtime.InteropServices.InvalidComObjectException 7 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

例外の説明を見ると以下のようになっており、汎用的な例外ではなくCOMオブジェクトがRCWから分割されている場合など、特定の場合のみ使われる例外だと思われます。

text

1無効な COM オブジェクトを使用したときにスローされる例外。 2The exception thrown when an invalid COM object is used.

つまり、catch節で[System.Runtime.InteropServices.InvalidComObjectException]だけをキャッチするように指定すれば良いのではないでしょうか?

powershell

1try 2{ 3 $null = $App.Visible 4 Write-host "切れてない" 5} 6catch [System.Runtime.InteropServices.InvalidComObjectException] 7{ 8 Write-host "切れてる" 9}

例外の型名を毎回打つのは面倒なので、自分なら関数化も考えます。

powershell

1<# 2.Synopsis 3有効なCOMオブジェクトかどうかテストする(パイプライン入力不可) 4#> 5function Test-ComObject { 6 param( [System.__ComObject]$InputObject ) 7 8 if( $null -eq $InputObject ) { return $false } 9 10 try { 11 $InputObject.GetType() > $null 12 } catch [System.Runtime.InteropServices.InvalidComObjectException] { 13 return $false 14 } 15 return $true 16}

投稿2018/11/09 10:33

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamikazelight

2018/11/09 11:40

もう一度 考え直してみたら過去にした質問で最全面から順にウィンドウが取得出来るようになったお陰で ずっとcomをとっておく必要がなくなったので 範囲が限定されて 簡単にtryで囲めるようになったのを考えてませんでした。 しかもいつどこでアクセス出来なくなるかわからないのに特定の箇所で確認する意味はあんまり無いですよね.... ありがとうございました。
kamikazelight

2018/12/11 01:19 編集

--削除-- すみません 早とちりでした
guest

0

PowerShellは触ったことがないので、外しているかもしれませんが、PowerShellでオブジェクトの管理をやってくれる仕組みがないのであれば、ご自身で参照カウンタを管理するしかないのではないでしょうか。
以下PowerShell書けないので概念的な説明になりますが、

スクリプト内に参照カウンタ用の変数を持たせておき、_New_Excelを
0. カウンタが0の場合Excelオブジェクトを作成して、カウンタをインクリメント
0. カウンタが1以上の場合、カウンタをインクリメントして、Excelオブジェクトを新しく作らずに、前回作ったオブジェクトを渡す

という処理にします。同様に_ComQuitについても

  1. カウンタが1以上の場合、カウンタをデクリメントするのみ
  2. デクリメントの結果カウンタが0になった場合にオブジェクトを破棄する

として、Excelオブジェクトを使う場合、必ず_New_Excelを呼んで、使い終わったら_ComQuitを呼ぶようにしおけば、多少複雑な分岐やネスト処理があっても、参照用カウンタをチェックすることで、オブジェクトが残っているかどうか判別できると思います。

VC++ではこういうことをやってくれるラッパークラスがあるのですが、PowerShellでクラスが使えるのであれば、そいうクラスを作って、クラス内部で参照カウンタの管理を任せてもいいと思います。

投稿2018/11/09 01:31

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamikazelight

2018/11/09 03:03

情報が不足しておりました。 ごめんなさい Excelは完全にpowershellで操作するわけではなく Excel業務の補助操作のために利用します。 そのためExcelのオープンやクローズは手動で行います。 その関係上 Excelオブジェクトのカウンタは作れないのです。 ホントはファイルのドロップとかでExcelのオープンやクローズが 出来ればいいのですが 同じ名前のファイルを開くためにであったり VBA入りのファイルで読み取り専用でないと利用できないファイルを読み取り専用で開くためだったりで VBS 経由で開いているファイルもあり 少し厳しいのです...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問