原來這事,因爲我們使用JobObjects確保在使用用C此代碼當前進程退出(我們實際上是從C#P-調用的)的所有子進程退出:
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
標誌自動殺死所有進程有沒有辦法來設置所有進程退出代碼,所以OS退出過程,退出代碼0
在C#中,我們遵循標準的指導方針,清理資源,並使用SafeHandle
- 派生類來確保CloseHandle
被調用,並且絕對是相同的 - 在CLR實際退出之前,它調用::CloseHandle
爲所有SafeHandle
s忽略返回值和Environment.Exit
的實際返回碼集。
但是更有意思的是,如果在C#和C++中都刪除了對CloseHandle
的明確(或不那麼明確)的調用,OS仍然會在CLR/CRT退出後關閉進程出口處的所有句柄,並且實際的退出碼將被退回。所以有時候最好不要清理資源:-)換句話說,直到調用本地::ExitProcess
,你不能保證退出代碼將完好無損。
所以要解決這個特殊問題,我可以調用AssignProcessToJobObject
每當一個子進程啓動或刪除對CloseHandle
明確(或不那麼明確)的調用。我選擇了第一種方法。