2012-01-23 6 views
6

私はデバッグしているいくつかのコードで問題に遭遇しています。 Excel interopは、ブックからいくつかの値を抽出するために使用されます。ただし、プログラムが終了してもExcelは開いたままです。 、私は伝統的な解決策を試してみたが、それはまだコードが実行される場合Excelプロセスはinteropの後も開いたままです。従来のメソッドは動作しません

private void TestExcel() 
    { 
     Excel.Application excel = new Excel.Application(); 
     Excel.Workbooks books = excel.Workbooks; 
     Excel.Workbook book = books.Open("C:\\test.xlsm"); 

     book.Close(); 
     books.Close(); 
     excel.Quit(); 

     Marshal.ReleaseComObject(book); 
     Marshal.ReleaseComObject(books); 
     Marshal.ReleaseComObject(excel); 
    } 

のコードであっても、このシンプルな作品は、複数のファイル(XLSM、XLSXで実行中のプロセスを維持し、すべてのマシン上で開いているExcelへの参照を保持しますxls)。今すぐ開かれたExcelプロセスを強制終了するための回避策がありますが、私は自分の正気のためにこれを働かせる方がはるかです。

私はそれをWorkbook変数に絞り込んだことを付け加えておきます。 books.Open()へのコールを削除し、bookへの参照をすべて削除すると、正常に終了します。

+0

テストしたときにコードが正常に機能しましたが、実行時に例外が発生する可能性がありますか? – msmucker0527

答えて

11

これは私のために成功してきました);このコードで任意の明白な問題を指摘すること自由に感じ、私は本当に遠くCOM-読み書きされてからです

// Store the Excel processes before opening. 
Process[] processesBefore = Process.GetProcessesByName("excel"); 

// Open the file in Excel. 
Application excelApplication = new Application(); 
Workbook excelWorkbook = excelApplication.Workbooks.Open(Filename); 

// Get Excel processes after opening the file. 
Process[] processesAfter = Process.GetProcessesByName("excel"); 

// Now find the process id that was created, and store it. 
int processID = 0; 
foreach (Process process in processesAfter) 
{ 
    if (!processesBefore.Select(p => p.Id).Contains(process.Id)) 
    { 
     processID = process.Id; 
    } 
} 

// Do the Excel stuff 

// Now close the file with the COM object. 
excelWorkbook.Close(); 
excelApplication.Workbooks.Close(); 
excelApplication.Quit(); 

// And now kill the process. 
if (processID != 0) 
{ 
    Process process = Process.GetProcessById(processID); 
    process.Kill(); 
} 
+2

これは正しいため、答えとしてマークされています。それはまだ私の開発マシンで動作していませんが、これはクリーンインストールまたは私の家のコンピュータで動作します。奇妙な – bradenb

3

私はCOMのアマチュアですが、それはかなり長い時間前に小さなプロジェクトに使用されていましたが、ここで使用したスニペットです。私はたぶんそれをどこかのオンラインで見つけた、覚えていない。いずれにせよ、私はそれにその完全な栄光を貼り付け;)

public static class ComBlackBox 
{ 
    public static void ReleaseObject(object obj) 
    { 
     try 
     { 
      System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
      obj = null; 
     } 
     catch (ArgumentException ex) 
     { 
      obj = null; 
      MessageBox.Show("Unable to release the Object " + ex.Message); 
     } 
     finally 
     { 
      GC.Collect(); 
     } 
    } 
} 

を私は今それを試してみることができないんだけど、それはおそらく(私は正直にすべての詳細を覚えていない)働きました。多分それがあなたを助けるでしょう。

 xlApp.Quit(); 

     //release all memory - stop EXCEL.exe from hanging around. 
     if (xlWorkBook != null) { Marshal.ReleaseComObject(xlWorkBook); } //release each workbook like this 
     if (xlWorkSheet != null) { Marshal.ReleaseComObject(xlWorkSheet); } //release each worksheet like this 
     if (xlApp != null) { Marshal.ReleaseComObject(xlApp); } //release the Excel application 
     xlWorkBook = null; //set each memory reference to null. 
     xlWorkSheet = null; 
     xlApp = null; 
     GC.Collect(); 
+1

最後に最後にtry catchにGC.Collect()があるため、この作業は部分的です。しかし、最終的な部分に到達するまでは、それは本当に終わらない。どうして ?シート/シート/ワークブックを渡すか、関数に秀でるならば、オブジェクトが値渡しされるからです。それらのCOM値は、オブジェクト自体で何をしていても同じままです。これらのCOMオブジェクトを参照渡しすることができない限り、私はそれを試しました。 –

2

これは私がこの問題を回避得た方法である:

0

このコードは私のために機能します。

//Declare separate object variables 
Excel.Application xlApp = new Excel.Application(); 
Excel.Workbooks xlWorkbooks = xlApp.Workbooks; 
Excel.Workbook xlWorkbook = xlWorkbooks.Add(Missing.Value); 
Excel.Worksheet xlWorksheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(1); 

//Create worksheet 

xlWorkbook.Close(false, Missing.Value, Missing.Value); 
xlWorkbooks.Close(); 
xlApp.Quit(); 

Marshal.FinalReleaseComObject(xlWorksheet); 
Marshal.FinalReleaseComObject(xlWorkbook); 
Marshal.FinalReleaseComObject(xlWorkbooks); 
Marshal.FinalReleaseComObject(xlApp); 

xlWorksheet = null; 
xlWorkbook = null; 
xlWorkbooks = null; 
xlApp = null; 

GC.Collect(); 

This article from Microsoftこの問題に関するいくつかの良い情報があります。

関連する問題