2012-06-01 6 views
4

Как я могу получить версию моего приложения?Как получить версию исполняемого исполняемого файла?


я использую GetFileVersionInfo(ParamStr(0), ...):

filename := PChar(ExtractShortPathName(ParamStr(0))); 

//Get the number of bytes he have to allocate for the file information structure 
dwInfoLength := GetFileVersionInfoSize(lptstrFilename, {var}dwHandle); 

//Get version info 
GetMem(pInfoData, dwInfoLength); 
GetFileVersionInfo(lptstrFilename, dwHandle, dwInfoLength, pInfoData); 

//Set what information we want to extract from pInfoData 
lpSubBlock := PChar(Chr(92)+Chr(0)); 

//Extract the desired data from pInfoData into the FileInformation structure 
VerQueryValue(pInfoData, lpSubBlock, PFileInformation, LengthOfReturned); 

Проблема этого метода заключается в том, что она требует загрузчик Windows, в load the image before the resources can be read. Я создаю свои приложения с флагом изображения IMAGE_FILE_NET_RUN_FROM_SWAP (in order to avoid in-page exceptions on a fiddly network).

Это вызывает загрузчик Windows, чтобы загрузить весь файл по сети снова, а не просто смотреть на «меня». Поскольку я проверяю и сохраняю свою собственную версию при запуске, запуск в течение 6 секунд запускается в 10-секундный запуск приложения.

Как я могу прочитать версию me, my работает приложение?


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

Но я также предполагаю, что можно было бы узнать ресурсы версии из моих собственных процессов (не будучи членом группы «Администраторы» или «Отладчики»).

Могу ли я прочитать версию мой процесс?


Попутный Bonus Вопрос: Как я могу загрузить PE Image ресурсы меня, а не по сети?

ответ

8

Нашел, прямо здесь, на Stackoverflow:

How to determine Delphi Application Version

я уже знал , как определить версию приложения, но @StijnSanders предложил «лучше» путь, по точно причинам я бил :

Я настоятельно рекомендую не использовать GetFileVersion, если вы хотите узнать версию исполняемого файла, который в данный момент запущен! У меня есть две очень веские причины, чтобы сделать это:

  • Исполняемый могут быть недоступны (отключенный диск/акция), или изменить (.exe переименован в .bak и заменен на новый EXE-файл без запущенного процесса остановки).
  • Данные версии, которые вы пытаетесь прочитать, на самом деле уже загружены в память и доступны вам, загрузив этот ресурс, что всегда лучше, чем выполнять дополнительные (относительно медленные) операции с дисками.

Что я не адаптирован в:

function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean; 
var 
    fileInformation: PVSFIXEDFILEINFO; 
    verlen: Cardinal; 
    rs: TResourceStream; 
    m: TMemoryStream; 
    resource: HRSRC; 
begin 
    //You said zero, but you mean "us" 
    if Instance = 0 then 
     Instance := HInstance; 

    //UPDATE: Workaround bug in Delphi if resource doesn't exist  
    resource := FindResource(Instance, 1, RT_VERSION); 
    if (resource = 0) 
    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, '\', /*var*/Pointer(fileInformation), /*var*/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:

rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION); 

Если нет информация о версии, Delphi пытается создать исключение:

procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar); 
    procedure Error; 
    begin 
     raise EResNotFound.CreateFmt(SResNotFound, [Name]); 
    end; 
begin 
    HResInfo := FindResource(Instance, Name, ResType); 
    if HResInfo = 0 then Error; 
    ... 
end; 

Исправлена ​​ошибка, конечно, является то, что PChar не всегда указатель на AnSi полукокса. С неименованными ресурсами они являются целыми константами, отлитыми от PChar. В этом случае:

Name: PChar = PChar(1); 

Когда Delphi пытается построить строку исключения, и разыменовывает указатель 0x00000001 это вызывает и нарушение прав доступа.

Исправление вручную вызвать FindResource(Instance, 1, RT_VERSION) первый:

var 
    ... 
    resource: HRSRC; 
begin 
    ... 
    resource := FindResource(Instance, 1, RT_VERSION); 
    if (resource = 0) 
    begin 
     iMajor := 0; 
     iMinor := 0; 
     iRelease := 0; 
     iBuild := 0; 
     Result := False; 
     Exit; 
    end; 

    m := TMemoryStream.Create; 
    ... 

Примечание: Любой код выпущен в общественное достояние. Никакой атрибуции не требуется.

+1

Действительно, это то же самое, что я думал: поиск ресурса 'VERSIONINFO' (' RT_VERSION'), а затем его загрузка API 'VerQueryValue'. И вам повезло, что это уже фрагмент кода Delphi, а не C++ на MSDN. –

+1

Значит, это не делает ваш вопрос точным дубликатом? –

+0

@WarrenP Ответы одинаковы; даже когда вопросы разные.Этот вопрос касается «моего собственного» процесса, который не обязательно означает, что кому-то захочется версия приложения Delphi. И кто знает, Microsoft может добавить API, чтобы получить версию «я». –

8

Возможно, вы захотите попробовать FindResource/LockResource API для доступа к VERSIONINFO ресурсу вашего работающего модуля. В статье MSDN приведен пример в разделе «Примеры», а также есть комментарий сообщества с C++ sample code, который выполняет именно это. Это начинается с уже загруженного модуля, а не из имени файла (который предположительно загружается отдельно с флагом, указывающим только «ресурсы загрузки» и, возможно, игнорируя тот факт, что изображение уже отображается в процессе).

Обратите внимание, что - за предоставленный фрагмент кода вы можете найти ресурс своего модуля, а затем повторно использовать стандартный VerQueryValue API для продолжения разбора ресурсов оттуда.

+1

пример, кажется, был включен в раздел Примеры, вы найдете * «Пример см. В разделе [Обновление ресурсов] (https://msdn.microsoft.com/en-us/library/ windows/desktop/ms648008 (v = vs.85) .aspx # _win32_Updating_Resources). * * – Wolf

2

Предлагаю вам ознакомиться с кодом JclFileUtils.pas, от JCL. В классе «TJclFileVersionInfo» есть несколько перегруженных конструкторов, которые позволяют работать с файлом и с помощью дескриптора модуля для получения информации о версии.

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

Смежные вопросы