delphi - 如何获取正在运行的可执行文件的版本?

标签 delphi winapi resources versioning delphi-5

如何获取正在运行的应用程序的版本?

<小时/>

我一直在使用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 秒的应用程序启动。

我如何读取我的正在运行的应用程序的版本?

<小时/>

我假设 Windows 没有 API 来读取正在运行的进程的版本,只有我从中加载的文件(如果该文件不再存在,则它无法读取任何版本信息)。

但我还假设可以从我的进程自己的内存中读取版本资源(当然,无需成为管理员或调试器组的成员)。

我可以读取流程的版本吗?

<小时/>

相关奖励问题:我如何从而不是通过网络加载PE Image资源?

最佳答案

在 Stackoverflow 上找到了它:

How to determine Delphi Application Version

我已经知道如何确定应用程序版本,但 @StijnSanders 提出了“更好”的方法,这正是我所遇到的原因:

I most strongly recommend not to use GetFileVersion when you want to know the version of the executable that is currently running! I have two pretty good reasons to do this:

  • The executable may be unaccessible (disconnected drive/share), or changed (.exe renamed to .bak and replaced by a new .exe without the running process being stopped).
  • The version data you're trying to read has actually already been loaded into memory, and is available to you by loading this resource, which is always better than to perform extra (relatively slow) disk operations.

我适应了:

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 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, '\', (*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 char 的指针。对于非命名资源,它们是整数常量,转换为 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;
    ...

Note: Any code is released into the public domain. No attribution required.

关于delphi - 如何获取正在运行的可执行文件的版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10854958/

相关文章:

windows - 是否存在与 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 或 IMAGE_FILE_NET_RUN_FROM_SWAP 相关的风险?

c# - 如何在文件写入时尽可能快地复制文件?

silverlight 资源与 VS 设计器不兼容?

delphi - 验证真实日期

delphi - 是否记录了 Set 类型的星号运算符?

c++ - 查找dll的依赖模块

c++ - visual c++ 2010 无法添加资源文件

delphi - CreateWindow 不再存在于 user32.dll 中

delphi - TDataSource TDBMemo 未处于插入或浏览模式

wpf - 为什么允许 ImageSource 作为 WPF 资源?