2013-10-09 2 views
2

Наши выходы C# приложение с кодом 0, даже если он явно возвращающиеся -1 в коде:Неверный код выхода процесса Windows (C#/C++/etc.)?

internal class Program 
{ 
    public int Main() 
    { 
     .... 
     return -1; 
    } 
} 

То же самое произошло, если void Main был использован:

internal class Program 
{ 
    public void Main() 
    { 
     .... 
     Environment.Exit(-1); 
    } 
} 

Как другие вопросы по SO предложил это может быть необработанное исключение CLR/C++/native в каком-то другом потоке. Однако я добавил грациозное завершение всех управляемых/собственных потоков прямо перед этим последним, но поведение оставалось.

В чем может быть причина?

ответ

2

Оказывается, это произошло потому, что мы использовали JobObjects, чтобы убедиться, что все дочерний процесс выхода, когда ток выходит из процесса с использованием этого кода в C (мы на самом деле р-вызывается из C#):

HANDLE h = ::CreateJobObject(NULL, NULL); 

JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; 
::ZeroMemory(&info, sizeof(info)); 
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 
::SetInformationJobObject(h, JobObjectExtendedLimitInformation, &info, sizeof(info)); 
::AssignProcessToJobObject(h, ::GetCurrentProcess()); 

... 

::CloseHandle(h); 

return -1; 

Этот код добавляет текущий процесс и все его дочерние процессы к объекту задания, который будет закрыт при текущем выходе процесса. НО, но он имеет побочный эффект, когда был вызван CloseHandle, он убьет текущий процесс, не достигнув линии return -1. А так как JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE флаг автоматически убивает все процессы, нет способа установить код выхода для всех процессов, поэтому ОС вышла из процесса с кодом выхода 0.

В C# мы следовали стандартным рекомендациям по очистке ресурсов и использованию SafeHandle - чтобы убедиться, что вызывается CloseHandle, и абсолютно то же самое произошло - до того, как CLR на самом деле вышла из него, вызывается ::CloseHandle для всех SafeHandle s, игнорируя фактический код возврата, установленный как возвращаемым значением, так и Environment.Exit.

Однако, что еще более интересно, заключается в том, что если явный (или не столь явный) вызов CloseHandle удаляется как на C#, так и на C++, ОС все равно будет закрывать все дескрипторы на выходе процесса после выхода CLR/CRT и будет возвращен фактический код выхода. Поэтому иногда полезно не очищать ресурсы :-) или, другими словами, до тех пор, пока не будет вызван родной ::ExitProcess, вы не можете гарантировать, что код выхода будет неповрежден.

Так, чтобы исправить эту конкретную проблему, я мог либо вызвать AssignProcessToJobObject всякий раз, когда дочерний процесс запускается или удаляется явный (или не столь явный) вызов на CloseHandle. Я выбрал первый подход.

Смежные вопросы