読み取り/書き込み操作のためにExcelテンプレートファイルを開くC#でアプリケーションを作成しています。ユーザーがアプリケーションを閉じると、Excelファイルを保存せずに、Excelアプリケーションプロセスが閉じられます。アプリを複数回実行した後、タスクマネージャーを参照してください。
このコードを使用してExcelファイルを開きます:
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");
そして、データアクセスのために私はこのコードを使用します:
Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
this question や this などのstackoverflowで同様の質問が表示され、回答をテストしますが、機能しません。
これを試して:
excelBook.Close(0);
excelApp.Quit();
ワークブックを閉じるとき、次の3つのオプションパラメータがあります。
Workbook.close SaveChanges, filename, routeworkbook
Workbook.Close(false)
または遅延バインディングを実行している場合、ゼロを使用する方が簡単な場合がありますWorkbook.Close(0)
これは、ブックのクローズを自動化するときに実行した方法です。
また、私は行って、そのドキュメントを調べて、ここで見つけました: Excel Workbook Close
おかげで、
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
これを試してください..それは私のために働いた...あなたはそのxlアプリケーションオブジェクトをリリースしてプロセスを停止する必要があります。
これを考えて、それはプロセスを殺します:
System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (!string.IsNullOrEmpty(p.ProcessName))
{
try
{
p.Kill();
}
catch { }
}
}
また、普通に閉じてみましたか?
myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
excelBook.Close(null, null, null); // close your workbook
excelApp.Quit(); // exit Excel application
Excel = null; // set to NULL
参照: https://stackoverflow.com/a/17367570/132599
次のような二重ドット呼び出し式の使用は避けてください。
var workbook = Excel.Workbooks.Open(/*params*/)
...この方法では、ワークブックだけでなくワークブック用にRCWオブジェクトを作成し、それもリリースする必要があります(オブジェクトへの参照が維持されていない場合は不可能です)。
これで問題は解決しました。コードは次のようになります。
public Excel.Application excelApp = new Excel.Application();
public Excel.Workbooks workbooks;
public Excel.Workbook excelBook;
workbooks = excelApp.Workbooks;
excelBook = workbooks.Add(@"C:/pape.xltx");
...
Excel.Sheets sheets = excelBook.Worksheets;
Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;
そして、それらすべてのオブジェクトを解放します。
System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
excelBook .Save();
excelBook .Close(true);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
これをtry {} finally {}
でラップして、何かがうまくいかなくてもすべてがリリースされるようにします(何がうまくいかない可能性がありますか)。
public Excel.Application excelApp = null;
public Excel.Workbooks workbooks = null;
...
try
{
excelApp = new Excel.Application();
workbooks = excelApp.Workbooks;
...
}
finally
{
...
if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}
Excelを強制終了するのは必ずしも簡単ではありません。この記事を参照してください: Excelを終了する50の方法
この記事では、Microsoftからの最善のアドバイス( MS Knowlege Base Article )を使用して、Excelを正常に終了する方法について説明しますが、必要に応じてプロセスを強制終了することでも確認します。 2番目のパラシュートが好きです。
開いているワークブックをすべて閉じ、アプリケーションを終了して、xlAppオブジェクトを解放してください。最後に、プロセスがまだ動作しているかどうかを確認し、動作している場合は終了します。
また、この記事では、すべてのExcelプロセスを強制終了するのではなく、開始された正確なプロセスのみを強制終了するようにします。
ウィンドウハンドルからプロセスを取得 も参照してください。
私が使用するコードは次のとおりです:(毎回動作します)
Sub UsingExcel()
'declare process; will be used later to attach the Excel process
Dim XLProc As Process
'call the sub that will do some work with Excel
'calling Excel in a separate routine will ensure that it is
'out of scope when calling GC.Collect
'this works better especially in debug mode
DoOfficeWork(XLProc)
'Do garbage collection to release the COM pointers
'http://support.Microsoft.com/kb/317109
GC.Collect()
GC.WaitForPendingFinalizers()
'I prefer to have two parachutes when dealing with the Excel process
'this is the last answer if garbage collection were to fail
If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
XLProc.Kill()
End If
End Sub
'http://msdn.Microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
ByRef lpdwProcessId As Integer) As Integer
End Function
Private Sub ExcelWork(ByRef XLProc As Process)
'start the application using late binding
Dim xlApp As Object = CreateObject("Excel.Application")
'or use early binding
'Dim xlApp As Microsoft.Office.Interop.Excel
'get the window handle
Dim xlHWND As Integer = xlApp.hwnd
'this will have the process ID after call to GetWindowThreadProcessId
Dim ProcIdXL As Integer = 0
'get the process ID
GetWindowThreadProcessId(xlHWND, ProcIdXL)
'get the process
XLProc = Process.GetProcessById(ProcIdXL)
'do some work with Excel here using xlApp
'be sure to save and close all workbooks when done
'release all objects used (except xlApp) using NAR(x)
'Quit Excel
xlApp.quit()
'Release
NAR(xlApp)
End Sub
Private Sub NAR(ByVal o As Object)
'http://support.Microsoft.com/kb/317109
Try
While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
End While
Catch
Finally
o = Nothing
End Try
End Sub
独自のCOM
オブジェクトExcel pidでプロセスを強制終了できます
dllインポートコードの下にどこかに追加します
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
そして使用する
if (excelApp != null)
{
int excelProcessId = -1;
GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExcelProc.Kill();
}
}
私は同じ問題に出会い、それを解決するために多くの方法を試しましたが、うまくいきません。最後に、私は自分の方法で見つけました。参照 リンクの説明をここに入力
私のコードが将来の誰かを助けることを願っています。私はそれを解決するために2日以上費やしました。以下は私のコードです:
//get current in useing Excel
Process[] excelProcsOld = Process.GetProcessesByName("Excel");
Excel.Application myExcelApp = null;
Excel.Workbooks excelWorkbookTemplate = null;
Excel.Workbook excelWorkbook = null;
try{
//DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
}
catch (Exception ex ){
}
finally
{
//Compare the Excel ID and Kill it
Process[] excelProcsNew = Process.GetProcessesByName("Excel");
foreach (Process procNew in excelProcsNew)
{
int exist = 0;
foreach (Process procOld in excelProcsOld)
{
if (procNew.Id == procOld.Id)
{
exist++;
}
}
if (exist == 0)
{
procNew.Kill();
}
}
}
excelBook.Close(); excelApp.Quit();コードの終わりを追加すれば、それで十分かもしれません。それは私のコードに取り組んでいます
ほとんどのメソッドは機能しますが、Excelプロセスは常にアプリケーションを閉じるまで残ります。
Excelプロセスを一度強制終了すると、同じスレッドで再度実行できなくなります。理由はわかりません。
wb.Close();
app.Quit();
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
{
try
{
p.Kill();
}
catch { }
}
}
「Excel」という名前の最後の10秒のプロセスを閉じます
別のソリューションに基づいています。私はこれを使用しています:
IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
excelObj.ActiveWorkbook.Close();
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
if (p.MainWindowHandle == xAsIntPtr)
{
try
{
p.Kill();
}
catch { }
}
}
「MainWindowHandle」を使用してプロセスを識別し、彼を閉じます。
excelObj:これは私のアプリケーション相互運用Excelオブジェクトです
すべてのExcelプロセスを閉じる正しい方法
var _Excel = new Application();
foreach (Workbook _workbook in _Excel.Workbooks) {
_workbook.Close(0);
}
_Excel.Quit();
_Excel = null;
var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
if (!string.IsNullOrEmpty(p.ProcessName)) {
try {
p.Kill();
} catch { }
}
}
各Excelオブジェクトに変数を使用し、Marshal.ReleaseComObject >0
をループする必要があります。ループがなければ、Excelプロセスはまだアクティブのままです。
public class test{
private dynamic ExcelObject;
protected dynamic ExcelBook;
protected dynamic ExcelBooks;
protected dynamic ExcelSheet;
public void LoadExcel(string FileName)
{
Type t = Type.GetTypeFromProgID("Excel.Application");
if (t == null) throw new Exception("Excel non installato");
ExcelObject = System.Activator.CreateInstance(t);
ExcelObject.Visible = false;
ExcelObject.DisplayAlerts = false;
ExcelObject.AskToUpdateLinks = false;
ExcelBooks = ExcelObject.Workbooks;
ExcelBook = ExcelBooks.Open(FileName,0,true);
System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
ExcelSheet = ExcelBook.Sheets[1];
}
private void ReleaseObj(object obj)
{
try
{
int i = 0;
while( System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
{
i++;
if (i > 1000) break;
}
obj = null;
}
catch
{
obj = null;
}
finally
{
GC.Collect();
}
}
public void ChiudiExcel() {
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
ReleaseObj(ExcelSheet);
try { ExcelBook.Close(); } catch { }
try { ExcelBooks.Close(); } catch { }
ReleaseObj(ExcelBooks);
try { ExcelObject.Quit(); } catch { }
ReleaseObj(ExcelObject);
}
}
次のコードを使用して、xlsをxlsxに変換しながらExcelアプリケーションを閉じることができます。この種のタスクを実行し、Excelアプリケーションがタスクマネージャーで実行されている場合、バックグラウンドで実行されているこのExcelを閉じる必要があります。 InteropはComコンポーネントであり、Marshal.FinalReleaseComObjectを使用してcomコンポーネントをリリースします。
private void button1_Click(object sender, EventArgs e)
{
Excel03to07("D:\\TestExls\\TestExcelApp.XLS");
}
private void Excel03to07(string fileName)
{
string svfileName = Path.ChangeExtension(fileName, ".xlsx");
object oMissing = Type.Missing;
var app = new Microsoft.Office.Interop.Excel.Application();
var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
wb.Close(false, Type.Missing, Type.Missing);
app.Quit();
GC.Collect();
Marshal.FinalReleaseComObject(wb);
Marshal.FinalReleaseComObject(app);
}