2009-01-22 5 views
6

Ho implementato un processo di auto aggiornamento dove il mio exe dell'applicazione principale avvia un programma di aggiornamento che passa un handle a se stesso sulla riga di comando. L'applicazione exe chiama ExitProcess per uscire e il programma di aggiornamento chiama WaitForSingleObject sull'handle passato per attendere la chiusura dell'exe dell'applicazione.Quando Windows invia un segnale al processo?

WaitForSingleObject attende. Fino a quando l'applicazione chiama ExitProcess, il programma di aggiornamento si blocca.

Tuttavia, a volte, quando il programma di aggiornamento tenta di sovrascrivere le dll dell'applicazione con le nuove versioni, viene visualizzato un errore di blocco file che la versione corrente del mio programma di aggiornamento considera un errore irreversibile e termina. Sembra che includere un sonno arbitrario (100) sia sufficiente per aggirare questo "problema" ma odio davvero il codice in questo modo. davvero odio.

Mi sembra molto strano che l'handle del processo possa essere segnalato mentre l'applicazione principale è ancora attiva per avere i file dll bloccati.

risposta

1

Come un'altra risposta fa notare, la maniglia processo ottiene segnalata quando il processo è arrestato esecuzione e il sistema operativo potrebbe richiedere più tempo per rilasciare DLL.

Hai ragione che affidarsi a Sleep (100) è una cattiva idea.Si dovrebbe piuttosto avvolgere sovrascrivere le DLL in un ciclo come questo:

BOOL UpdateDll(LPCTSTR dll_name, WHATEVER whatever) { 
    int tries = 150; 
    while (tries--) { 
    if (TryUpdateDll(dll_name, whatever)) 
     return TRUE; 
    Sleep(200); 
    } 
    return FALSE; 
} 

Questo continua a cercare di scaricare la DLL per 30 secondi e poi si arrende. 30 secondi dovrebbero essere sufficienti anche quando il sistema è sotto carico pesante, ma comunque proteggerà il tuo updater dall'impiccarsi per sempre. (Nel caso UpdateDll restituisca FALSE, assicurati di presentare un messaggio di errore significativo all'utente, indicando il nome della DLL incriminata.)

Se stai scherzando con COM, potrebbe anche essere utile una chiamata a CoFreeUnusedLibraries prima di uscire. (http://msdn.microsoft.com/en-us/library/ms679712.aspx) Francamente non so se la COM potrebbe conservare le DLL anche dopo che il processo è terminato, ma meglio essere al sicuro.

La linea di fondo è che c'è molta stranezza nell'API Win32. Non devi affrontare ogni caso finché trovi una soluzione accettabile. Ovviamente Sleep (100) potrebbe rompersi, ma un loop di polling di 30 secondi mi sembra accettabile.

2

Il processo segnala quando il codice dell'applicazione viene chiuso. Potrebbe essere necessario un po 'più di tempo per il sistema operativo per scaricare completamente il processo. Il punto di segnalazione è "Ho finito di fare quello che devo fare", è più efficace rilasciare altro codice che potrebbe avere cose veramente utili da fare invece di fare in modo che il codice attenda mentre il sistema operativo esegue alcune operazioni di manutenzione.

+0

Sembra che, in pratica, l'handle del processo venga segnalato non appena esiste un codice di uscita valido per il ritorno da GetExitCode(). Tuttavia, in termini di casi di utilizzo comuni, le app che sono più probabilmente in attesa di handle di processo sono installatori/updaters che devono sapere quando sono in grado di eliminare elementi. –

0

Potrebbe essere che le DLL siano bloccate da qualche altro processo al momento. Un modo per testare questo sarebbe quello di generare un report di ciò che è trattenuto nella DLL quando questo accade.

0

Ho visto un'eruzione di questi con alcuni software antivirus circa sei mesi fa. Prova senza AV e, per lo meno, assicurati che l'AV sia aggiornato.

0

Se una delle DLL in uso utilizzano le discussioni, non possono terminare (o partecipare) abbastanza veloce se non si scarica esplicitamente loro- che naturalmente verificare se fossero stati caricati in modo esplicito utilizzando LoadLibrary

Date un'occhiata qui: http://msdn.microsoft.com/en-us/library/ms682596(VS.85).aspx

In particolare questa linea:

... la DLL viene scaricato quando il processo termina o chiama il FreeLib funzione rary e il conteggio di riferimento diventa zero. Se il processo termina come risultato della funzione TerminateProcess o TerminateThread , il sistema non chiama la funzione di punto di ingresso DLL .

0

una possibile correzione per voi ... mentre non è possibile sostituire dll che è in uso, è possibile rinominarlo. quindi se hai una DLL che devi sostituire, ma è in uso per qualche motivo, rinominala in .delete o qualcosa del genere. fare l'aggiornamento, quindi fare in modo che il programma principale cerchi tutti i file .delete e rimuoverli all'avvio.

-don