Chiusura del processo dell'applicazione Excel in C # dopo l'accesso ai dati


88

Sto scrivendo un'applicazione in C # che apre un file modello Excel per operazioni di lettura / scrittura. Voglio che quando l'utente chiude l'applicazione, il processo di applicazione di Excel sia stato chiuso, senza salvare il file di Excel. Vedi il mio Task Manager dopo più esecuzioni dell'app.

inserisci qui la descrizione dell'immagine

Uso questo codice per aprire il file excel:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");

e per l'accesso ai dati utilizzo questo codice:

Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

Vedo domande simili in stackoverflow come questa domanda e questa e test le risposte, ma non funziona.


Excel e Word sono molto lenti e presentano un sacco di stranezze come quella in cui ti sei imbattuto. I file sono file zip con alcuni XML e altri contenuti. C'è anche Open XML SDK (o forse qualcosa di più recente) che può aprire i documenti. Tale codice funziona anche senza Office installato localmente. Considera di non utilizzare Excel
Sten Petrov

Risposte:


97

Prova questo:

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

Alla chiusura del libro di lavoro, hai tre parametri opzionali:

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)o se stai eseguendo un binding tardivo, a volte è più facile usare zero. Workbook.Close(0) Ecco come l'ho fatto quando automatizzo la chiusura delle cartelle di lavoro.

Inoltre sono andato a cercare la documentazione e l'ho trovata qui: Excel Workbook Close

Grazie,


Grazie Caro Michael, Funziona correttamente: excelBook.Close (0)
Javad Yousefi

Ciao ragazzi, questo non funziona quando apri un file Excel per la lettura. Di seguito è riportato il codice var excelApp = new Application (); var workBooks = excelApp.Workbooks.Open @ "c: \ temp \ myexcel.xlsx"); workBooks.Close (0); excelApp.Quit ();
user1131926

Ho usato applicationClass ... e ho usato il codice sopra per smaltire gli oggetti ma non funziona ...
Singaravelan

3
Dopo molti tentativi falliti con tutte queste risposte, sono andato con questa soluzione per ottenere l'ID del processo che ho aperto e ucciderlo direttamente.
UndeadBob

@ Singaravelan: Hai controllato la risposta di David Clarke?
L'Anh Nguyen

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

prova questo .. ha funzionato per me ... dovresti rilasciare quell'oggetto applicazione xl per interrompere il processo.


14

Rif: https://stackoverflow.com/a/17367570/132599

Evita di usare espressioni di chiamata a doppio punto, come questa:

var workbook = excel.Workbooks.Open(/*params*/)

... perché in questo modo crei oggetti RCW non solo per la cartella di lavoro, ma per le cartelle di lavoro, e dovresti rilasciarlo anche tu (cosa non possibile se non viene mantenuto un riferimento all'oggetto).

Questo ha risolto il problema per me. Il tuo codice diventa:

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;

E poi rilascia tutti quegli oggetti:

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

Lo racchiudo in un try {} finally {}per garantire che tutto venga rilasciato anche se qualcosa va storto (cosa potrebbe andare storto?) Ad es

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
Questo ha funzionato per me, assegnando cartelle di lavoro a una variabile in modo che possa essere cancellata. Inoltre, un'osservazione, avevo esattamente lo stesso codice per cancellare l'app Excel nell'applicazione Web e nell'applicazione console. Il codice prima dell'aggiornamento per eliminare il doppio punto ha funzionato bene nell'app console ma quando è stato eseguito nell'app Web non ha cancellato EXCEL.EXE. Non sono sicuro del motivo per cui si sono comportati in modo diverso, ma l'eliminazione del riferimento a doppio punto lo ha risolto nell'app Web.
IronHide

lavorando per me. Penso che per rilasciare un oggetto, dobbiamo rilasciare tutti gli oggetti correlati. Ho avuto lo stesso problema con il programma SolidWorks.
Gs.

1
Chiudi la cartella di lavoro, esci dall'applicazione Excel, evita la chiamata a doppio punto e rilascia ogni singolo oggetto COM creato. Ha funzionato per me. Risposta salvavita. Grazie.
Sinan ILYAS

13

Pensa a questo, uccide il processo:

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 { }
    }
}

Inoltre, hai provato a chiuderlo normalmente?

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

Grazie per la tua risposta La tua prima soluzione chiude Tutti i file Excel aperti. Quando uso 'excelBook.Close', viene visualizzata la finestra di dialogo di salvataggio di Excel e non lo voglio :(
Javad Yousefi

1
L'ho modificato e aggiunto con una riga per eseguire il salvataggio Come nel codice che sostituirà la finestra di dialogo con il codice, spero che aiuti. :)
Morris Miao

1
L'ho appena usato con un controllo iniziale per i processi Excel aperti e ho salvato gli ID in un elenco. Quindi ho creato un nuovo processo Excel, ho eseguito le modifiche necessarie e chiuso qualsiasi processo Excel che non fosse contenuto nell'elenco ID.
182764125216

Non è il modo corretto per rilasciare excel dal task manager. Dovresti rilasciare tutti gli oggetti che sono stati creati, inclusi quelli che sono stati creati dietro le quinte come WorkBOoks.
ehh

In questo modo, uccideresti ogni singolo processo Excel in esecuzione. Il problema è che potrebbero esserci altri utenti o applicazioni che utilizzano Excel contemporaneamente. Tieni a mente se sei disposto a farlo.
Sinan ILYAS

6

Uccidere Excel non è sempre facile; vedi questo articolo: 50 modi per uccidere Excel

Questo articolo prende i migliori consigli da Microsoft ( articolo di base di MS Knowlege ) su come far chiudere bene Excel, ma poi si assicura anche che uccida il processo se necessario. Mi piace avere un secondo paracadute.

Assicurati di chiudere tutte le cartelle di lavoro aperte, chiudere l'applicazione e rilasciare l'oggetto xlApp. Infine controlla se il processo è ancora attivo e, in tal caso, uccidilo.

Questo articolo assicura anche che non terminiamo tutti i processi di Excel, ma solo il processo esatto che è stato avviato.

Vedi anche Ottieni processo dalla maniglia della finestra

Ecco il codice che uso: (funziona sempre)

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

Questa era l'unica soluzione che ha funzionato per me. Grazie.
Jon votare

2

Ho incontrato gli stessi problemi e ho provato molti metodi per risolverlo ma non funziona. Infine, ho trovato il a modo mio. Qualche riferimento inserisci qui la descrizione del link

Spero che il mio codice possa aiutare qualcuno in futuro. Ho impiegato più di due giorni per risolverlo. Di seguito è riportato il mio codice:

//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 (); aggiungi la fine del codice, potrebbe essere sufficiente. sta lavorando sul mio codice


Sì, ma quando lo uso, viene visualizzata la finestra di dialogo di salvataggio e non voglio che appaia :(
Javad Yousefi

1

Puoi terminare il processo con il tuo COMoggetto excel pid

aggiungi da qualche parte sotto il codice di importazione dll

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

e utilizzare

 if (excelApp != null)
            {
                int excelProcessId = -1;
                GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);

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

1

Ho scoperto che è importante avere Marshal.ReleaseComObjectun Whileciclo E finire con Garbage Collection .

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 { }
             }
         }

Chiude il processo degli ultimi 10 secondi con il nome "Excel"


0

Basato su altre soluzioni. Ho usato questo:

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 { }
                    }
                }

Utilizzando "MainWindowHandle" per identificare il processo e chiuderlo.

excelObj: questo è il mio oggetto excel di Application Interop


0

Usa una variabile per ogni oggetto Excel e devi eseguire il ciclo Marshal.ReleaseComObject >0. Senza il ciclo, il processo di Excel rimane ancora attivo.

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

Possiamo chiudere l'applicazione Excel durante la conversione da xls a xlsx utilizzando il codice seguente. Quando eseguiamo questo tipo di attività, l'applicazione Excel è in esecuzione nel task manager, dovremmo chiudere questo Excel che è in esecuzione in background. Interop è un componente Com, per rilasciare il componente com abbiamo utilizzato Marshal.FinalReleaseComObject.

 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

La maggior parte dei metodi funziona, ma il processo Excel rimane sempre fino alla chiusura dell'applicazione.

Quando uccidi il processo excel una volta non può essere eseguito di nuovo nello stesso thread, non so perché.


0

Il modo giusto per chiudere tutti i processi di Excel

var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
    _workbook.Close(0);
}

_excel.Quit();
_excel = null;

Utilizzando l'esempio di processo, questo potrebbe chiudere tutto il processo Excel a prescindere.

var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
    if (!string.IsNullOrEmpty(p.ProcessName)) {
        try {
            p.Kill();
        } catch { }
    }
}

Ciò eliminerà anche tutte le istanze legittime di Excel aperte al di fuori dell'ambiente VS. cioè diciamo che avevo un altro foglio di lavoro Excel aperto nell'attuale app Excel, beh il tuo codice uccide anche quello.
Mark

Grazie aggiornato le note.
Md. Alim Ul Karim

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

Ha funzionato per me.


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

questo GetWindowThreadProcessId trova l'ID di processo corretto o excell .... Dopo averlo ucciso .... Buon divertimento !!!


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

Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolve il problema aiuterebbe davvero a migliorare la qualità del tuo post e probabilmente si tradurrebbe in più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo alla persona che lo chiede ora. Si prega di modificare la risposta di aggiungere una spiegazione, e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni.
Dave
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.