Problema con Excel.Application

giovedì 29 ottobre 2009 - 12.09

Zixower Profilo | Newbie

Saluto tutti e battezzo il mio ingresso nel forum con la seguente domanda:

Sto sviluppando un'applicazione in VB.NET (1.0, vecchiotto, lo so, ma questa è la licenza che ho e questa devo usare). Alcune sezioni di questa applicazione generano dei report su file Excel. Il problema che mi si presenta è che anche dopo la chiusura dei file Excel o comunque la chiamata Quit e l'assegnazione di nothing all'oggetto Excel.Application, finché non si chiude la mia applicazione, rimane in memoria il processo EXCEL. Questo impedisce di aprire altri file Excel. Se si prova, compare la barra del titolo, menu e strumenti di Excel, ma l'area di lavoro rimane trasparente. Se chiudo la mia applicazione il processo sparisce ed a quel punto funziona tutto correttamente.

Questa è la parte di codice del form che avvia il thread che lavora sul file Excel:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Questa è la parte di codice della classe del thread richiamato dalla form:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Il codice in alcuni punti è "sporco" perché ho provato un sacco di combinazioni per risolvere il problema, ma nulla. Qualche idea?

Ringrazio già da adesso tutti quelli che cercheranno di dedicarmi del tempo per darmi una mano.

MarKonE Profilo | Guru

Ciao,

hai provato con Finalize ?

http://msdn.microsoft.com/en-us/library/0s71x931%28VS.71%29.aspx


Ciao!
My Blog... http://blogs.dotnethell.it/Mark/

Zixower Profilo | Newbie

Purtroppo non va. Non conoscevo finalize ed ho guardato un po' in giro per capire come funziona. Ho aggiunto alla fine della classe del thread il seguente codice (prima dell' "end class", per intenderci):

Protected Overrides Sub Finalize() MyBase.Finalize() End Sub

Se non ho capito male dovrebbe essere usato così. Se è corretto, purtroppo non ha risolto il problema.

Una cosa che non ho detto, è che le form sono MDI Child. Ho anche provato ad aprire la form non come MDI Child, senza assegnare il MDI Parent, ma il problema non si è risolto (le sto provando tutte). La prova l'ho fatta dato che il processo EXCEL non si chiude alla chiusura della form Child, ma alla chiusura della form Parent, che è la principale in cui si aprono tutte le form. Chiedo scusa per la dimenticanza.

Zixower Profilo | Newbie

Ho trovato un esempio che diceva di inserire GC.Collect e GC.WaitForPendingFinalizers due volte dopo il quit e l'assegnazione di nothing, cioé:

xlApplication.Quit xlApplication = Nothing GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.WaitForPendingFinalizers()

Ma nenche questa volta è cambiato nulla. E' un vero mistero.

alexmed Profilo | Guru

Ciao
è un accrocchio ma dovrebbe funzionare

Quando apri la tua applicazione crei una lista delle applicazioni in esecuzioni che corrispondano ad Excel con relativo PID.

Dopo che la tua applicazione avvia excel vai a fare di nuovo la ricerca e se ne hai una diversa a quelle rilevate prima memorizzi il nuovo PID.

Una volta che non hai più bisogno di Excel (xlApplication.Quit ... xlApplication = Nothing) vai a fare una ricerca tra i processi corrispondenti a quel PID, quindi una volta trovato farai Processo.Kill().

Ciao


alexmed

Zixower Profilo | Newbie

Buona idea. Non avevo pensato di lavorare sul PID (anche perché non so come farlo ). Avevo vagliato la possibilità di abbattere il processo, ma avevo il problema di rischiare di chiudere fogli aperti indipendentemente dalla mia applicazione. Adesso cerco documentazioni su come mettere in pratica la tua idea e provo. Grazie mille.

Zixower Profilo | Newbie

Chiedo scusa, dato che è passato molto tempo dalla risposta a quando ho effettivamente provato ad applicare la soluzione, che mi sono dimenticato di postarla.

Ho seguito il tuo suggerimento e funziona (grazie mille). Lo sviluppo non brilla in eccellenza, però funziona. Alla fine, dove non mi serve tenere aperto il file Excel generato, prima di creare l'oggetto, mappo i PID di tutti i processi Excel aperti, genero l'oggetto, e poi rimappo i processi Excel aperti. A questo punto memorizzi il PID che non trova riscontro nella prima mappatura. Quando chiudo tutto, dopo i vari salvataggi e QUIT, distruggo il processo utilizzando il PID memorizzato all'inizio:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

alexmed Profilo | Guru

Ciao
Ti passo la mia soluzione

Me.btnPREVIEW.Enabled = False Dim myOLDProcess As Process Dim allOLDProcess As Process() = Process.GetProcessesByName("EXCEL") 'ESEGUO EXCEL --------------------- ..... xlSheet = Nothing xlBook = Nothing xlApp = Nothing 'FINE EXCEL --------------------- System.Threading.Thread.Sleep(3000) Dim value As Boolean = False Dim killProcess As Integer Dim myNEWProcess As Process Dim allNEWProcess() As Process = Process.GetProcessesByName("EXCEL") If allOLDProcess.Length = 0 Then For Each myNEWProcess In allNEWProcess killProcess = myNEWProcess.Id Next Else For Each myNEWProcess In allNEWProcess Dim idProcess As Integer = myNEWProcess.Id For Each myOLDProcess In allOLDProcess If idProcess = myOLDProcess.Id Then value = False Else value = True End If Next If value = True Then killProcess = (myNEWProcess.Id) End If Next End If Dim exlProcess As Process = Process.GetProcessById(killProcess) exlProcess.Kill() Me.btnPREVIEW.Enabled = True

Ciao

alexmed

Zixower Profilo | Newbie

Nel mio programma ci sono elaborazioni abbastanza lunghe, che durano diversi minuti (dovuto anche al fatto che gran parte dei PC in azienda sono abbastanza datati). Con la tua soluzione, non rischio di andare a chiudere eventuali file Excel che l'utente si è aperto per i fatti suoi, mentre è in attesa della fine dell'esecuzione?

alexmed Profilo | Guru

Ciao
In quel caso temo di si. Perchè si basa sul concetto "controllo prima" - "controllo dopo" e se c'è qualcosa di diverso lo elimino.
Magari fai una prova.

Ciao

alexmed

Zixower Profilo | Newbie

Confermo che la soluzione che ho trovato funziona perfettamente. (alexmed, la tua soluzione nel mio caso non va bene, per il problema che ti ho esposto. Grazie lo stesso. ).

Posto la correzione della funzione Crea_Oggetto_Excel_con_Recupero_ID_Processo, che nella versione che vi ho precedentemente postato era buggata (in presenza di processi Excel preesistenti, restituiva PID=0).

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5