2012-02-24 22 views
7

Excelワークブックのすべてのシートをループし、各シートを独自のワークブックとして保存するプログラムを作成しています。 Sheet.Copyメソッドが奇妙なオブジェクトを作成するので、私が予想していたより少しトリッキーなことが判明しました(MSDNディスカッションの関連記事はhttp://msdn.microsoft.com/en-us/library/ms178779.aspxです)。VB.NET Excelプログラムは、完了後にEXCEL.EXEをフローティングにします。

とにかく、プログラムが完了した後に残っているEXCEL.EXEプロセスを掛けている外に、本質的に完全であるところに私を持ってきたanother Stack Overflow postが見つかりました。私は彼らが関連していると思う)。ここで

は私のコードです:

 'close excel and release com objects 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(exportsheet) 
     exportsheet = Nothing 
     xlApp1.Workbooks(fileNames(counter - 1)).Close(False) 

Imports System.Data 
Imports System.IO 
Imports Microsoft.Office.Interop 
Imports Office = Microsoft.Office.Core 
Imports xlNS = Microsoft.Office.Interop.Excel 
Imports System.Runtime.InteropServices 

Class Form1 

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 

    'Get information from text boxes 
    Dim InputLocation As String 
    Dim OutputLocation As String 

    InputLocation = InputLoc.Text & "\" & FileName.Text 

    If OutputLoc.Text = "" Then 
     OutputLocation = InputLoc.Text 
    Else 
     OutputLocation = OutputLoc.Text 
    End If 

    'Make file to save files in 
    ' Get date and time in filename as well 
    Dim TLDateTime As String 
    Dim TLDay As String 
    Dim TLMonth As Integer 
    Dim TLYear As Integer 
    Dim TLHour As Integer 
    Dim TLMinute As Integer 
    Dim TLDate As String 
    Dim TLTime As String 
    Dim TLSecond As Integer 

    TLDay = DateTime.Now.Day 
    TLMonth = DateTime.Now.Month 
    TLYear = DateTime.Now.Year 
    TLHour = DateTime.Now.Hour 
    TLMinute = DateTime.Now.Minute 
    TLSecond = DateTime.Now.Second 

    Dim MyDate As New DateTime(TLYear, TLMonth, TLDay, TLHour, TLMinute, TLSecond) 
    Dim MyString As String = MyDate.ToString("MMMddyyyy_HHmmss") 
    TLDate = TLMonth.ToString + TLDay.ToString + TLYear.ToString 
    TLTime = TLHour.ToString + TLMinute.ToString 
    TLDateTime = TLDate + "_" + TLTime 

    Try 
     Directory.CreateDirectory(OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime) 
     OutputLocation = OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime 
    Catch 
     MsgBox("Trying to create a file that exists, please delete it. If the file does not exist check to make sure your output location exists") 
    End Try 

    'Open up excel file with information in it 

    Dim xlApp1 As Excel.Application 
    Dim locs As Excel.Workbook 

    Dim exportsheet As Excel.Worksheet 
    xlApp1 = New Excel.Application 
    xlApp1.Visible = True 
    xlApp1.Application.DisplayAlerts = False 
    locs = xlApp1.Workbooks.Open(InputLocation) 

    'locsws = locs.ActiveSheet 
    Dim wkshtcount = locs.Worksheets.Count - 1 
    Dim fileNames As New ArrayList 

    For counter = 1 To wkshtcount + 1 
     'identify and copy sheet to move 
     exportsheet = CType(locs.Worksheets(counter), Excel.Worksheet) 
     fileNames.Add(exportsheet.Name) 
     exportsheet.Copy(Type.Missing, Type.Missing) 

     exportsheet = xlApp1.Workbooks("Book" & counter).Sheets(1) 

     exportsheet.SaveAs(Filename:=OutputLocation & "\" & fileNames(counter - 1) & ".xlsx") 

     'close excel and release com objects 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(exportsheet) 
     exportsheet = Nothing 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.ActiveWorkbook) 
     xlApp1.ActiveWorkbook.Close(False) 

    Next 
    'close excel and release com objects 
    locs.Close(False) 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(locs) 
    locs = Nothing 
    xlApp1.Quit() 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1) 
    xlApp1 = Nothing 


End Sub 
End Class 

今、私はこの問題は、私は、エクスポートファイルとそれが作成する新しいワークシートを閉じようとループの終わりから来ていると思います

私は、作成された新しいワークシートのComObjectをリリースするために何をすべきか分かりません。私はあらゆる種類のものを試してきましたが、私がそれを行うときにCOMエラーがスローされます。何も定義しないと(エクスポートシートと同じように)、デフォルトでのみ読み込まれるので、それをしないでください。

System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.Workbooks(fileNames(counter - 1))) 

しかし、そうではありません。私はこれのいくつかの変種を試して、私はそれが上記のMSDNリンクと関係があると思っていますが、私は何をすべきかをかなり整理することはできません。だからコードは私の目的のために働いています。

テストファイルでは、3枚のExcelファイルを使用していますが、それぞれに情報を入れてシート名を変更するので、動作しているかどうかを簡単に確認できます。

ご意見ありがとうございます、ありがとうございます。

更新:私の主なExcelアプリケーションからの可視性をオフにしただけで、まだ私はCopyを使っている方法が新しいExcelアプリケーションを作成していると信じています。それを参照してください。そこに可視性をオフにする方法を誰かが知っていれば、それは非常に高く評価されます。

最終更新日:私が実行していたのと同じ問題が発生した場合、最初のアップデートで解決するはずですが、excel.exeが終了するまで停止することに注意することも重要です応用。私はWindowsフォームアプリケーションとしてレポートオートメーションコードです(同僚がファイルの場所などを与えることができます)。プログラムからポップアップウィンドウを閉じるまで、excel.exeプロセスが実行されます。おそらくガベージコレクトは、アプリケーションウィンドウを閉じるまで、または何らかの理由でexcel.exeのインスタンスにハングアップするまで実行されません。

+0

は、オブジェクト、元を閉じた、構築「を使用使用して...エンド」しようとしています。 "xlApp1 =新しいExcel.Applicationの使用"? –

+0

私はそれを知らなかった。それを実装するには、xlApp1から始まるすべてのものをラップしますか?私はそれが私の更新と一緒にコピー方法によって作成されている新しいExcelアプリケーションがあると思うようになるのかどうか分からない。 – asjohnson

+0

MSDNから、「コードでは、ファイルハンドル、** COMラッパー**、SQL接続など、アンマネージリソースが必要になることがあります。それは有望に見える、私はそれを試してみると表示されます。ありがとう。 – asjohnson

答えて

1

私はついに来たソリューションを追加することが追加されました

ループ。別のスタックオーバーフローポストのコメントThe first answerでこの答えが見つかりました。基本的に、私が持っていた問題は、worksheet.copyメソッドが参照なしでワークブックオブジェクトを作成することですが、それはactivesheetを参照することで参照できることが判明しています。私のようにドアを蹴っただけではなく、新しいワークブックオブジェクトを作成して割り当てることができると思います。あるいは、私が提案するリンクとして投稿しても、それを保存することもできます。私の恩人のために、それは私が望むワークシートを保存した後にそれを解放することはちょうどいいです、そして、これは私のexcel.exeのプロセスをぶら下げました。

もう少しエレガントなコードオプションが必要な場合は、私が作成したばかげたものの代わりに、私が正しくできないように管理していた各ループに対して、ron tornambeの投稿をチェックしてください。基本的には自分のコードでループを使いたいと思うでしょう。スタックオーバーフローのおかげでいつもありがとう。

以下
+0

問題から2,3日遅れて取り戻してから、それに戻っていくことは、あなたのアプローチを変えて解決策を生み出すことができます。 – asjohnson

+0

PIAライブラリではなく、NetOffice interopライブラリ(http://netoffice.codeplex.com)を参照してください。この種の厄介なケースに対処するために、いくつかのCOMリファレンスカウントが強化されており、異なるOfficeバージョンをターゲットにするという利点があります。 – Govert

+0

提案をありがとう、私は見てみましょう。 COMの参照をあまりひどくしないものは、私が興味を持っているものです。 – asjohnson

1

これは非常に簡単なワークシートのフォームです。ご質問がある場合はお知らせください。

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
    'Get information from text boxes 
    Dim InputLocation As String 
    Dim OutputLocation As String 

    InputLocation = InputLoc.Text & "\" & Filename.Text 

    If OutputLoc.Text = "" Then 
     OutputLocation = InputLoc.Text 
    Else 
     OutputLocation = OutputLoc.Text 
    End If 

    'Make file to save files in 
    ' Get date and time in filename as well 
    Dim TLDateTime As String 
    Dim TLDay As String 
    Dim TLMonth As Integer 
    Dim TLYear As Integer 
    Dim TLHour As Integer 
    Dim TLMinute As Integer 
    Dim TLDate As String 
    Dim TLTime As String 
    Dim TLSecond As Integer 

    TLDay = DateTime.Now.Day 
    TLMonth = DateTime.Now.Month 
    TLYear = DateTime.Now.Year 
    TLHour = DateTime.Now.Hour 
    TLMinute = DateTime.Now.Minute 
    TLSecond = DateTime.Now.Second 

    Dim MyDate As New DateTime(TLYear, TLMonth, TLDay, TLHour, TLMinute, TLSecond) 
    Dim MyString As String = MyDate.ToString("MMMddyyyy_HHmmss") 
    TLDate = TLMonth.ToString + TLDay.ToString + TLYear.ToString 
    TLTime = TLHour.ToString + TLMinute.ToString 
    TLDateTime = TLDate + "_" + TLTime 

    Try 
     Directory.CreateDirectory(OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime) 
     OutputLocation = OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime 
    Catch 
     MsgBox("Trying to create a file that exists, please delete it. If the file does not exist check to make sure your output location exists") 
    End Try 

    'Open up excel file with information in it 
    Dim xlApp1 As Excel.Application = New Excel.Application 
    xlApp1.Visible = True 
    xlApp1.Application.DisplayAlerts = False 

    Dim locs As Excel.Workbook 
    locs = xlApp1.Workbooks.Open(InputLocation) 
    Dim fileNames As New ArrayList 
    Dim counter As Integer = 1 
    For Each ws As Excel.Worksheet In locs.Worksheets 
     fileNames.Add(ws.Name) 
     ws = xlApp1.Workbooks(counter).Sheets(1) 
     ws.SaveAs(Filename:=OutputLocation & "\" & fileNames(counter - 1) & ".xlsx") 
     'close excel and release com objects 
     System.Runtime.InteropServices.Marshal.ReleaseComObject(ws) 
     xlApp1.Workbooks(counter).Close(False) 
     counter += 1 
    Next 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(locs) 
    locs = Nothing 
    xlApp1.Quit() 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1) 
    xlApp1 = Nothing 
End Sub 
+0

私はそれを実行し、それがどのように行くのか見てみましょう。ありがとう!型「システムをインタフェースするIDisposableを=新まずExcel.Application InvailidCastExceptionが未処理だったようxlApp1を使用して タイプのCOMオブジェクトをキャストできません「Microsoft.Office.Interop.Excel.ApplicationClass」: – asjohnson

+0

私はそれを実行すると、私は上のエラーを取得します.IDisposable '。次のエラーのため、IID '{805D7A98-D4AF-3F0F-967F-E5CF45312D2C}'のインターフェイスのCOMコンポーネントのQueryInterface呼び出しが失敗しました:このようなインターフェイスはサポートされていません(HRESULTからの例外:0x80004002(E_NOINTERFACE)) 。 – asjohnson

+0

Dang、コメントで書式設定できますか、それともいつも混乱しますか?私はコードのために4スペースのものを試みましたが、愛はありませんでした。いずれにしても、コンパイル時にそのキャスト例外を取得しないでください。 – asjohnson

1

あなたが作成されて参照されていないCOMオブジェクトがある場合は、以下を実行する必要があるかもしれません:このMSDNフォーラムのポストから撮影

GC.Collect() 
GC.WaitForPendingFinalizers() 

http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/cb5f7948-c229-483e-846b-a1cfbbcd86ca/

+0

あなたは知っています、私はそこに(2回連続して私が読んだことを読んでいたものですが)持っていましたが、私が出てきた投稿のためにそれを削除しました私は今それを見つけることができません)あなたがそれを使用する方法を知っていない限り、あなたはそれを使用すべきではない、おそらく単に悪化させるので、私はそれを取り出した。私はちょうどそれに戻って(ちょうど場合との最後とループで試して)を追加し、私はまだexcel.exeのぶら下げインスタンスがあります。私はそれを削除したためかもしれないと思ったときに良い提案、私は秒間、私は正直言った。 – asjohnson

3

(重要である私は、オブジェクトを解放することNOTEオーダー、)私のために動作するコードです

xlWorkBook.Close() 
xlApp.Quit() 
ReleaseObject(xlWorkSheet) 
ReleaseObject(xlWorkBook) 
ReleaseObject(xlApp) 

Private Sub ReleaseObject(ByVal obj As Object) 
    Try 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) 
    obj = Nothing 
    Catch ex As Exception 
    obj = Nothing 
    Finally 
    GC.Collect() 
    End Try 
End Sub 
関連する問題