データアクセス後にC#でExcelアプリケーションプロセスを閉じる


86

読み取り/書き込み操作用の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;

この質問これなどのスタックオーバーフローで同様の質問が表示され、回答がテストされますが、機能しません。


ExcelとWordは非常に遅く、偶然見つけたような癖がたくさんあります。ファイルは、いくつかのXMLおよびその他のコンテンツを含むzipファイルです。ドキュメントを開くことができるOpenXML SDK(またはもっと新しいもの)もあります。このようなコードは、Officeをローカルにインストールしなくても機能します。Excelを使用しないことを検討してください
Sten Petrov

回答:


94

これを試して:

excelBook.Close(0); 
excelApp.Quit();

ワークブックを閉じるとき、3つのオプションのパラメーターがあります。

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)または、遅延バインディングを実行している場合は、ゼロを使用する方が簡単な場合があります。 Workbook.Close(0) これは、ブックの閉じを自動化するときに行った方法です。

また、私はそのドキュメントを調べて、ここで見つけました: Excel Workbook Close

ありがとう、


おかげで親愛なるマイケル、それは正しく動作します:excelBook.Close(0)
Javad Yousefi 2013

こんにちはみんなこれはあなたが読むためにExcelファイルを開いているときに機能していません。以下は、コードvar excelApp = new Application();です。var workBooks = excelApp.Workbooks.Open @ "c:\ temp \ myexcel.xlsx"); workBooks.Close(0); excelApp.Quit();
user1131926 2013

applicationClassを使用しました...上記のコードを使用してオブジェクトを
破棄しました

3
これらすべての回答で何度も失敗した後、私はこのソリューションを使用して、開いたプロセスIDを取得し、直接強制終了しました。
UndeadBob 2017年

@Singaravelan:デビッド・クラークの答えを確認しましたか?
–ThếAnhNguyễn 2017

22
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

これを試してください..それは私のために働きました...あなたはプロセスを停止するためにそのxlアプリケーションオブジェクトを解放するべきです。


14

参照: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);

これをaでラップし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);
}

2
これは私にとってはうまくいき、ワークブックを変数に割り当ててクリアできるようにしました。また、1つの観察結果として、WebアプリケーションとコンソールアプリケーションのExcelアプリをクリアするためのまったく同じコードがありました。ダブルドットを取り除く更新前のコードは、コンソールアプリでは正常に機能しましたが、Webアプリで実行すると、EXCEL.EXEがクリアされませんでした。なぜ動作が異なるのかわかりませんが、二重ドット参照を削除すると、Webアプリで修正されました。
IronHide 2015年

私のために働いています。comobjectをリリースするには、関連するすべてのオブジェクトをリリースする必要があると思います。solidworksプログラムについても同じ問題がありました。
Gsを。

1
ブックを閉じ、Excelアプリケーションを終了し、二重ドット呼び出しを避け、作成されたすべてのCOMオブジェクトを解放します。それは私のために働いた。命を救う答え。ありがとう。
SinanILYAS19年

13

これを考えてください、それはプロセスを殺します:

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

回答ありがとうございます。最初の解決策では、開いているすべてのExcelファイルが閉じます。「excelBook.Close」を使用すると、Excelの保存ダイアログが表示されますが、必要ありません:(
Javad Yousefi 2013

1
私はそれを編集し、ダイアログをコードに置き換えるコードでsaveAsを実行する行を追加しました。それが役立つことを願っています。:)
Morris Miao

1
これを開いているExcelプロセスの初期チェックで使用し、IDをリストに保存しました。次に、新しいExcelプロセスを作成し、編集を行い、IDリストに含まれていないExcelプロセスをすべて閉じました。
182764125216 2014年

タスクマネージャからExcelを解放する正しい方法ではありません。WorkBOoksなどのバックグラウンドで作成されたオブジェクトを含め、作成されたすべてのオブジェクトを解放する必要があります。
ehh 2016

このようにして、実行中のすべてのExcelプロセスを強制終了します。問題は、Excelを同時に使用している他のユーザーまたはアプリケーションが存在する可能性があることです。あなたがこれをする気があるかどうかだけ覚えておいてください。
SinanILYAS19年

5

Excelを強制終了するのは必ずしも簡単ではありません。この記事を参照してください:Excelを殺す50の方法

この記事は、マイクロソフトからの最良のアドバイスを取り入れています(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

これが私のために働いた唯一の解決策でした。ありがとう。
ジョン投票

2

私は同じ問題に遭遇し、それを解決するために多くの方法を試しましたが、機能しません。ついに、途中で見つけました。いくつかの参照はここにリンクの説明を入力します

私のコードが誰かの将来に役立つことを願っています。私はそれを解決するために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();
                    }        
                }
            }

1

excelBook.Close(); excelApp.Quit(); コードの終わりを追加すれば、それで十分かもしれません。それは私のコードに取り組んでいます


はい。ただし、使用すると保存ダイアログが表示されますが、表示したくないです:(
Javad Yousefi 2013

1

あなたはあなた自身のCOMオブジェクトでプロセスを殺すことができます優れた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();
                }
            }

1

ループMarshal.ReleaseComObject内にあり、ガベージコレクションでWhile終了することが重要であることがわかりました。

static void Main(string[] args)
{
    Excel.Application xApp = new Excel.Application();
    Excel.Workbooks xWbs = xApp.Workbooks;
    Excel.Workbook xWb = xWbs.Open("file.xlsx");

    Console.WriteLine(xWb.Sheets.Count);

    xWb.Close();
    xApp.Quit();

    while (Marshal.ReleaseComObject(xWb) != 0);
    while (Marshal.ReleaseComObject(xWbs) != 0);
    while (Marshal.ReleaseComObject(xApp) != 0);

    GC.Collect();
    GC.WaitForPendingFinalizers();
}

0
         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秒のプロセスを閉じます


0

すべての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 { }
    }
}

0

別のソリューションに基づいています。私はこれを使用しました:

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:これは私のアプリケーション相互運用エクセルオブジェクトです


0

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);
        }
}

0

次のコードを使用して、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);
   }

0

ほとんどの方法は機能しますが、Excelプロセスはアプリケーションを閉じるまで常に残ります。

一度Excelプロセスを強制終了すると、同じスレッドでもう一度実行することはできません-理由はわかりません。


-1
        GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
        wb.Close(true,Missing.Value,Missing.Value);
        app.Quit();
        System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
        foreach (System.Diagnostics.Process p in process)
        {
            if (p.Id == iProcessId)
            {
                try
                {
                    p.Kill();
                }
                catch { }
            }
        }
}
[DllImport("user32.dll")]

private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

uint iProcessId = 0;

このGetWindowThreadProcessIdは、excellの正しいプロセスIDを見つけます....それを強制終了した後....お楽しみください!!!


-1
private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

このコードは問題を解決する方法と理由の説明含めて質問を解決するかもしれませ んが、投稿の品質を向上させるのに本当に役立ち、おそらくより多くの賛成票をもたらすでしょう。あなたは今尋ねている人だけでなく、将来読者のために質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提条件を示してください。
デイブ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.