2009-05-08 15 views
9

È possibile acquisire il processo finale del task manager di un'applicazione Windows all'interno della stessa applicazione Windows stessa? Sto usando un'applicazione di vincita C# 2.0 e vorrei fare un po 'di elaborazione del database (cambiare un flag da' Y 'a' N 'nel DB) quando si verifica un processo finale.Gestione del processo finale di un'applicazione Windows

risposta

10

No, non è possibile agganciare la decisione del sistema operativo di terminare un processo. Nota, questo non viene fatto da task manger, terminando un processo è la responsabilità del kernel.

Sarà necessario fare due cose qui:

  1. Collegare i gestori di eventi per i normali messaggi di interfaccia utente che raccontano un'applicazione per uscire. Utilizza questi eventi per conservare dati, risorse gratuite e in caso contrario uscire in modo pulito.
  2. Gestire le eccezioni appropriate per rilevare gli errori, pulire e salvare i dati, se possibile.

Ecco tre collegamenti al blog di Raymond che spiegano perché non puoi fare ciò che stai chiedendo.

Inoltre, ho affrontato un simile StackOverflow domanda here.

+0

Sì, posso fare la gestione degli eventi. Tuttavia, se l'utente esegue un processo finale dal task manager, verrà comunque contrassegnato come "connesso" nel database e quando tenterà di accedere nuovamente, non gli sarà consentito. Ora so perché il messaggio di fine processo dice "Non puoi salvare alcun dato non salvato ... ecc." –

+0

Giusto - questo è di progettazione Immagina se Windows lascia che un'app agganci la chiamata a TerminateProcess() che è quale task manager L'utilità di pianificazione non è progettata per essere utilizzata per la normale conclusione di un processo - è una pistola - è pensata per uccidere i processi, non per terminarli in modo ordinato L'intenzione è nobile! Tutti i processi devono cercare di pulire e i dati persistono in modo affidabile, ma se l'utente desidera che il processo venga interrotto, TerminateProcess() lo eseguirà proprio lì. – Foredecker

+0

Tutto ciò suona come Rashmi P. non vede la foresta dagli alberi. La connessione DB deve timeout sul lato server. Il nuovo processo creerà una nuova connessione, ergo no problem-o. – GregC

1

È possibile ottenere l'ID processo e monitorare il processo ed è possibile utilizzare la proprietà HasExited per verificare se il processo è terminato o meno. Di seguito è riportato un codice VB rapido (Scusate non ho VS ora. Questo è stato scritto da me in un altro forum)

Public Class Form1 
    Dim p As ProcessStartInfo 
    Dim process As Process 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     p = New ProcessStartInfo("iexplore.exe") 
     process = process.Start(p) 
    End Sub 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 
     MsgBox(process.Id) 
     If process.HasExited Then 
      MsgBox("yes") 
     Else 
      MsgBox("no") 
     End If 
    End Sub 
End Class 

Sopra codice inizia il pulsante controlla se il processo è fine o meno InternetExplorer e. È possibile utilizzare un processo simile per ottenere tutto il processo in esecuzione e utilizzare il processID.

+0

hey Shoban, posso catturare un processo esterno fine app (notepad iexplorem, ecc) utilizzando il tuo codice.Ma cosa devo fare per acquisire l'attività finale sulla stessa app (quella che contiene Form1 nel codice ur sopra) –

+0

Ha detto "all'interno della stessa applicazione Windows". –

+1

Non puoi farlo nella stessa app, quindi l'idea di Shoban è il più vicino possibile. – RichieHindle

1

Non penso che sia possibile farlo dall'interno dell'applicazione. Lo scopo di End Task è quello di interrompere immediatamente il processo. Questo non consente l'esecuzione di alcun codice di pulizia.

Shoban ha indicato un altro modo per raggiungere il tuo obiettivo. Un'altra applicazione o servizio dovrebbe cercare il processo principale. Quando l'altro processo non riesce a trovare il processo principale, è possibile eseguire l'elaborazione del database in quel punto.

3

Come su un approccio leggermente diverso:

Avere l'applicazione aggiorna un campo di data e ora per esempio LastPollDate ogni tanto mentre è in esecuzione e ha un campo separato, ad es. "AppTerminatedNormally" che si imposta su N e passa a Y se si ottiene un evento di chiusura del modulo.

Se l'app viene uccisa tramite Task Manager, la data non verrà più aggiornata e la tua AppTerminatedNormally sarà ancora no.

In questo modo è possibile eseguire una query che trova tutte le righe in cui LastPollDate ha più di 10 minuti e AppTerminatedNormally è N e tutte le sessioni terminate in modo anomalo.

+0

Questa è una buona strada da percorrere. Grazie – Sakthivel

2

Ti sputeranno tutti a questo post, ma qui va ...

Stai provando a risolvere il problema al livello sbagliato (ad esempio il codice di esecuzione nella tua app quando il kernal sta uccidendo l'app). Il vero problema è assicurare che il database rifletta correttamente la presenza (o l'assenza) delle sue applicazioni client.

Per risolvere questo, evitare che le applicazioni si trovino in uno "stato incongruente" tra le interazioni dell'utente. In altre parole, non avviare transazioni che non è possibile eseguire rapidamente, non scrivere dati in file che lasciano il file in uno stato semigrafico o illeggibile e non tenere le risorse esterne all'applicazione in modo incongruo stato al di fuori delle interazioni dell'utente. In altre parole, se la tua app non è impegnata a rispondere a un gestore di eventi, dovrebbe essere pronta a chiudere immediatamente.

Se segui la procedura precedente, troverai pochissimi scenari in cui è necessario "pulire rapidamente" prima di terminare. Al di fuori delle interazioni in cui un utente fa clic su "OK" o "Salva", ecc., Un'applicazione ben scritta dovrebbe essere in grado di sopravvivere alla risoluzione immediata senza danni permanenti o corruzione dei suoi archivi di dati.

Se è assolutamente necessario impostare un flag nel database all'uscita (che suona tipica di un modello utilizzato per rilevare se un utente è connesso o meno), quindi prendere in considerazione una delle seguenti alternative:

  1. Periodicamente (forse una volta ogni 30 secondi) inserisce/aggiorna un campo simile al timestamp nel database, per indicare in che modo un'applicazione è stata recentemente online. Altre applicazioni possono ispezionare questi timestamp per determinare la data in cui un'altra applicazione era online ... se il valore è negli ultimi 30 secondi, l'altra app è ancora opnline.

  2. Come giustamente suggerito da Woodhenge, creare un processo separato (idealmente un servizio) per monitorare lo stato dell'applicazione principale. I servizi Windows possono essere configurati per il riavvio automatico in caso di guasto del servizio. Questo processo di monitoraggio emetterà quindi timestamp al database.

noti che entrambi i suggerimenti sopra risolve il problema reale (rilevando se le applicazioni accedono al database) senza mai lasciare il database in uno "stato incongruente" (il flag suddetto è "Y" quando l'applicazione è effettivamente morto e la bandiera dovrebbe essere "N").

2

Se ci si rivolge Windows Vista (o superiore) potrebbe essere interessato al API RegisterApplicationRecoveryCallback ...

http://msdn.microsoft.com/en-us/library/aa373345.aspx

Esso consente di specificare una routine di richiamata nella vostra app che verrà richiamato quando il processo sta per bloccarsi. N.B. è solo per arresti anomali e non verrà chiamato automaticamente se il processo viene ucciso deliberatamente.

Puoi p/invocare questa API da C# (l'ho fatto), ma tieni presente che quando viene richiamata la tua chiamata la tua app è già in pessimo stato, e puoi fare pochissime ipotesi sul stato della tua memoria. Se si dispone di dati in memoria che si desidera utilizzare in questa routine, lo inserirò in un ambito statico con un ambito molto generale, in modo da avere la migliore possibilità di non essere "riordinato" durante la routine di callback piste.

Ci sono alcune altre API interessanti, legate a questo, che consentono di riavviare automaticamente la vostra applicazione dopo un guasto, ecc

+0

hey ringrazio Martin ... darò un'occhiata a questo :) –

Problemi correlati