СТАТЬИ > Assembler.Ru

Старт и завершение ассемблерных Windows-приложений

  Поэт утверждал, что-де "все начинается с любви". Поэтам вообще свойственно сказануть что-нибудь этакое не подумав, получить гонорар - и в ресторан, а вы потом разбирайтесь, чего он имел ввиду. Например, предположим, имеется пара гомо сапиенс противоположных полов, выращенная до репродуктивного возраста в условиях, гарантированно исключающих ознакомление с процессом размножения двуполых животных вообще и вида гомо сапиенс в частности. Вопрос: сможет ли указанная пара, руководствуясь исключительно собственными наблюдениями разницы физиологического строения своих организмов и инстинктом, реализовать репродуктивную функцию? Низшие существа, как-то: хомячки - могут, проверено. А мы, цари природы, сможем? Разум не помешает? Ой, что-то сомнительно. Похоже, в процессе эволюции мы прикупили себе одно средство выживания - разум, заплатив за него другим - способностью существовать вне информационного поля социума.

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

Ту же задачу, в принципе, решают и устаревшие функции WinExec и LoadModule. На самом деле на сегодняшний день они представляют собой всего лишь реализации той же функции CreateProcess.
Еще одно замечание, несколько офф-топик. Поскольку вызываемый процесс совершенно независим от вызывающего, то функция CreateProcess возвращает управление вызывающему процессу обычно до того, как вызываемый процесс закончит свою инициализацию. Если вы хотите, чтобы вызывающий процесс взаимодействовал с вызываемым, следует использовать функцию WaitForInputIdle для того, чтобы подождать завершения инициализации.

  Функция CreateProcess:

  Функция _WinMainCRTStartup, если таковая имеется, подготавливает рабочую среду для runtime-библиотеки, а также значения параметров для функции WinMain, после чего передает управление функции WinMain.

  И, наконец, функция WinMain делает все, что придумает прикладной программист.

Несколько пояснений про элементы контекста. Поскольку мы не ставим своей целью продублировать всю имеющуюся в природе документацию на Windows, то эти пояснения будут самыми общими.

  В ОС Windows существует множество способов закончить работу приложения. В MSDN сказано, что это произойдет, если:

Надо сказать, что этот список не окончателен. Николай Критский (nkritsky@mail.ru) подсказал еще и такой экзотический, но вполне работоспособный вариант: функцией SetErrorMode отключить выдачу системных сообщений об ошибках, а затем искусственно создать такую ошибку (например, выполнив деление на 0). Возникшая при этом исключительная ситуация приведет к завершению работы приложения.

  На самом деле перечисленное разнообразие - только кажущееся, так как некоторые из указанных вариантов - это всего лишь скрытый вызов все той же функции ExitProcess. Это касается и ret в первичном потоке, и CTRL+C для консольного приложения, и даже варианта Николая Критского. Фактически в этих вариантах управление передается в существующие по умолчанию runtime-модуль, процедуру поддержки консоли или обработчик исключительной ситуации, которые и вызовут функцию ExitProcess.

  Рекомендуется завершать работу приложения вызовом функции ExitProcess. При этом гарантируется, что система будет освобождена от последствий работы приложения, а именно:

  1. Все занятые приложением dll-библиотеки будут освобождены, то есть для каждой из них будет вызвана входная функция со параметрами отключения. При этом внутренние счетчики занятости библиотек будут декрементированы, и те библиотеки, счетчики которых достигнут 0, будут выгружены из системы.
  2. Будут закрыты все дескрипторы объектов, существовавшие в приложении
  3. Будет завершена работа всех потоков приложения
  4. Объект приложения перейдет в состояние "установлен", так что если кто-то в системе ждал завершения работы нашего приложения, сразу узнает об этом
  5. Все объекты потоков приложения также перейдут в состояние "установлен"
  6. Статус завершения процесса изменится со значения STILL_ACTIVE на значение, переданное функции ExitProcess

  Упомянутая выше функция TerminateProcess делает все то же самое, за исключением освобождения dll-библиотек, и именно поэтому не может быть рекомендована как регулярное средство завершения работы. Ее следует использовать только в каких-то специальных или чрезвычайных случаях.

  В заключение необходимо заметить, что отнюдь не все ресурсы, занятые приложением, освобождаются автоматически при завершении его работы. Поэтому хороший стиль программирования предполагает, что программист самостоятельно, не надеясь на систему, должен освобождать занятые им ресурсы по мере исчерпания надобности в них или перед завершением работы приложения.

  См. также статьи минимальное приложение и параметры функции WinMain.

  [C] Svet(R)off

© 2002-2004 wasm.ru - all rights reserved and reversed