加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-15 09:43:30 所属栏目:大数据 来源:网络整理
导读:我怎样才能获得正在运行的应用程序的版本? 我一直在使用 GetFileVersionInfo(ParamStr(0),...) : filename := PChar(ExtractShortPathName(ParamStr(0)));//Get the number of bytes he have to allocate for the file information structuredwInfoLength
我怎样才能获得正在运行的应用程序的版本?

我一直在使用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来读取正在运行的进程的版本,只有我加载的文件(如果文件不再存在,那么它无法读取任何版本信息).

但我也假设有可能从我的进程自己的内存中读取版本资源(当然不是Administrators或Debuggers组的成员).

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

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

解决方法

在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) 
    begin
       iMajor := 0;
       iMinor := 0;
       iRelease := 0;
       iBuild := 0;
       Result := False;
       Exit;
    end;

    m := TMemoryStream.Create;
    try
        rs := TResourceStream.CreateFromID(Instance,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,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,RT_VERSION):

var
    ...
    resource: HRSRC;
begin
    ...
    resource := FindResource(Instance,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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读