четверг, 24 декабря 2015 г.

Окно консоли в оконном приложении Windows

Подсистемы в Windows

Для Windows исполняемый файл — это не просто кусок кода. Обычный exe имеет стандартный заголовок и целый ряд сегментов. Подробнее о структуре exe-файла можно узнать на википедии.

Исполняемые файлы, предназначенные для ОС Windows, в заголовке имеют запись о «подсистеме» (subsystem). От этой записи зависит, какое окружение создаст ОС Windows во время запуска и работы процесса. Для прикладных нужд важны лишь две подсистемы:
  • Подсистема консольных приложений (Console) заставляет ОС Windows создать окно, эмулирующее консоль DOS. Если приложение не является консольным, то это окно явно будет лишним.
  • Подсистема оконных приложений (Window) приводит к тому, что эмулятор консоли DOS не создаётся.
Приложение для подсистемы console выглядит примерно так:

Убираем окно консоли

Окно эмуляции консоли DOS бывает полезным при отладке, потому что к нему прикрепляются стандартные потоки ввода/вывода (то есть stdin, stdout, stderr). Но в релизной версии лучше обойтись без лишнего окна.

Убрать окно можно в два шага
  • Изменить подсистему в настройках компоновщика (linker) для проекта, дающего на выходе «.exe».
  • Разобраться с main/WinMain
Подсистема меняется просто:


Разница между main и WinMain

Функция main — стандартная точка входа для программ, написанных на языках C и C++. К сожалению, для оконных приложений разработчики Windows решили сделать иначе: если подсистемой приложения указана подсистема «Window», то выполнение программы начнётся с функции WinMain (wWinMain для unicode-программ), у которой совсем иные параметры.

Если у готового приложения поменять подсистему с console на window, компоновщик выдаст ошибку сборки: функция WinMain не найдена. Варианты решения:
  • Для приложений, основанных на winapi (WTL, MFC) можно определить функцию WinMain так, как рассказано на MSDN
  • Для приложений, использующих кроссплатформенные библиотеки (SFML, SDL), есть распространённое решение, подготовленное авторами библиотек. Нужно просто указать компоновщику на библиотеку sfml-main.lib (или SDLmain.lib в случае SDL). Единственная задача такой библиотечки — предоставлять свою реализацию функции WinMain, которая просто вызывает функцию main, определённую в исходном коде программы.

1 комментарий: