我在Delphi中编写了一些程序,当我从密钥上的磁盘运行它时。在某些时候,我需要在应用程序运行时拔掉密钥上的磁盘。如果我在一台至少有1GB内存的计算机上这样做,一切都还可以。当我在512mb的机器上执行此操作时,我得到一个外部异常C0000006。如果我没有弄错,这是因为操作系统正在尝试读取下一行代码,但无法找到它的资源(意思是,应用程序没有加载到ram),这是荒谬的,因为它是一个500kb的应用程序。
我该如何解决这个问题?或者至少以更优雅的方式处理这个例外? (因为我不能抓住它,因为它是一个外部异常)。
哦,我的Delphi应用程序是windows xp下的控制台应用程序。
答案 0 :(得分:37)
您需要做的是告诉Windows将整个程序加载到内存中,而不是允许它在需要时请求加载页面。我已成功完成了运行CD的应用程序。我现在没有代码跟我一起,但我记得我在源代码中找到了关于如何在源代码中创建奇妙的开源安装程序Inno Setup的提示。
编辑:实际上,经过一些研究后,您可以使用Delphi编译器指令告诉Windows加载完整的可执行文件。这有效,如果你有Delphi>这将导致你永远不会得到外部异常。
将此行放在您的应用程序项目文件中:
{$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 ++ here中做到这一点(除非你找到一种在链接时间后修改PE头标志的方法,看起来很复杂)
N - [
答案 1 :(得分:17)
那是EXCEPTION_IN_PAGE_ERROR
。这意味着OS加载程序无法分页运行应用程序所需的某些数据,可能是由于I / O错误或其他错误。由于你要删除磁盘,这是有道理的。
也许允许应用程序的工作集(常用内存页面集)在1GB机器上增长得足够大,这样就无需使用磁盘来重新加载页面,但事实并非如此。在512MB机器上?
我建议尝试将可执行文件复制到临时位置并从那里开始,可能会延迟删除;或使用其他一些机制来保证正常使用中应用程序触及的所有内存页面的磁盘后备,并在内存压力的情况下防止此错误,操作系统将修剪正在运行的进程的工作集。
答案 2 :(得分:4)
与@Barry一样,我建议检查运行可执行文件的卷的驱动器类型;如果它是一个可移动的驱动器(并且缺少“已在临时”命令行参数)将可执行文件(及其任何依赖项)复制到用户的%TEMP%
文件夹,然后使用额外的命令从那里重新启动它line参数表示“已经在临时”。
File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose)
(或带有FileStream
参数的FileOptions
构造函数之一)创建每个临时文件,但请确保挂起到返回的File
实例,直到启动第二个副本后 (例如,在List<File>
中)。Close()
个实例上调用File
。这样,无论哪个进程首先完成,文件都会关闭,并且可以提前删除源卷。
答案 3 :(得分:1)
解决方案
uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}
可用于 Delphi自版本6 。
答案 4 :(得分:0)
有RunImageLocally from MSJ的Delphi工作版本强制可执行文件/ dll被分页。这可以防止从网络或可移动媒体运行时出现C0000006错误...
在https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr
上查看答案 5 :(得分:0)
如果您的软件是从网络驱动器运行,则通常会发生此例外C0000006。为了防止这个问题,你可以组合标志
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
带有以下标志:
IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;
{$SetPEFlags $0C00}