- 題名: 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