【问题标题】:External exception C0000006外部异常 C0000006
【发布时间】:2010-11-22 00:27:06
【问题描述】:

我在 Delphi 中编写了一些程序,当我从磁盘上运行它时。在某些时候,我需要在应用程序运行时拔下密钥上的磁盘。如果我在至少有 1gb 内存的计算机上执行此操作,一切都很好。当我在 512mb 的机器上执行此操作时,我得到一个外部异常 C0000006。如果我没记错的话,这是因为操作系统正在尝试读取下一行代码但找不到它的资源(意思是应用程序没有加载到内存中),这很荒谬,因为它是一个 500kb 应用程序。

我该如何解决这个问题?或者至少以更优雅的方式处理这个异常? (因为它是一个外部异常,所以我无法捕捉到它)。

哦,我的 Delphi 应用程序是 windows xp 下的控制台应用程序。

【问题讨论】:

标签: delphi exception error-handling windows-xp


【解决方案1】:

您需要做的是告诉 Windows 将整个程序加载到内存中,而不是让它在需要时请求加载页面。对于从 CD 上运行的应用程序,我已经成功地做到了这一点。我现在没有代码,但我记得我在出色的开源安装程序 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 here(除非你找到一种方法来修改PE头标志之后链接时间,看起来很复杂)

N@

【讨论】:

  • 项目文件应该在哪里?
  • 我想的任何地方,但我之前把它放在program 行下面。
  • @Nat。 D2006 支持此指令。看我的问题stackoverflow.com/questions/6905395/…
  • @neves 我相信网上有一些工具可以在编译后设置标题标志。不知道有什么在我脑海中的。
  • 使用 MS VS 的 editbin。命令是editbin /SWAP:CD your_exe
【解决方案2】:

解决办法

uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}

可用于 Delphi 自第 6 版起

【讨论】:

    【解决方案3】:

    如果您的软件是从网络驱动器运行的,也经常会出现此异常 C0000006。为了防止这个问题,你可以结合标志

    {$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
    

    带有以下标志:

    IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;
    
    {$SetPEFlags $0C00}
    

    【讨论】:

      【解决方案4】:

      RunImageLocally from MSJ 有一个 Delphi 工作版本,它强制执行可执行文件/dll 被分页。这可以防止从网络或可移动媒体运行时出现 C0000006 错误...

      查看https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr

      【讨论】:

        【解决方案5】:

        和@Barry 一样,我建议检查运行可执行文件的卷的驱动器类型;如果它是可移动驱动器(并且缺少“已经在临时”命令行参数),则将可执行文件(及其任何依赖项)复制到用户的 %TEMP% 文件夹,然后使用额外的命令行参数从那里重新启动它表示“已经在温度中”。

        1. 使用File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose)(或采用FileOptions 参数的FileStream 构造函数之一)创建每个临时文件,但请确保保留返回的File 实例直到之后 启动第二个副本(例如在List<File> 中)。
        2. 复制每个文件的内容。
        3. 从临时文件夹启动可执行文件。
        4. 在上面保存的每个 File 实例上调用 Close()
        5. 退出原始可执行文件。

        这样,无论哪个进程先完成,文件都会关闭,并且可以更早地删除源卷。

        【讨论】:

          【解决方案6】:

          那是EXCEPTION_IN_PAGE_ERROR。这意味着操作系统加载程序未能在应用程序运行所需的某些数据中分页,可能是由于 I/O 错误或其他错误。既然您要移除磁盘,那将是有道理的。

          也许应用程序的工作集(经常使用的内存页面集)在 1GB 机器上被允许增长到足够大,这样就不需要求助于磁盘来重新加载页面,但事实并非如此在 512MB 的机器上?

          我建议尝试将可执行文件复制到一个临时位置并从那里启动它,可能会延迟删除;或者使用其他机制来保证应用程序在正常使用中接触到的所有内存页面都在磁盘上进行备份,并在内存压力的情况下防止此错误,在这种情况下,操作系统将修剪正在运行的进程的工作集。

          【讨论】:

          • 你在哪里查到它是什么类型的错误?
          • winbase.h 中的 EXCEPTION_ 代码;它们通常是 winnt.h 中相应 NTSTATUS 代码的同义词。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-04-20
          • 2015-06-14
          • 2011-12-22
          • 2021-01-15
          • 2016-06-12
          • 2010-10-26
          • 1970-01-01
          相关资源
          最近更新 更多