我可以在C#进程中使用SetErrorMode吗?

6

我正在准备编写一个在线评测核心,
这是一个可以编译用户代码并运行程序以检查答案的程序,类似于uva在线评测。

但我在捕获提交程序异常方面遇到了问题,如下所示。

int main()
{
    while(~scanf("%d %d",n,&m))
    {   
        printf("%d\n",n+m);
    }
    return 0;
}

首先行代码出现“访问被拒绝”的错误是因为它将一个整数扫描到错误的位置。
我该如何捕获进程的运行时错误?

我曾经使用“try catch”来捕获异常,
但它没有返回任何与运行时错误有关的信息。

所以我只能检查提交程序的退出代码,虽然这不是除了进程之外的好方法。
结果如图片所示。

我必须手动关闭错误消息框,
然后我发现解决方案是为进程使用SEH Handler DLL。

SetErrorMode(SEM_NOGPFAULTERRORBOX);

但我不知道如何在C#进程中使用它。 以下是我的评测机代码。
timer = new Stopwatch();
timer.Reset();

submitProg = new Process();
submitProg.StartInfo.FileName = outputFile;
submitProg.StartInfo.UseShellExecute = false;
submitProg.StartInfo.CreateNoWindow = true;
submitProg.StartInfo.RedirectStandardInput = true;
submitProg.StartInfo.RedirectStandardOutput = true;
submitProg.StartInfo.RedirectStandardError = true;
submitProg.StartInfo.ErrorDialog = false;
submitProg.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
submitProg.EnableRaisingEvents = true;

submitProg.Start();
timer.Start();

progInput = submitProg.StandardInput;
progOutput = submitProg.StandardOutput;

progInput.Write(inputStream.ReadToEnd());
submitProg.StandardInput.Close();
while (!submitProg.HasExited)
{
    peakPagedMem = submitProg.PeakPagedMemorySize64;
    peakVirtualMem = submitProg.PeakVirtualMemorySize64;
    peakWorkingSet = submitProg.PeakWorkingSet64;
    if (peakPagedMem > memLimit)
    {
        submitProg.Kill();
    }
    if (timer.ElapsedMilliseconds > timeLimit)
    {
        timeLimitExceed = true;
        submitProg.Kill();
    }
}

timeUsed = timer.ElapsedMilliseconds;
timer.Stop();

if(submitProg.ExitCode!=0)systemRuntimeError = true;

感谢您的帮助,非常抱歉我的英语很差。

==================================
附言:
问题是如何在C#中为子进程设置错误模式。
我的英语不够好,无法解释这个问题,真的很抱歉。<(_ _)>


只要你在任何情况下都很好地隔离你的东西,有几个错误框不应该是问题。你可以只需关闭沙盒和相关进程。 - Matti Virkkunen
2个回答

11

如果你指的是Win32 API函数SetErrorMode,那么你需要使用P/Invoke,这个函数签名很简单,所以使用起来也很容易:

[DllImport("kernel32.dll")]
static extern ErrorModes  SetErrorMode(ErrorModes uMode);

[Flags]
public enum ErrorModes : uint {
    SYSTEM_DEFAULT             = 0x0,
    SEM_FAILCRITICALERRORS     = 0x0001,
    SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
    SEM_NOGPFAULTERRORBOX      = 0x0002,
    SEM_NOOPENFILEERRORBOX     = 0x8000
}

(这个网站http://www.pinvoike.net/始终是一个很好的起点,以获得正确的声明。)


@kannaduki 在MSDN上没有提到这是由子进程继承的,因此我认为它不会被继承。 - Richard
似乎没有被继承。我该如何为我的子进程设置错误模式?谢谢。 - Nekosyndrome
1
@kannaduki 开始处理吧。我从MSDN上注意到,在Win7/2008R2中,推荐使用SetThreadErrorMode,因为它是一个新的API,更加"不会造成干扰"。也就是说,只有当可执行文件和它所使用的库在不同的错误模式下编写和测试时,改变全局状态才是安全的。 - Richard

5
在不将代码注入到另一个进程中的情况下,你无法设置错误模式。在C#中很难做到这一点。在C/C++中也不会有很好的效果,因为这些程序存活时间太短,无法给你注入时间。
总之,这不解决问题。你还需要防止陷入无限循环后永远无法退出的程序。简单的解决方案是给每个程序分配有限的执行时间,例如10秒钟。如果超时就使用Process.Kill()结束它并声明失败。这也可以解决弹出消息框导致程序崩溃的问题。
使用Process.WaitForExit(milliseconds)重载即可轻松实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接