Linux下实现exe文件版本号读取

**背景:
exe作为windows平台下的可执行文件,属性里面带有一个版本号,如下图中的File version:3.9.11.1000,在一些linux作为操作系统的程序更新服务器中,有时需要获取当前待更新的exe中的版本号以响应用户的HTTP GET请求获得最新的程序版本,由于linux环境无法调用windows提供的API,所以本文给出了一种跨平台,特别是Linux平台下获得版本号的方法。
请输入图片描述
如何exe获得文件中的版本号(File version)呢?
在windows下我们可以调用windows提供的API,QT C++开发环境代码如下
其本质是调用winver.h中的GetFileVersionInfo函数,使用时需要在头文件中加入

#include <windows.h>

在QT的Pro文件中加入

LIBS += -lVersion #获取exe里面的版本号使用 

源码

QString GetExeFileVersion (QString fName)
{
    // first of all, GetFileVersionInfoSize
    DWORD dwHandle;
    DWORD dwLen = GetFileVersionInfoSize(fName.toStdString().c_str(), &dwHandle);

    // GetFileVersionInfo
    LPVOID lpData = new BYTE[dwLen];
    if (!GetFileVersionInfo(fName.toStdString().c_str(), dwHandle, dwLen, lpData))
    {
        qDebug() << "error in GetFileVersionInfo";
        delete[] lpData;
        return "";
    }
    // VerQueryValue
    VS_FIXEDFILEINFO* lpBuffer = NULL;
    UINT uLen;

    if (!VerQueryValue(lpData,QString("\\").toStdString().c_str(),(LPVOID*)& lpBuffer,&uLen))
    {
        qDebug() << "error in VerQueryValue";
        delete[] lpData;
        return "";
    }
    else
    {  
    return QString::number((lpBuffer->dwFileVersionMS >> 16) & 0xffff) + "." + QString::number((lpBuffer->dwFileVersionMS) & 0xffff) + "." +QString::number((lpBuffer->dwFileVersionLS >> 16) & 0xffff) + "." +QString::number((lpBuffer->dwFileVersionLS) & 0xffff);  
     }
}

以上是Windows平台上得到exe版本号的一种方法,本质实际上是调用windows提供的API,但是在Linux下,显然我们无法调用windows平台提供的API,所以本文提供了一种另外的方法:
请输入图片描述

                           Exe文件结构

分析EXE文件结构发现,基本所有的exe文件下有一段特定的字节
56 00 53 00 5f 00 56 00 45 00 52 00 53 00 49 00 4f 00 4e 00 5f 00 49 00 4e 00 46 00 4f 00 00 00 00 00 bd 04 ef fe
请输入图片描述

上图红色下划线部分8个字节就是该EXE的版本号,因为windows下x86或者x64架构内存采用的是小端对齐系统,每两字节组合成一个无符号16位整形Unsigned Short,所以高低字节交换后,对应的版本号位0009.0003.03e8.000b,对应的十进制值为9.3.1000.11,又每两字节交换(第1、2和第3、4字节交换,第5、6字节和第7、8字节交换),得到3.9.11.1000,即为最终的版本号。
完整代码如下,使用该方法可以实现跨平台(兼容Windows、Linux、MacOs),因为本质上是将exe文件读进内存,对原始的16进制源码值进行分析,从而避免调用Windows的API,如果exe文件过大,临时读进内存影响运行效率,还可以对代码进行改造,实行文件分段读取进内存,减少程序运行资源消耗。
废话少说,下面是该方法使用的代码示例
头文件《toolFunc.h》

#ifndef TOOLFUNC_H
#define TOOLFUNC_H
#include <QObject>
#include <QFile>
#include <QDebug>
QString GetExeFileVersion(QString path);
#endif // TOOLFUNC_H

源文件《toolFunc.cpp》

#include "toolFunc.h"
QString GetExeFileVersion(QString path)
{
    QByteArray qByteArrayVer;
    uint16_t u16Ver[4];
    QByteArray key=QByteArray::fromHex("56 00 53 00 5f 00 56 00 45 00 52 00 53 00 49 00 4f 00 4e 00 5f 00 49 00 4e 00 46 00 4f 00 00 00 00 00 bd 04 ef fe");
    QFile file(path);
    if(file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"file open success";
        QByteArray data=file.readAll();
        int posBegin=data.indexOf(key);
        if(posBegin!=-1)
        {
            qByteArrayVer=data.mid(posBegin+key.size()+4,8);
            memcpy(&u16Ver,qByteArrayVer.data(),8);
            return QString::number(u16Ver[1]) + "." +QString::number(u16Ver[0]) + "." +QString::number(u16Ver[3]) + "." +QString::number(u16Ver[2]);
        }
    }
    file.close();
    return "Err.Err.Err.Err";
}

Windows下程序运行结果:
运行环境:windows10 x64
编译环境:QT5.7.0+MinGW5.7.0 32位,最后一个兼容Windows XP的版本)
请输入图片描述

Linux下运行结果:
运行环境:Centos8.2.2004 x64
编译环境:QT5.14.2+GCC8.5.0
请输入图片描述

总结:该方法可在linux、下windows下轻松实现对exe文件的版本号读取。

所有原创文章采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
您可以自由的转载和修改,但请务必注明文章来源并且不可用于商业目的。
本站部分内容收集于互联网,如果有侵权内容、不妥之处,请联系我们删除。敬请谅解!

添加新评论

  关于博主

  近期评论

  •  额: 优秀帅气的小伙子,加油

  分类目录

生活其实很简单,过了今天就是明天。

低头哭过别忘了抬头继续走。

不要被任何人打乱自的脚步,因为没有谁会像你一样清楚和在乎自己梦想。

没有人可以打倒我,除非我自己先趴下!

你要记住你不是为别人而活,你是为自己而活。