J'ai écrit un programme dans Delphi et quand je l'exécute à partir d'un disque sur une clé. À un moment donné, je dois débrancher le disque sur la clé lorsque l'application est en cours d'exécution. Si je le fais sur un ordinateur avec au moins 1 Go de RAM, tout va bien. Lorsque je fais cela sur une machine de 512 Mo, je reçois une exception externe C0000006. Si je ne me trompe pas, c'est parce que le système d'exploitation tente de lire la ligne de code suivante mais ne trouve pas la ressource correspondante (ce qui signifie que l'application n'a pas été chargée dans le bélier), ce qui est absurde, car il s'agit d'une application de 500 Ko.
Comment puis-je résoudre ça? ou au moins gérer cette exception d'une manière plus élégante? (Depuis je ne peux pas l'attraper car c'est une exception externe).
Oh, et mon application Delphi est une application console sous Windows XP.
Ce que vous devez faire, c'est dire à Windows de charger tout votre programme en mémoire, plutôt que de lui permettre de charger des pages quand il le faut. Je l'ai fait avec succès pour les applications fonctionnant sur un CD. Je n'ai pas le code avec moi pour l'instant, mais je me souviens d'avoir trouvé des astuces sur la manière de le faire en source pour le fantastique programme d'installation open source Inno Setup.
Edit: En fait, après quelques recherches, vous pouvez utiliser une directive de compilation Delphi pour indiquer à Windows de charger le fichier exécutable complet. Cela fonctionne si vous avez Delphi> 2006. Cela aura pour effet que vous n'obtiendrez jamais l'exception externe.
Mettez cette ligne dans votre fichier de projet d'applications:
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
Cela indique à Windows que le fichier exécutable va être utilisé à partir d'un support amovible, chargez-le en mémoire (ou dans le fichier d'échange). Ensuite, vous n'avez pas à vous soucier de choses telles que copier le fichier sur la machine en premier, etc.
Edit 2: J'ai actuellement accès à Delphi 7 et je peux confirmer, comme l'ont noté d'autres personnes, que cela fonctionne également avec Delphi 7 (et probablement Delphi 6) avec le code suivant:
const
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
Pour Delphi <6, vous pouvez forcer le pagination de l'exécutable. Il existe un exemple de procédure à suivre en C++ ici (à moins que vous ne trouviez le moyen de modifier les indicateurs d'en-tête PE après le lien. le temps qui semble compliqué)
N @
C'est EXCEPTION_IN_PAGE_ERROR
. Cela signifie que le chargeur de système d'exploitation n'a pas réussi à rechercher certaines données nécessaires à l'exécution de l'application, probablement en raison d'une erreur d'entrée-sortie ou d'une autre erreur. Puisque vous retirez le disque, cela aurait du sens.
Peut-être que le jeu de travail (l'ensemble des pages de mémoire fréquemment utilisées) de l'application était autorisé à devenir suffisamment grand sur des machines de 1 Go, de sorte qu'un recours au disque pour recharger des pages n'était pas nécessaire, mais ce n'était pas le cas sur des machines de 512 Mo ?
Je suggérerais d'essayer de copier le fichier exécutable dans un emplacement temporaire et de le démarrer à partir de là, éventuellement avec suppression retardée; ou utilisez un autre mécanisme pour garantir la sauvegarde sur disque de toutes les pages de mémoire touchées par l'application en utilisation normale, et évitez cette erreur en cas de pression de la mémoire, où le système d'exploitation limite le jeu de processus en cours d'exécution.
Comme @Barry, je vous recommande de vérifier le type de lecteur du volume à partir duquel votre exécutable est exécuté; s'il s'agit d'un lecteur amovible (et qu'il manque un paramètre de ligne de commande "déjà en temp"), copiez l'exécutable (et toutes ses dépendances) dans le dossier %TEMP%
de l'utilisateur, puis relancez-le à partir de cet emplacement avec un paramètre de ligne de commande supplémentaire pour indiquer "déjà en temp".
File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose)
(ou l'un des constructeurs FileStream
qui prend un paramètre FileOptions
), mais veillez à vous accrocher à l'instance File
renvoyée jusqu'à ce queaprèsla deuxième copie soit lancée (par exemple, dans un List<File>
).Close()
sur chacune des instances File
enregistrées ci-dessus.Ainsi, les fichiers sont fermés quel que soit le processus qui se termine en premier et le volume source peut être supprimé plus tôt.
La solution
uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}
est disponible pour Delphi depuis la version 6 .
Cette exception C0000006 se produit également souvent si votre logiciel est exécuté à partir d'un lecteur réseau. Pour éviter ce problème, vous pouvez combiner le drapeau
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
avec le drapeau suivant:
IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;
{$SetPEFlags $0C00}
Il existe une version de travail Delphi de RunImageLocally de MSJ qui force le pagination de l'exécutable/dll. Cela peut empêcher les erreurs C0000006 lors de l'exécution à partir d'un réseau ou d'un support amovible ...
Découvrez-le sur https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr