2

この方法で、リスト内のExcelファイルから列データを取得しようとしています。

private void Form1_Load(object sender, EventArgs e)
        {
            Excel.Application xlApp = new Excel.Application();
            Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"D:/test.xlsx");
            Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[1];
            Excel.Range xlRange = xlWorksheet.UsedRange;

            int rowCount = xlRange.Rows.Count;
            int colCount = xlRange.Columns.Count;

            List<string> FirstColumnValues = new List<string>();
            List<string> SecondColumnValues = new List<string>();

            for (int row=1; row <= rowCount; row++)
            {
                for (int col = 1; col <= colCount; col++)
                {
                    switch (col)
                    {
                        case 1:
                            FirstColumnValues.Add(xlRange.Cells[row, col].Value2.ToString());
                            break;
                        case 2:
                            SecondColumnValues.Add(xlRange.Cells[row, col].Value2.ToString());
                            break;
                    }
                }
            }

            if (FirstColumnValues.Count != 0 && SecondColumnValues.Count != 0)
            {
                xlWorkbook.Close();
                xlApp.Quit();
                MessageBox.Show("Completed");
                Marshal.ReleaseComObject(xlRange);
                Marshal.ReleaseComObject(xlWorksheet);
                Marshal.ReleaseComObject(xlWorkbook);
                Marshal.ReleaseComObject(xlApp);
                xlApp = null;
            }
        }

問題は、プロセスEXCEL.EXEを適切に閉じるためにすべてのことを試みても、プロセスが閉じられないことです。Excelプロセスを適切に閉じることについてここに投稿された多くの質問があることを私は知っています。しかし、私は専門家ではなく、私ができることのほとんどすべてを試しました。まだ運がない。

だから、誰かがこのコードの何が問題なのか教えてもらえますか?そして、すべてのデータがリストに保存されているときに、プロセスを一度閉じるにはどうすればよいでしょうか。

4

4 に答える 4

4

この質問はすでに回答済みですが、同じ問題を解決しようとして見つけたものを共有したいと思いました。うまくいけば、誰かがこれが役に立つと思うでしょう。これはvb.netにありますが、翻訳できると確信しています。

Dim proc As System.Diagnostics.Process
        For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
            If proc.MainWindowTitle.ToString = "" Then
                proc.Kill()
            End If
        Next

アプリからExcelファイルを開いているときに、ウィンドウのタイトルがnullであることがわかりました。そのため、実行中のすべてのExcelプロセスを閉じる代わりに、タイトルのないプロセスを閉じました。

編集:

クリーンアップされていない残りの変数(基本的には2つのドットを使用して設定した変数)が見つからないためにプロセスを終了する場合は、少なくとも正しいExcelインスタンスを強制終了します。

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);

...

if (xlApp != null)
{
  GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), ref excelProcessId);

  Process ExcelProc = Process.GetProcessById(excelProcessId);
  if (ExcelProc != null)
  {
    ExcelProc.Kill();
  }

私は殺害プロセスを推奨していません。VSTOContribで適切にクリーンアップする必要があります。例:

using (var xlApp = new Microsoft.Office.Interop.Excel.Application().WithComCleanup())
于 2012-11-06T00:08:05.860 に答える
1

私は前にそこに行ったことがあります。これが私がそれを整理するのを本当に助けた記事です:

http://devcity.net/Articles/239/1/article.aspx

Excelは、プロセスの終了について非常に頑固なようです。System.Diagnostics.Processを使用してプロセスを強制終了する可能性が高くなります。

于 2012-09-21T12:12:25.933 に答える
1

おそらく、Marshal.FinalReleaseComObjecttry{}catch{}finally{}を使用して試してみることを検討してください。

この投稿を見たことがあるかどうかわからない場合は、洞察も得られる可能性があります。

于 2012-09-21T12:18:01.727 に答える
1

実行中のExcelインスタンスが最終的に(つまり、アプリケーションが終了したときに)終了するようにする最も簡単な方法は、最上位のオブジェクトをtry/finallyブロックでラップすることです。

Excel.Application xlApp;  
try{  
   xlApp = new Excel.Application();  
   ...do some work...  
}  
finally{  
   xlApp.DisableAlerts=True;  
   xlApp.Quit();  
   xlApp.DisableAlerts=False;  
   Marshal.ReleaseComObject(xlApp);  
}  

//If you don't mind having the Excel process kept alive for a while,  
//you don't even have to call ReleaseComObject() on the intermediate objects.  
//The runtime will eventually free the underlying COM objects.  

//If you want to clean up right away, your bookkeeping needs to be more thorough.  
//Every time you access a method or property that returns a runtime callable wrapper  
//(System.__ComObject), you'll need to assign them to a variable  
//and make sure Marshal.ReleaseComObject() is called.  

// More thorough bookkeeping...    
Excel.Application xlApp;  
try{  
   xlApp = new Excel.Application();  

   Excel.Workbooks xlWorkbooks = xlApp.Workbooks;  
   Excel.Workbook xlWorkbook = xlWorkbooks.Open(@"D:/test.xlsx");  
   Excel.Sheets xlSheets = xlWorkbook.Sheets;  
   Excel.Worksheet xlWorksheet = xlSheets[1];  
   Excel.Range xlRange = xlWorksheet.UsedRange;  

   ...inside the loop...  
   Excel.Range xlCell = xlRange.Cells[row, col];  
   FirstColumnValues.Add(xlCell.Value2.ToString());  
   Marshal.ReleaseComObject(xlCell);  

   ...inside the loop...  
   Excel.Range xlCell = xlRange.Cells[row, col];  
   SecondColumnValues.Add(xlCell.Value2.ToString());  
   Marshal.ReleaseComObject(xlCell);  

   ...do more work...  

   ...clean up...  
   Marshal.ReleaseComObject(xlRange);  
   Marshal.ReleaseComObject(xlWorksheet);  
   Marshal.ReleaseComObject(xlSheets);  
   Marshal.ReleaseComObject(xlWorkbook);  
   Marshal.ReleaseComObject(xlWorkbooks);  
}  
finally{  
   xlApp.DisableAlerts=True;  
   xlApp.Quit();  
   xlApp.DisableAlerts=False;  
   Marshal.ReleaseComObject(xlApp);  
}  
于 2013-03-15T23:35:12.517 に答える