Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use SetErrorMode in C# process?

Tags:

c#

winapi

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.<(_ _)>

like image 931
Nekosyndrome Avatar asked May 21 '11 08:05

Nekosyndrome


2 Answers

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 http://www.pinvoike.net/ is always a good place to start to get the right declaration.)

like image 117
Richard Avatar answered Sep 21 '22 18:09

Richard


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.

like image 22
Hans Passant Avatar answered Sep 20 '22 18:09

Hans Passant