- 題名: vb.netで2つのエクセルファイルを処理する場合の挙動について
- 日時: 2012/09/05 14:10:58
- ID: 30892
- この記事の返信元:
- (なし)
- この記事への返信:
- [30893] Re[1]: vb.netで2つのエクセルファイルを処理する場合の挙動について2012/09/05 15:02:54
- ツリーを表示
■No30892に返信(やむさんの記事) > MRComObject 自作関数でしょうか。MRComObject に関する説明が抜けていますよ。 名前からして、Marshal.(Final)ReleaseComObjct メソッドを 読んでいるものであろうとは想像がつきますけれどね。 > xlTmpBooks = xlApp.Workbooks > xlBooks = xlApp.Workbooks この 2 つは同じ COM インスタンスへの参照となるでしょうから、 xlTmpBooks を廃して、xlBooks のみで管理してみてください。 > なぜこのような現象が起こるのか、教えてください。 xlTmpBooks と xlBooks は同じインスタンスであるにも関わらず、 MRComObject(xlTmpBooks) を実施しているからでは無いでしょうか。 その後もまだ、xlBook.SaveAs にて Workbook を使用するのですから、 それより前のタイミングで、親オブジェクト(Workbooks や Application 等)の 終了処理を実施するのは避けるべきです。 > FileAを終了する際に、Booksを解放せず > FileAのBooksを開放すると、 「解放」ですね。開放だと open の意味になってしまいます。 開放は、自身が管理している資源や制限を開け放ち、自由に出入りさせること。 解放は、束縛を解いて自由にすること/管理資源の所有権を破棄し解き放つこと。 図書館の一般カイホウ、校庭の一時カイホウなどは前者で、 人質のカイホウ、ストレスからのカイホウなどは後者です。 > If Not isBooksClose = False Then 「If isBooksClose Then」の方が素直では?
■No30894に返信(やむさんの記事) > 引数を省略せず、 これは「引数 isBooksClose に True を渡した場合」という意味ですね? > 確かにxlBooksとxlTmpBooksは、同じxlAppを参照しています。 参照先は、xlApp.Workbooks ですね。 xlBooks Is xlTmpBooks の結果は True でしょうか。 > closeTmpExcel関数でxlTmp...を解放し、 > closeExcel関数でxlAppまで解放してしまった後、 closeTmpExcel は関数ではありませんが、それはさておき。 True / False 時の動作が、自分の予想と真逆なんですよね…。 ============================== closeTmpExcel(isBooksClose As Boolean) に True が渡された場合、 FileA が xlTmpBook.Close() で閉じられた後、さらに追加で xlTmpBooks.Close() が実行されることになります。 通常はここで、FileB のファイル未保存確認の通知が表示されるところですが、 DisplayAlerts = False のため、両ブックともそのまま閉じられます。 さて、問題はその後の closeExcel(saveFile As String)。 この時点では、FileB が既に閉じられているため、 xlBook.Close() や MRComObject(xlBook) を実施する前であっても、 xlBook.SaveAs(saveFile) や xlBook.Close は RPC_E_DISCONNECTED になると予想しています。 ――しかし、今回はそれがエラーにならなかったのですね? ============================== 一方、引数無しで closeTmpExcel(isBooksClose As Boolean) を 呼び出した場合は、isBooksClose に False が渡されたことを意味しますので、 この場合には Workbooks.Close が実行されず、FileA のみが閉じられますね。 この場合、closeExcel 内の xlBook.SaveAs の行に到達するまでに 下記の状態になると予想します。 共有物:xlApp As Application :生存中 共有物:xlTmpBooks As Workbooks :生存中 FileA :xlTmpBook As Workbook :MRComObject済み FileA :xlTmpSheets As Sheets :MRComObject済み FileA :xlTmpSheet As WorkSheet :MRComObject済み 共有物:xlBooks As Workbooks :生存中 FileB :xlBook As Workbook :生存中 FileB :xlSheets As Sheets :MRComObject済み FileB :xlSheet As WorkSheet :MRComObject済み 共有物であるはずの Workbooks 変数が 2 つあるのは不自然ですが、 xlBook.SaveAs の呼び出しについては、特に問題無さそうです。 RPC_E_DISCONNECTED にはなりそうに無いのですが…。不思議。
■No30897に追記(魔界の仮面弁士)
> この時点では、FileB が既に閉じられているため、
> xlBook.Close() や MRComObject(xlBook) を実施する前であっても、
> xlBook.SaveAs(saveFile) や xlBook.Close は
> RPC_E_DISCONNECTED になると予想しています。
この根拠は、Excel VBA での検証結果によるものです。
(VB.NET から呼ぶと解放が面倒なので、先に VBA で検証していました)
>>> ※エラー内容:
>>> 起動されたオブジェクトはクライアントから切断されました。 (HRESULT からの例外: 0x80010108 (RPC_E_DISCONNECTED))
Workbooks.Close 後に Workbook.Close あるいは Workbook.SaveAs を
実行しようとすれば、RPC_E_DISCONNECTED が通知されたので、これが
原因だと思い込んでいたのです。
(やむさんの VB.NET 環境ではエラー無く呼べたみたいですが)
Dim X As Excel.Application
Set X = New Excel.Application '自身とは別の excel.exe を生成
X.Visible = True
Dim BS As Excel.Workbooks
Set BS = X.Workbooks
Dim B As Excel.Workbook
Set B = BS.Add()
X.DisplayAlerts = False
BS.Close 'これを実行すると、BS.Count は 0 になった
B.Close 'ここでエラー &H80010108 発生(B.SaveAs を呼んだ場合も同様)
'『オートメーション エラーです。
' 起動されたオブジェクトはクライアントから切断されました。』
> xlAppが解放された状態であっても、xlTmpBooksはcloseして解放するのみなので
> 問題ないということなんでしょうか。
xlAppが解放された段階で、Excel.exe が終了しているかどうかを
タスクマネージャで確認してみてください。生き残っているようであれば、
Close を呼び出せる可能性はありそうですね。
上記 VBA コードの例で恐縮ですが、最後の B.Close の行をコメントにして
X.DisplayAlerts = False
BS.Close
'B.Close
X.Quit
Set X = Nothing
BS.Close
のようにしてみても、二回目の BS.Close は成功したためです。
そもそも、上記で X.Quit を実行した段階では、Excel が
非表示に変更されるだけで、Excel.exe は生き残っていました。
流石に、その excel.exe 自体を強制終了した後では、WS.Close が
『リモート サーバーがないか、使用できる状態ではありません。』
というエラー(Err.Number = 462)になりました。
なお、Quit を呼ぶ前もしくは呼んだ後に
Set BS = Nothing を実行した場合は、Excel.exe も終了します。
ブックが最上位オブジェクトだった時代の名残ですかね…。
>>>> MRComObject
>>> 名前からして、Marshal.(Final)ReleaseComObjct メソッドを
>>> 読んでいるものであろうとは想像がつきますけれどね。
>> はい、魔界の仮面弁士さんのおっしゃる通りです。
>> その関数内で解放処理を行っています。
MRComObject の内部実装がまだ公表されていませんが、
もしも Marshal.FinalReleaseComObject ではなく
Marshal.ReleaseComObject を使用しているのだとしたら、
その時の戻り値もチェックしてみてください。
戻り値が = 0 になれば正常ですが、< 0 の場合は過解放となりますし、
> 0 の場合は、どこかで参照カウントが内部増加していることになります。
たとえば、Workbooks オブジェクトの参照カウントが残っていれば、
MRComObject(xlBooks) を実施した後でも、xlTmpBooks への操作は
続行できるかと思います。
分類:[.NET]
はじめて投稿します。
2つのエクセルファイルを同時に開き、FileAからFileBにシートをコピーした後、
FileAを終了させて、FileBに書き込みを行ってからFileBを終了する
といった処理を行おうと思っています。
実際に、FileAからFileBに対してシートをコピーし、FileAを終了させて
FileBを保存してから終了する処理を実行したところ、FileBを保存するところで
エラーとなってしまいます。
※エラー内容:
起動されたオブジェクトはクライアントから切断されました。 (HRESULT からの例外: 0x80010108 (RPC_E_DISCONNECTED))
FileAを終了する際に、Booksを解放せず、FileBの保存・終了後
FileAのBooksを開放すると、問題なく処理が実行されます。
なぜこのような現象が起こるのか、教えてください。
以上、宜しくお願いします。
-----以下実際のコード----
Public Sub openExcel(ByVal filePath As String, ByVal tmpPath As String, ByVal sheetName As String)
'テンプレートファイルのオープン
xlApp = New Excel.Application
'xlTmpApp = New Excel.Application
'xlTmpApp.Visible = False
'xlTmpApp.DisplayAlerts = False
'xlTmpBooks = xlTmpApp.Workbooks
xlTmpBooks = xlApp.Workbooks
xlTmpBook = xlTmpBooks.Open(tmpPath)
xlTmpSheets = xlTmpBook.Worksheets
xlTmpSheet = CType(xlTmpSheets.Item(1), Excel.Worksheet)
'xlApp = New Excel.Application
Dim shipGuide As String = IO.Path.Combine(My.Application.Info.DirectoryPath, SHIP_GUIDE_FILE_TMP)
xlApp.Visible = True
xlApp.DisplayAlerts = False
xlBooks = xlApp.Workbooks
xlBook = xlBooks.Open(shipGuide)
'xlBook = xlBooks.Add()
xlSheets = xlBook.Worksheets
xlSheet = CType(xlSheets.Item(xlSheets.Count), Excel.Worksheet)
'テンプレートのシートをコピー
xlTmpSheet.Copy(After:=xlSheet)
closeTmpExcel(True) @引数を省略すると、Aの個所でエラー
closeExcel(filePath)
'xlTmpBooks.Close()
'MRComObject(xlTmpBooks)
End Sub
Public Sub closeTmpExcel(Optional ByVal isBooksClose As Boolean = False)
MRComObject(xlTmpSheet)
MRComObject(xlTmpSheets)
xlTmpBook.Close()
MRComObject(xlTmpBook)
If Not isBooksClose = False Then
xlTmpBooks.Close()
MRComObject(xlTmpBooks)
End If
'xlTmpApp.DisplayAlerts = True
'xlTmpApp.Visible = True
'xlTmpApp.Quit()
'MRComObject(xlTmpApp)
End Sub
Public Sub closeExcel(ByVal saveFile As String)
MRComObject(xlSheet)
MRComObject(xlSheets)
xlBook.SaveAs(saveFile) Aこの個所でエラー
xlBook.Close()
MRComObject(xlBook)
xlBooks.Close()
MRComObject(xlBooks)
xlApp.Visible = True
xlApp.DisplayAlerts = True
xlApp.Quit()
MRComObject(xlApp)
End Sub