Domanda

Nella nostra applicazione # WinForms C, generiamo file PDF e di lancio di Adobe Reader (o qualunque sia il gestore .pdf sistema predefinito è) tramite la classe Process. Dal momento che i nostri file PDF possono essere di grandi dimensioni (circa 200K), gestiamo l'evento Exited per poi ripulire il file temporaneo in seguito.

Il sistema funziona come previsto quando si apre un file e poi richiuso. Tuttavia, quando si apre un secondo file (prima di chiudere Adobe Reader), il secondo processo immediatamente uscite (dal Reader è ora usando il suo potere MDI) e nel nostro gestore Exited nostra chiamata File.Delete dovesse fallire perché è bloccato dal processo di Adobe ora uniti . Tuttavia, in Reader che invece otteniamo:

C'è stato un errore l'apertura di questo documento. Questo file non può essere trovato.

La cosa insolita è che se metto un punto di interruzione debugger prima che l'eliminazione dei file e consentire a tentare (e non riescono) la cancellazione, poi le si comporta di sistema come previsto!

Sono positivo che il file esista e abbastanza positivo che tutte le maniglie / file di flussi al file sono chiusi prima di avviare il processo.

Stiamo lanciando con il seguente codice:

// Open the file for viewing/printing (if the default program supports it) 
var pdfProcess = new Process();
pdfProcess.StartInfo.FileName = tempFileName;
if (pdfProcess.StartInfo.Verbs.Contains("open", StringComparer.InvariantCultureIgnoreCase))
{
    var verb = pdfProcess.StartInfo.Verbs.First(v => v.Equals("open", StringComparison.InvariantCultureIgnoreCase));
    pdfProcess.StartInfo.Verb = verb;
}
pdfProcess.StartInfo.Arguments = "/N"; // Specifies a new window will be used! (But not definitely...)
pdfProcess.SynchronizingObject = this;
pdfProcess.EnableRaisingEvents = true;
pdfProcess.Exited += new EventHandler(pdfProcess_Exited);

_pdfProcessDictionary.Add(pdfProcess, tempFileName);

pdfProcess.Start();

Nota:. Stiamo usando il _pdfProcessDictionary per memorizzare i riferimenti al processo di oggetti in modo che rimangano nella portata in modo tale evento Exited può essere sollevato con successo

La nostra pulizia / evento terminato è:

void pdfProcess_Exited(object sender, EventArgs e)
{
    Debug.Assert(!InvokeRequired);
    var p = sender as Process;
    try
    {
        if (_pdfProcessDictionary.ContainsKey(p))
        {
            var tempFileName = _pdfProcessDictionary[p];
            if (File.Exists(tempFileName)) // How else can I check if I can delete it!!??
            {
                // NOTE: Will fail if the Adobe Reader application instance has been re-used!
                File.Delete(tempFileName);
                _pdfProcessDictionary.Remove(p);
            }

            CleanOtherFiles(); // This function will clean up files for any other previously exited processes in our dictionary
        }
    }
    catch (IOException ex)
    {
        // Just swallow it up, we will deal with trying to delete it at another point
    }
}

Possibili soluzioni:

  • Rileva che il file è ancora aperto in un altro processo
  • Rileva che il secondo processo è in realtà non è completamente chiuso e che il file viene aperto nel primo processo, invece
È stato utile?

Soluzione

I solo affrontato questo un paio di giorni fa.

Quando non v'è alcuna istanza aprire già, il documento si apre in una nuova istanza direttamente.

Quando c'è un'istanza già aperta, credo che genera esempio una nuova istanza, che in realtà non ottenere un handle. Quello che succede è il controllo ritorna alla funzione immediatamente, che poi va ed elimina il file prima che la nuova istanza ha avuto la possibilità di leggere il file -. Da qui sembra non esserci

I "risolto" questo non eliminando i file immediatamente, ma tenere traccia dei percorsi in un elenco, e poi bombardare tutti loro quando si chiude il programma (avvolgere ogni eliminazione in un try / catch con un blocco catch vuoto caso il file è scomparso nel frattempo).

Altri suggerimenti

Vorrei suggerire seguente approccio:

  1. Crea file nella directory temp dell'utente ( Path.GetTempPath ). È possibile creare un po 'di sottocartella sotto di esso.
  2. Tentativo di eliminare i file solo quando ultima istanza di processo viene terminato (cioè è necessario contare il numero di processi che si era lanciato, in uscita, diminuire il conteggio e quando diventa zero, tentare di eliminare i file (tutti) che sono aprire finora)
  3. Prova a sottocartella clean-up creato (nella directory temp) durante l'avvio e termina l'applicazione. Si può anche tentare di periodica timer di clean-up utilizzando.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top