Вопрос о чтении версии запущенного приложения в памяти Windows может возникнуть в случае, когда стандартные методы, такие как GetFileVersionInfo, не работают из-за особенностей загрузки исполняемого файла. Например, если приложение загружается с использованием флага IMAGE_FILE_NET_RUN_FROM_SWAP, Windows загружает весь образ файла снова, что приводит к увеличению времени запуска приложения.
Проблема
Использование GetFileVersionInfo требует, чтобы Windows загрузил исполняемый файл перед чтением ресурсов. При этом, если приложение скомпилировано с флагом IMAGE_FILE_NET_RUN_FROM_SWAP, Windows загружает весь образ файла заново, что может вызвать задержку при запуске приложения.
Решение
Чтобы получить версию запущенного приложения, можно использовать функции Windows API FindResource и LockResource для доступа к ресурсу VERSIONINFO уже загруженного модуля. Пример кода на языке Object Pascal (Delphi) для чтения версии запущенного приложения:
function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean;
var
fileInformation: PVSFIXEDFILEINFO;
verlen: Cardinal;
rs: TResourceStream;
m: TMemoryStream;
resource: HRSRC;
begin
// Проверка на валидность указателя на модуль
if Instance = 0 then
Instance := HInstance;
// Проверка на наличие ресурса версии
resource := FindResource(Instance, 1, RT_VERSION);
if resource = 0 then
begin
// Если ресурс не найден, возвращаем ошибку
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Result := False;
Exit;
end;
// Создание потока для чтения ресурса
m := TMemoryStream.Create;
try
rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
try
m.CopyFrom(rs, rs.Size);
finally
rs.Free;
end;
// Сдвиг указателя на начало потока
m.Position:=0;
// Чтение информации о версии из потока
if not VerQueryValue(m.Memory, '\', Pointer(fileInformation), SizeOf(TVS FixedFILEINFO), verlen) then
begin
// В случае ошибки возвращаем нулевые значения
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Exit;
end;
// Извлечение значений версии из структуры
iMajor := fileInformation.dwFileVersionMS shr 16;
iMinor := fileInformation.dwFileVersionMS and $FFFF;
iRelease := fileInformation.dwFileVersionLS shr 16;
iBuild := fileInformation.dwFileVersionLS and $FFFF;
finally
m.Free;
end;
Result := True;
end;
Важное замечание
В приведенном выше коде есть предупреждение о том, что он может иногда приводить к сбоям из-за ошибки в Delphi. Если ресурс версии отсутствует, Delphi пытается поднять исключение, которое приводит к нарушению доступа при работе с некорректным указателем. Для исправления этой ошибки необходимо сначала проверить наличие ресурса с помощью FindResource, и только после этого пытаться его использовать.
Альтернативные методы
В более новых версиях Delphi (например, 10.3.3) предоставляются удобные методы для чтения версии продукта из запущенного exe. Это можно сделать, установив соответствующие значения в разделе [Options]\[ProductVersion] проекта.
Заключение
При работе с запущенными приложениями в памяти Windows, важно понимать, как обращаться к ресурсам уже загруженного модуля, чтобы избежать дополнительных задержек и ошибок. Использование функций FindResource и LockResource в сочетании с VerQueryValue позволяет эффективно получать информацию о версии приложения без необходимости доступа к файлу на диске.
Вопрос связан с чтением информации о версии приложения, запущенного в памяти Windows, и возможными проблемами, связанными с особенностями загрузки исполняемых файлов, например, использованием флага `IMAGE_FILE_NET_RUN_FROM_SWAP`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.