L'applicazione di Office non si chiude dopo l'automazione dal client Visual Studio .NET

Si applica a
Visual Studio 2015

Vedere gli altri prodotti a cui si applica questo articolo.

Sintomi

Quando si automatizza un'applicazione di Microsoft Office da Microsoft Visual Basic .NET o Microsoft Visual C# .NET, l'applicazione di Office non viene chiusa quando si chiama il metodo Quit.

Causa

Quando Visual Studio .NET chiama un oggetto COM da codice gestito, crea automaticamente un Runtime Callable Wrapper (RCW). La RCW effettua il marshalling delle chiamate tra l'applicazione .NET e l'oggetto COM. La RCW mantiene un conteggio dei riferimenti sull'oggetto COM. Pertanto, se non tutti i riferimenti sono stati rilasciati in RCW, l'oggetto COM non si chiude.

Risoluzione

Per assicurarsi che l'applicazione di Office venga chiuso, determinare se il codice di automazione soddisfa i criteri seguenti:

  • Dichiarare ogni oggetto come nuova variabile. Ad esempio, modificare la riga di codice seguente:

    oBook = oExcel.Workbooks.Add()
    
    

    Apportare le seguenti modifiche:

    dim oBooks as Excel.Workbooks
    oBooks = oExcel.Workbooks
    oBook = oBooks.Add()
    
    
  • Utilizzare System.Runtime.InteropServices.Marshal.ReleaseComObject in un ciclo finché non restituisce 0 al termine dell'utilizzo di un oggetto. System.Runtime.InteropServices.Marshal.ReleaseComObject decrementa il numero di riferimenti di RCW e il ciclo verifica che il componente COM sottostante venga rilasciato indipendentemente dal numero di volte in cui è stato rientrato in CLR.

  • Per rilasciare il riferimento alla variabile, impostare la variabile su Nothing o Null.

  • Usare il metodo Quit dell'oggetto applicazione di Office per indicare al server di arrestarsi.

Stato

Questo è il comportamento da progettazione.

Altre informazioni

Passaggi per riprodurre il comportamento

  1. Avviare Visual Studio .NET.

  2. Scegliere Nuovo dal menu File e quindi fare clic su Proietta. In Progetti Visual Basic selezionare Applicazione Windows e quindi fare clic su OK.

    Nota Form1 viene creato per impostazione predefinita.

  3. Aggiungere un riferimento alla libreria di oggetti di Microsoft Excel. A questo scopo, procedere come segue:

    1. Scegliere Aggiungi riferimento dal menu Progetto.

    2. Nella scheda COM individuare la Raccolta oggetti per Excel e quindi fare clic su Seleziona.

      Per Microsoft Excel 2002: Libreria oggetti di Microsoft Excel 10.0

      Nota Se non è già stato fatto, è consigliabile scaricare e installare gli assembly di interoperabilità primario (PIA) di Microsoft Office XP.

      Per altre informazioni sui PIA di Office XP, vedere il seguente articolo della Microsoft Knowledge Base:

      328912 gli assembly di interoperabilità primario (PIA) di Microsoft Office XP sono disponibili per il download
       Per Microsoft Office Excel 2003: Libreria oggetti di Microsoft Excel 11.0

    3. Fare clic su OK nella finestra di dialogo Aggiungi riferimenti per accettare le selezioni.

  4. Nel menu Visualizza fare clic su Casella degli strumenti e quindi trascinare un controllo Button in Form1.

  5. Fare doppio clic su Button1.

    Nota Viene visualizzata la finestra del codice per il modulo.

  6. Aggiungere il codice seguente all'inizio di Form1.vb:

    Imports Microsoft.Office.Interop
    
    
  7. Sostituire il codice seguente nella finestra del codice:

        Private Sub Button1_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles Button1.Click
        End Sub
    
    

    Sostituire il codice seguente:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBook As Excel.Workbook = oApp.Workbooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        oSheet = Nothing
        oBook.Close(False)
        oBook = Nothing
        oApp.Quit()
        oApp = Nothing
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    
    
  8. Premere F5 per eseguire l'applicazione.

  9. Aprire Gestione attività di Windows. In Visual Studio, visualizzare la finestra Output per visualizzare i messaggi di debug. Fare clic sul pulsante di comando. Si noti che un'istanza di Excel.exe viene visualizzata nell'elenco Processi.

  10. L'istanza di Excel viene eseguita nell'elenco attività anche dopo che l'applicazione ha completato la modalità di sospensione. Chiudere la finestra di dialogo e notare che Excel non viene più visualizzato nell'elenco Processi.

  11. Quando si esezionano i passaggi nella sezione "Risoluzione", l'applicazione di Office viene chiuso dopo il rilascio dell'ultima variabile. Sostituire la funzione nel passaggio 5 usando il codice seguente:

      Private Sub NAR(ByVal o As Object)
        Try
          While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
          End While
        Catch
        Finally
          o = Nothing
        End Try
      End Sub
    
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBooks As Excel.Workbooks = oApp.Workbooks
        Dim oBook As Excel.Workbook = oBooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        NAR(oSheet)
        oBook.Close(False)
        NAR(oBook)
        NAR(oBooks)
        oApp.Quit()
        NAR(oApp)
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    
    

Se si usa Visual C# .NET, fare riferimento al codice per la funzione NAR():


private void NAR(object o)
{
    try 
    {
        while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) ;
    }
    catch {}
    finally 
    {
        o = null;
    }
}

Nota A partire da .NET Framework 2.0, è possibile utilizzare System.Runtime.InteropServices.Marshal.FinalReleaseComObject invece del ciclo while che chiama System.Runtime.InteropServices.Marshal.ReleaseComObject per ottenere lo stesso risultato.
 

Risoluzione dei problemi

Nota Se si seguono i passaggi descritti nella sezione "Passaggi per riprodurre il comportamento" e il server ancora non si arresta, è possibile utilizzare il GC. Collect() e gc. WaitForPendingFinalizers() (metodo) dopo il rilascio dell'ultimo oggetto. Poiché il runtime esegue garbage collection sul RCW, il GC. Il metodo Collect() forza l'esecuzione del Garbage Collector e potrebbe rilasciare eventuali riferimenti ancora presenti nella RCW. Il GC. Il metodo Collect() tenta di recuperare la memoria massima disponibile. Si noti che ciò non garantisce che tutta la memoria verrà recuperata.

Applicabile a

Questo articolo si applica anche a:

  • Microsoft Visual Basic .NET (tutte le edizioni)
  • Microsoft Visual C# .NET (tutte le edizioni)
  • Microsoft Office 2016 (tutte le edizioni)
  • Microsoft Office 2013 (tutte le edizioni)