27 ноября 2023

Ошибка ".exe is not a valid Win32 application" на старых версиях Windows

    На прошлой неделе мне сказали, что 32-х битное консольное приложение, написанное на Delphi 11, не запускается под Windows 2003. Я не поверил. Поставил на виртуалку Delphi 11.3, сделал тестовое 32-х битное консольное приложение с одной строкой кода "Writeln('It works!')", попросил админа поднять древнюю виртуалку с Windows Server 2003, запустил на ней свое тестовое приложение и получил ошибку "temp.exe is not a valid Win32 application":
exe is not a valid Win32 application
Как так? Ведь разработка десктопных приложений – это же конек Delphi!

    На этот раз я не стал искать решение сам, а задал вопрос в Telegram-канале Delphi & Lazarus (самый многолюдный из русскоязычных каналов посвященных Delphi). Первые ответы мне не внушали оптимизма. Например, были сомнения в моей адекватности. Вдруг я скомпилировал не 32-х битное приложение или не под Windows? Но в течение часа вопрос решился. Спасибо некоему Alexander'у.

    С выпуском в 1993 году Windows NT 3.1 Microsoft ввела для исполняемых файлов (exe, dll, ocx, sys и т.д.) новый формат – Portable Executable (PE). Каждый исполняемый файл этого формата содержит PE-заголовок, который представляет собой структуру данных с информацией необходимой операционной системе для его выполнения. Мою проблему с ошибкой ".exe is not a valid Win32 application" позволит решить изменение четырех полей PE-заголовка определяющих минимальную версию операционной системы необходимую для запуска приложения:

  • MajorOperatingSystemVersion – основной номер требуемой версии операционной системы;
  • MinorOperatingSystemVersion – дополнительный номер требуемой версии операционной системы;
  • MajorSubsystemVersion – основной номер версии подсистемы;
  • MinorSubsystemVersion – дополнительный номер версии подсистемы.
Эти поля описаны в файле winnt.h (Winapi.Windows.pas у Delphi) в структуре IMAGE_OPTIONAL_HEADER32. Перечень номеров версий операционной системы MS Windows можно посмотреть в справке по Win32 API.

    Для компилируемого в Delphi приложения установить значения этих полей PE-заголовка можно в IDE через параметры компоновщика, вне IDE при компиляции проекта через консольные параметры компилятора и в коде программы с помощью директив компилятора.

    Что бы в Delphi IDE добраться к параметрам компоновщика необходимо выбрать "Project > Options > Building > Delphi Compiler > Linking".

Параметры компоновщика в проекте на Delphi
Нас интересуют два параметра:
  • Set OS version fields in PE header as <major>.<minor> – устанавливает в PE-заголовке значения полей MajorOperatingSystemVersion (<major>) и MinorOperatingSystemVersion (<minor>). Этот параметр компоновщика эквивалентен директиве компилятора {$SETPEOSVERSION} и параметру компилятора ‑‑peosversion.
  • Set subsystem version fields in PE header as <major>.<minor> – указывает в PE-заголовке значения полей MajorSubsystemVersion (<major>) и MinorSubsystemVersion (<minor>). Этот параметр компоновщика эквивалентен директиве компилятора {$SETPESUBSYSVERSION} и параметру компилятора ‑‑pesubsysversion.
До Delphi 11 оба эти параметра по умолчанию имели значение 5.0 (что соответствует Windows 2000), а начиная с Delphi 11 их значение по умолчанию было изменено на 6.0 (что соответствует Windows Vista и Windows Server 2008). Хотя в справке RAD Studio, даже у Delphi 12, по-прежнему написано 5.0.

    Что бы программа запустилась под Windows Server 2003 в ее PE-заголовке необходимо, как минимальную требуемую версию операционной системы, указать версию 5.2 (Windows Server 2003) или еще меньшую (5.1 – Windows XP, 5.0 – Windows 2000). Со временем файлы проектов Delphi (*.dproj) с настройками и пакетные файлы для его компиляции могут потеряться, поэтому в данной ситуации надежнее воспользоваться директивами компилятора в коде программы. Добавляем директивы в код тестовой программы:

program test;

{$APPTYPE CONSOLE}
{$SETPEOSVERSION 5.2}
{$SETPESUBSYSVERSION 5.2}

begin
  Writeln('It works!');
end.
компилируем ее и запускаем под Windows 2003 – программа работает:
Ошибка exe is not a valid Win32 application решена
Не обращайте внимание на сообщение "Access is denied". Это старое сообщение в консоли, оставшееся после закрытия диалога с ошибкой при прошлом запуске программы.

Комментариев нет:

Отправить комментарий