Nekosyndrome
Nekosyndrome

Reputation: 65

Can I use SetErrorMode in C# process?

I'm preparing for writing an online judge core,
A program that can compile user's code and run the program to check the answer like uva online judge.

And I'm having problem in catching the exception of submit program like below.

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

it's access denied at first line because it scan an integer to error position.
how can I catch runtime error for my process?

I used to use "try catch" to catch the exception,
but it didn't reply anything about runtime error.

so I only check the exit code of the submit program although it's not a good method to check except for a process..
and it shows like photo

I have to close the error message box manually,
and I find a solution that is to use a SEH Handler DLL for the process.

SetErrorMode(SEM_NOGPFAULTERRORBOX);

but I don't know how to use it in C# process.

and below is my code of judger

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;

Thanks for helping, and so sorry for my poor English.

==================================
p.s.
the question is how can I set error mode for the child process in C#.
My English is not good enough to explain the problem, so sorry.<(_ _)>

Upvotes: 6

Views: 5292

Answers (2)

Richard
Richard

Reputation: 109100

If you mean the Win32 API function SetErrorMode then you'll need to use P/Invoke, which is easy with such a simple signature:

[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
}

(The Site pinvoke.net is always a good place to start to get the right declaration.)

Upvotes: 12

Hans Passant
Hans Passant

Reputation: 942010

You cannot set the error mode in another process without injecting code into that process. Which is impossible to do easily in C#. It isn't going to work well in C/C++ either, these kind of programs don't live long enough to give you time to inject.

It doesn't solve your problem anyway, you also have to protect against programs that never exit after they got stuck in an endless loop. The simple solution is to give every program a limited amount of time to execute. Say 10 seconds. If it doesn't complete then Process.Kill() it and declare a failure. This will also take care of the programs that bomb with a message box.

Trivial to implement with the Process.WaitForExit(milliseconds) overload.

Upvotes: 5

Related Questions