Нужно ли завершать процесс Windows с помощью ExitProces () или TerminateProcess ()? - PullRequest
0 голосов
/ 08 марта 2019

У меня есть эта простая программа:

#include <windows.h>
int WINAPI startMeUp() {
  return 0;
}

, который я компилирую с помощью инструментов командной строки Visual Studio следующим образом:

cl /nologo /GS- /Gs- /c /W4 main.c /Fomain.obj
link /nologo main.obj /subsystem:console /entry:startMeUp /nodefaultlib kernel32.lib user32.lib /OUT:the.exe

Когда я затем выполняю .\the.exe, появляется сообщение о том, что the.exe перестала работать - из-за проблемы программа перестала работать правильно. Windows закроет программу и сообщит вам, если решение доступно

После замены return 0; на ExitProcess(0); и повторной компиляции / компоновки .\the.exe работает нормально.

Итак, мне кажется, что ExitProcess() необходим для правильного завершения процесса.

Поскольку я почти уверен, что у меня уже были рабочие программы, которые возвращали функцию точки входа, возвращая значение выхода, я не уверен, что для переносимых исполняемых файлов требуется, чтобы процесс завершался ExitProcess().

Редактировать Интересно, что если я поставлю MessageBox(NULL, "world", "hello", 0); перед return 0; (и, следовательно, не вызову ExitProcess()), исполняемый файл также будет работать нормально.

Редактировать II Когда я добавляю параметр компоновщика /export:startMeUp, компоновщик предупреждает меня с помощью LNK4216 , но я могу выполнить созданное без проблем.

Когда я использую dumpbin /all в обоих созданных exe-файлах, я вижу, что неисправный исполняемый файл имеет

 0 [       0] RVA [size] of Export Directory

в то время как новый, рабочий имеет

2000 [      40] RVA [size] of Export Directory

Кроме того, рабочий исполняемый файл состоит из двух разделов: .text и .rdata, в то время как неисправный имеет только раздел .text. Кажется, исполняемый код включен в раздел .rdata, поэтому он отсутствует в неисправном.

Что касается почему , то есть я понятия не имею.

Ответы [ 3 ]

0 голосов
/ 08 марта 2019

выход из процесса Windows или когда последний поток в выходе из процесса или когда вызывается TerminateProcess. потому что могут быть дополнительные (неявно созданные) потоки в вашем процессе - вам нужно вызвать TerminateProcess (или ZwTerminateProcess) прямо или косвенно.

ExitProcess внутренне вызовите TerminateProcess (хорошо, действительно ZwTerminateProcess), но перед этим сделайте некоторую работу для корректного завершения процесса. включая вызов всех точек входа DLL с DLL_PROCESS_DETACH уведомлением

так, в общем, вы должны позвонить ExitProcess (более правильно) или TerminateProcess

если вы пишете точку входа самостоятельно, правильная подпись должна быть

int WINAPI startMeUp(void*)

это функция stdcall , которая принимает 1 параметр (указатель на PEB ). когда вы возвращаетесь из этого API в систему - просто вызывается RtlExitUserThread, что приводит к завершению потока или выходу всего процесса, если это последний поток в процессе. даже указатель на системный стек x86 неверен после вашего возврата из startMeUp, это не приведет к ошибке, потому что просто RtlExitUserThread и оно никогда не вернется. Трудно сказать, что привело к сбою в вашем тесте без просмотра вашего двоичного файла, но быстрее нужно посмотреть (отладить) вашу конкретную систему. но это необычно - этого не должно быть. ваш процесс должен либо просто завершиться, либо все еще жить (бесконечно или некоторое время) в фоновом режиме в дополнительном потоке в процессе

0 голосов
/ 05 апреля 2019

Если вы просто спросите, нужен ли ExitProcess () в exe, я могу строго ответить вам: НЕТ

Я написал компилятор, который генерирует exe, и минимальная программа в нем (если не сказать о заголовках exe) может иметь только один байт: 0xC3, что является ret - такая программа при запуске сразу возвращается, но корректна

0 голосов
/ 08 марта 2019

Да, требуется ExitProcess, или вы в конечном итоге сгенерируете исключение, потому что идти некуда и вы не можете остановить процессор.

Однако запись обычно не предоставляется пользователем, она предоставляетсяCRT (WinMainCRTStartup), который также инициализирует глобальные переменные перед вызовом функции WinMain ().

Следовательно, все, что вам нужно сделать, - это предоставить WinMain.

Редактировать после редактирования: ExitProcess может бытьвызывается некоторым обработчиком исключений, который создается после вызова MessageBox.Вы не (и не можете) знать.

...