2009-08-23 16 views
17

Ho scritto qualche programma in Delphi e quando lo sto eseguendo da un disco su chiave. A un certo punto mi viene richiesto di scollegare il disco sulla chiave mentre l'applicazione è in esecuzione. Se lo faccio su un computer con almeno 1 GB di RAM, tutto va bene. Quando lo faccio su una macchina con 512mb ottengo un'eccezione esterna C0000006. Se non sbaglio, questo è dovuto al fatto che il sistema operativo sta cercando di leggere la riga successiva del codice ma non riesce a trovarne la risorsa (il che significa che l'applicazione non è stata caricata nella ram) che è assurda perché è un'applicazione da 500kb.Eccezione esterna C0000006

Come posso risolvere questo? o almeno gestire questa eccezione in un modo più elegante? (Dal momento che non riesco a prenderlo dato che si tratta di un'eccezione esterna).

Oh, e la mia applicazione Delphi è un'applicazione console in Windows XP.

+3

0xC0000006 e altre eccezioni sono elencate qui: http://www.support.tabs3.com/main/R10309.htm –

risposta

14

Questo è EXCEPTION_IN_PAGE_ERROR. Significa che il caricatore del sistema operativo non è riuscito a visualizzare la pagina in alcuni dati richiesti per l'esecuzione dell'applicazione, probabilmente a causa di un errore di I/O o di altri errori. Dal momento che stai rimuovendo il disco, ciò avrebbe senso.

Forse il set di lavoro (l'insieme di pagine di memoria utilizzate spesso) per l'applicazione è stato permesso di crescere abbastanza su macchine da 1 GB in modo tale che il ricorso al disco per ricaricare le pagine non era necessario, ma quello non era il caso su macchine da 512 MB?

Suggerisco di provare a copiare l'eseguibile in una posizione temporanea e avviarlo da lì, possibilmente con una cancellazione ritardata; o utilizzare qualche altro meccanismo per garantire il backup su disco per tutte le pagine di memoria toccate dall'applicazione in uso normale e prevenire questo errore nei casi di pressione della memoria, in cui il sistema operativo ridurrà il working set di processi in esecuzione.

+1

Dove l'hai cercato per scoprire che tipo di errore si tratta? –

+4

I codici EXCEPTION_ in winbase.h; sono generalmente sinonimi per corrispondenti codici NTSTATUS da winnt.h. –

33

Quello che dovete fare è dire a Windows di caricare l'intero programma in memoria, piuttosto che permettergli di richiedere le pagine di caricamento quando è necessario. Ho fatto questo con successo per le applicazioni in esecuzione su un CD. Non ho il codice con me in questo momento, ma ricordo che ho trovato suggerimenti su come farlo in fonte per il fantastico programma di installazione open source Inno Setup.

Modifica: In realtà, dopo aver fatto una piccola ricerca, è possibile utilizzare una direttiva del compilatore Delphi per dire a Windows di caricare l'intero eseguibile. Funziona con Delphi> 2006. Ciò avrà l'effetto di non ottenere mai l'eccezione esterna.

mettere questa riga nel file di progetto applicazioni:

{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP} 

Questo dice a Windows che l'eseguibile sta per essere utilizzato da un supporto rimovibile, in modo da caricare il file eseguibile nella memoria (o il file di swap). Quindi non è necessario preoccuparsi di cose come copiare prima il file sulla macchina, ecc.

Per Delphi < 2006, è possibile seguire il percorso di forzatura del file eseguibile in cui eseguire il paging. C'è un esempio di come farlo in C++ here (a meno che non si trova un modo per modificare i flag di intestazione PE dopo l'orario di collegamento, che sembra essere complicato)

N @

+0

Cool hack. Grazie per l'ottimo consiglio. –

+0

È arrivata questa risposta cercando in Google esattamente questo problema. Saluti! – HMcG

+0

Dove dovrebbe trovarsi nel file di progetto? –

4

come @Barry, mi sento di raccomandare il controllo del tipo di unità del volume dal quale è in esecuzione il tuo eseguibile; se si tratta di un'unità rimovibile (e manca un parametro della riga di comando "già in temp"), copiare l'eseguibile (e qualsiasi dipendenza) nella cartella %TEMP% dell'utente e quindi rilanciarlo da lì con un ulteriore parametro della riga di comando per indicare "già in temp".

  1. creare ogni file temporaneo utilizzando File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose) (o uno dei FileStream costruttori che prende un parametro FileOptions), ma assicuratevi di appendere sulla tornato File istanza finché dopo la seconda copia è lanciato (ad esempio in a List<File>).
  2. Copia il contenuto di ciascun file.
  3. Avvia l'eseguibile dalla cartella temporanea.
  4. Chiama Close() su ciascuna delle istanze File salvate in precedenza.
  5. Esci dall'eseguibile originale.

In questo modo i file vengono chiusi indipendentemente dal processo che viene terminato per primi e il volume di origine può essere rimosso in precedenza.

0

Questa eccezione C0000006 si verifica spesso anche se il software viene eseguito da un'unità di rete. Per evitare questo problema è possibile combinare la bandiera

{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP} 

con il flag seguente:

IMAGE_FILE_NET_RUN_FROM_SWAP = $0800; 

{$SetPEFlags $0C00} 
1

La soluzione

uses Windows; 
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP} 

è disponibile per Delphi dalla versione 6.