Единственное отличие состоит в том, что консольное приложение всегда порождает консоль, если она не запущена с одного (или консоль активно подавляется при запуске). Приложение Windows, с другой стороны, не порождает консоль. Он может по-прежнему подключаться к существующей консоли или создавать новую, используя AllocConsole
.
Это делает приложения Windows более подходящими для приложений с графическим интерфейсом или фоновых приложений, поскольку обычно для них не требуется создавать окно терминала.
В более техническом примечании единственное различие между консолью и исполняемым файлом Windows - один байт в PE-заголовке файла exe
. Переключение этого байта вручную (например, с помощью шестнадцатеричного редактора) преобразует тип приложения. Это хорошо опубликованный хак, который используется для создания консольных приложений в VB6 (где этот тип приложений явно не поддерживается).
Чтобы определить и изменить тип подсистемы приложения, вам необходимо прочитать части PE-заголовка. Однако адрес данных подсистемы не является фиксированным, поскольку он является частью необязательного заголовка файла, положение которого определяется адресом, хранящимся в заголовке файла DOS (в элементе e_lfanew
). Этот адрес фактически указывает на запись _IMAGE_NT_HEADERS
, которая, в свою очередь, включает структуру IMAGE_OPTIONAL_HEADER32
. Здесь есть int16
1) член с именем Subsystem
. Значение элемента равно 2 для приложения Windows и 3 для консольного приложения. Существуют и другие подсистемы (в частности, POSIX и ядро).
Я написал небольшое приложение VB6 для изменения подсистемы приложения, которое можно загрузить из ActiveVB в качестве исходного кода.
Формат PE не очень хорошо документирован, но этот документ может служить введением: Пиринг внутри PE: обзор формата исполняемых файлов Win32 .
1) Это на самом деле не противоречит моему утверждению о том, что отличается только один байт: самый старший байт этого члена всегда равен 0. Изменяется только младший байт.