Внешнее исключение C0000006 - PullRequest
21 голосов
/ 23 августа 2009

Я написал какую-то программу на Delphi, и когда я запускаю ее с диска на ключе. В какой-то момент я должен отключить диск от ключа во время работы приложения. Если я делаю это на компьютере с хотя бы 1 ГБ оперативной памяти, все в порядке. Когда я делаю это на машине с 512 МБ, я получаю внешнее исключение C0000006. Если я не ошибаюсь, это потому, что ОС пытается прочитать следующую строку кода, но не может найти ресурс для него (то есть приложение не было загружено в оперативную память), что абсурдно, поскольку это приложение размером 500 КБ.

Как я могу решить это? или хотя бы обработать это исключение более элегантным способом? (Так как я не могу поймать это, так как это внешнее исключение).

О, и мое приложение Delphi является консольным приложением под Windows XP.

Ответы [ 6 ]

37 голосов
/ 23 августа 2009

Что вам нужно сделать, это сказать Windows, чтобы загружать всю вашу программу в память, а не позволять ей требовать загрузки страниц, когда это необходимо. Я сделал это успешно для приложений, работающих с компакт-диска. У меня сейчас нет с собой кода, но я вспоминаю, что нашел подсказки о том, как сделать это в исходном коде для фантастической программы установки с открытым исходным кодом Inno Setup.

Редактировать: На самом деле, после небольшого исследования, вы можете использовать директиву компилятора Delphi, чтобы сообщить Windows о загрузке полного исполняемого файла. Это работает, если у вас Delphi> 2006. Это приведет к тому, что вы никогда не получите внешнее исключение.

Поместите эту строку в файл проекта приложения:

{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}

Это говорит Windows, что исполняемый файл будет использоваться со съемного носителя, поэтому загрузите исполняемый файл в память (или файл подкачки). Тогда вам не нужно беспокоиться о таких вещах, как копирование файла на компьютер и т. Д.

Редактировать 2: В настоящее время у меня есть доступ к Delphi 7, и я могу подтвердить, как отмечали другие, что это также работает с Delphi 7 (и, вероятно, Delphi 6) со следующим кодом:

const
  IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400;

{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}

Для Delphi <6 вы можете пойти по пути принудительного выполнения исполняемого файла для подкачки. Существует пример того, как сделать это в C ++ <a href="http://www.microsoft.com/msj/0398/win320398.aspx" rel="nofollow noreferrer"> здесь (если вы не найдете способ изменить Флаги заголовка PE после времени соединения, что выглядит сложным)

N @

17 голосов
/ 23 августа 2009

Это EXCEPTION_IN_PAGE_ERROR. Это означает, что загрузчику ОС не удалось отобразить некоторые данные, необходимые для запуска приложения, возможно, из-за ошибки ввода-вывода или другой ошибки. Поскольку вы извлекаете диск, это будет иметь смысл.

Возможно, рабочий набор (набор часто используемых страниц памяти) для приложения позволял расти достаточно большим на машинах объемом 1 ГБ, так что использование диска для перезагрузки страниц не было необходимым, но это не имело место на машинах 512МБ?

Я бы предложил попробовать скопировать исполняемый файл во временную папку и запустить его оттуда, возможно, с отложенным удалением; или используйте какой-либо другой механизм, чтобы гарантировать резервное копирование на диске для всех страниц памяти, к которым обращается приложение, при нормальном использовании, и предотвратить эту ошибку в случаях нехватки памяти, когда ОС урезает рабочий набор запущенных процессов.

4 голосов
/ 23 августа 2009

Как и @Barry, я бы рекомендовал проверить тип диска тома, с которого запускается ваш исполняемый файл; если это съемный диск (и в нем отсутствует параметр командной строки «уже в темпе»), скопируйте исполняемый файл (и любые его зависимости) в папку пользователя %TEMP%, а затем перезапустите его с дополнительным параметром командной строки. указывать «уже в темп».

  1. Создайте каждый временный файл, используя File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose) (или один из конструкторов FileStream, который принимает параметр FileOptions), но обязательно повесьте на возвращенный экземпляр File до после вторая копия запускается (например, в List<File>).
  2. Скопируйте содержимое каждого файла.
  3. Запустите исполняемый файл из временной папки.
  4. Вызовите Close() на каждом из File экземпляров, сохраненных выше.
  5. Выход из исходного исполняемого файла.

Таким образом, файлы закрываются независимо от того, какой процесс завершается первым, а исходный том можно удалить раньше.

1 голос
/ 09 ноября 2017

Раствор

uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}

доступно для Delphi начиная с версии 6 .

0 голосов
/ 28 января 2016

Это исключение C0000006 также часто возникает, если ваше программное обеспечение запускается с сетевого диска. Чтобы предотвратить эту проблему, вы можете объединить флаг

{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}

со следующим флагом:

IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;

{$SetPEFlags $0C00}
0 голосов
/ 17 августа 2015

Существует рабочая версия Delphi RunImageLocally от MSJ , которая заставляет выполнять загрузку исполняемого файла / dll. Это может предотвратить ошибки C0000006 при запуске из сети или съемного носителя ...

Проверьте это на https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr

...