Win32 获取EXE/DLL文件版本信息

发布于:2024-02-19 ⋅ 阅读:(101) ⋅ 点赞:(0)

CFileVersion.h

#pragma once

#include <windows.h>
#include <string>
#include <tchar.h>

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

// 版本号辅助类
class CVersionNumber
{
public:
    CVersionNumber() :m_nVer{ 0 } {};

    // 从版本字符串构造
    CVersionNumber(LPCTSTR lpStrVer) :m_nVer{ 0 }
    {
        _stscanf_s(lpStrVer, _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
    }

    // 从指定版本号构造
    CVersionNumber(WORD v1, WORD v2, WORD v3, WORD v4) :m_nVer{ v1, v2, v3, v4 }
    {
    }

    // 从版本字符串构造
    CVersionNumber& operator = (LPCTSTR lpStrVer)
    {
        _stscanf_s(lpStrVer, _T("%hd.%hd.%hd.%hd"), &m_nVer[0], &m_nVer[1], &m_nVer[2], &m_nVer[3]);
        return *this;
    }

    int CompareVersion(const CVersionNumber& ref)
    {
        for (int i = 0; i < _countof(m_nVer); i++)
        {
            if (m_nVer[i] != ref.m_nVer[i])
            {
                return (m_nVer[i] > ref.m_nVer[i] ? 1 : -1);
            }
        }

        return 0;
    }

    bool operator < (const CVersionNumber& ref)
    {
        return CompareVersion(ref) < 0;
    }

    bool operator == (const CVersionNumber& ref)
    {
        return CompareVersion(ref) == 0;
    }

    bool operator > (const CVersionNumber& ref)
    {
        return CompareVersion(ref) > 0;
    }

private:

    WORD m_nVer[4];         //版本号
};

typedef struct _FILE_VERSION_INFO
{
    _tstring strComments;                       //文件注释
    _tstring strInternalName;                   //内部名称
    _tstring strProductName;                    //产品名称
    _tstring strCompanyName;                    //公司名称
    _tstring strLegalCopyright;                 //法律版权
    _tstring strProductVersion;                 //产品版本
    _tstring strFileDescription;                //文件描述
    _tstring strLegalTrademarks;                //合法商标
    _tstring strPrivateBuild;                   //私有构建
    _tstring strFileVersion;                    //文件版本
    _tstring strOriginalFilename;               //原始文件名
    _tstring strSpecialBuild;                   //特殊构建
    _tstring strFileVersionEx;                  //文件版本(从 VS_FIXEDFILEINFO中 获取)
    _tstring strProductVersionEx;               //产品版本(从 VS_FIXEDFILEINFO中 获取)

    CVersionNumber FileVerNumber;               //文件版本号
    CVersionNumber ProductVerNumber;            //产品版本号
}FILE_VERSION_INFO;

class CFileVersion
{
    struct LANGANDCODEPAGE {
        WORD wLanguage;
        WORD wCodePage;

        LANGANDCODEPAGE()
            :
            wLanguage(0),
            wCodePage(0)
        {

        }
    };

public:
    CFileVersion();
    ~CFileVersion();

    CFileVersion operator = (const CFileVersion& r) = delete;
    static FILE_VERSION_INFO GetVersionInfo(const _tstring& strFile);
    static FILE_VERSION_INFO GetCurrentModuleVersionInfo();

public:
    bool LoadFile(const _tstring& strFile);             //加载文件信息
    void Close();

    FILE_VERSION_INFO GetVersionInfo() const;           //整个版本信息

    _tstring GetComments() const;                       //文件注释
    _tstring GetInternalName() const;                   //内部名称
    _tstring GetProductName() const;                    //产品名称
    _tstring GetCompanyName() const;                    //公司名称
    _tstring GetLegalCopyright() const;                 //法律版权
    _tstring GetProductVersion() const;                 //产品版本
    _tstring GetFileDescription() const;                //文件描述
    _tstring GetLegalTrademarks() const;                //合法商标
    _tstring GetPrivateBuild() const;                   //私有版本
    _tstring GetFileVersion() const;                    //文件版本
    _tstring GetOriginalFilename() const;               //原始文件名
    _tstring GetSpecialBuild() const;                   //特别版本
    _tstring GetFileVersionEx() const;                  //文件版本(从 VS_FIXEDFILEINFO中 获取)
    _tstring GetProductVersionEx() const;               //产品版本(从 VS_FIXEDFILEINFO中 获取)
    VS_FIXEDFILEINFO GetFixedFileInfo() const;          //文件的版本信息

private:
    _tstring _QueryInfo(const _tstring& strName) const;
    void _LoadAllInfo();

    LPVOID m_lpVerData;                                 //文件信息数据指针
    LANGANDCODEPAGE m_Translate;                        //语言代码页
    VS_FIXEDFILEINFO m_VsFixedFileInfo;                 //文件的版本信息
    FILE_VERSION_INFO m_VersionInfo;                    //版本信息
};

CFileVersion.cpp

#include "CFileVersion.h"
#include <tchar.h>
#include <strsafe.h>

#pragma comment(lib, "Version.lib")

typedef struct _FILE_VERSION_NUMBER
{
    WORD m_nVer[4];

    _FILE_VERSION_NUMBER() :m_nVer{0} {};

    _FILE_VERSION_NUMBER(LPCTSTR lpStrVer) :m_nVer{0}
    {
        _stscanf_s(lpStrVer, _T("%hd.%hd.%hd.%hd"),
            &m_nVer[0],
            &m_nVer[1],
            &m_nVer[2],
            &m_nVer[3]
        );
    }

    _FILE_VERSION_NUMBER& operator = (LPCTSTR lpStrVer)
    {
        _stscanf_s(lpStrVer, _T("%hd.%hd.%hd.%hd"),
            &m_nVer[0],
            &m_nVer[1],
            &m_nVer[2],
            &m_nVer[3]
        );

        return *this;
    }

    int CompareVersion(const _FILE_VERSION_NUMBER& ref)
    {
        for (int i = 0; i < _countof(m_nVer); i++)
        {
            if (m_nVer[i] != ref.m_nVer[i])
            {
                return (m_nVer[i] > ref.m_nVer[i] ? 1 : -1);
            }
        }

        return 0;
    }

    bool operator < (const _FILE_VERSION_NUMBER& ref)
    {
        return CompareVersion(ref) < 0;
    }

    bool operator == (const _FILE_VERSION_NUMBER& ref)
    {
        return CompareVersion(ref) == 0;
    }

    bool operator > (const _FILE_VERSION_NUMBER& ref)
    {
        return CompareVersion(ref) > 0;
    }

}FILE_VERSION_NUMBER;

#pragma pack(push)
#pragma pack(1)
// 包含文件的版本信息。 此信息与语言和代码页无关
// https://learn.microsoft.com/zh-cn/windows/win32/menurc/vs-versioninfo
typedef struct {
    WORD             wLength;       // VS_VERSIONINFO 结构的长度(以字节为单位),此长度不包括在 32 位边界上对齐任何后续版本资源数据的填充
    WORD             wValueLength;  // Value 成员的长度(以字节为单位)
    WORD             wType;         // 版本资源中的数据类型, 1: 资源包含文本数据 0: 版本资源包含二进制数据
    WCHAR            szKey[15];     // Unicode 字符串 L“VS_VERSION_INFO”
    WORD             Padding1;      // 在 32 位边界上对齐 Children 成员所需的任意或零个 WORD
    //VS_FIXEDFILEINFO Value
    //WORD             Padding2
    //WORD             Children
} VS_VERSIONINFO, * PVS_VERSIONINFO;

#pragma pack(pop)

CFileVersion::CFileVersion()
    :
    m_lpVerData(NULL)
{
    memset(&m_VsFixedFileInfo, 0, sizeof(m_VsFixedFileInfo));
}

CFileVersion::~CFileVersion()
{
    this->Close();
}

FILE_VERSION_INFO CFileVersion::GetVersionInfo(const _tstring& strFile)
{
    CFileVersion verInfo;
    verInfo.LoadFile(strFile);
    return verInfo.GetVersionInfo();
}

FILE_VERSION_INFO CFileVersion::GetCurrentModuleVersionInfo()
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    ::GetModuleFileName(NULL, szBuf, _countof(szBuf));
    return GetVersionInfo(szBuf);
}

bool CFileVersion::LoadFile(const _tstring& strFile)
{
    PVOID pFsRedirectionOldValue = NULL;
    bool isDisableWow64Fs = false;
    bool isSuccess = false;
    UINT cbTranslate = 0;
    DWORD dwVerSize;

    if (strFile.empty())
    {
        return false;
    }

    this->Close();

    m_VersionInfo = FILE_VERSION_INFO();

    // 禁用文件重定向
    isDisableWow64Fs = ::Wow64DisableWow64FsRedirection(&pFsRedirectionOldValue);

    do
    {
        // 获取版本信息数据大小
        dwVerSize = ::GetFileVersionInfoSize(strFile.c_str(), 0);
        if (0 == dwVerSize)
        {
            break;
        }

        // 分配版本信息缓冲
        m_lpVerData = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwVerSize);
        if (!m_lpVerData)
        {
            break;
        }

        // 获取版本信息
        if (!::GetFileVersionInfo(strFile.c_str(), 0, dwVerSize, m_lpVerData))
        {
            break;
        }

        // 获取语言代码
        LANGANDCODEPAGE* lpTranslate = NULL;
        if (!::VerQueryValue(m_lpVerData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate))
        {
            break;
        }

        m_Translate = *lpTranslate;

        // 获取 VS_FIXEDFILEINFO 信息
        PVS_VERSIONINFO lpVersion = (PVS_VERSIONINFO)m_lpVerData;
        if (0 != lpVersion->wValueLength)
        {
            VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)lpVersion + sizeof(VS_VERSIONINFO));

            DWORD dwAlign = 4;
            DWORD_PTR dwPadding = ((DWORD_PTR)pFixedFileInfo % dwAlign);
            if (0 != dwPadding)
            {
                pFixedFileInfo = (VS_FIXEDFILEINFO*)((LPBYTE)pFixedFileInfo + (dwAlign - dwPadding));
            }

            m_VsFixedFileInfo = *pFixedFileInfo;
        }

        // 加载所有信息
        _LoadAllInfo();

        isSuccess = true;

    } while (false);

    // 不成功则关闭
    if (!isSuccess)
    {
        this->Close();
    }

    // 恢复文件重定向
    if (isDisableWow64Fs)
    {
        ::Wow64RevertWow64FsRedirection(pFsRedirectionOldValue);
    }

    return isSuccess;
}

void CFileVersion::Close()
{
    if (m_lpVerData)
    {
        HeapFree(::GetProcessHeap(), 0, m_lpVerData);
        m_lpVerData = NULL;
    }
}

void CFileVersion::_LoadAllInfo()
{
    m_VersionInfo.strComments = _QueryInfo(_T("Comments"));
    m_VersionInfo.strInternalName = _QueryInfo(_T("InternalName"));
    m_VersionInfo.strProductName = _QueryInfo(_T("ProductName"));
    m_VersionInfo.strCompanyName = _QueryInfo(_T("CompanyName"));
    m_VersionInfo.strLegalCopyright = _QueryInfo(_T("LegalCopyright"));
    m_VersionInfo.strProductVersion = _QueryInfo(_T("ProductVersion"));
    m_VersionInfo.strFileDescription = _QueryInfo(_T("FileDescription"));
    m_VersionInfo.strLegalTrademarks = _QueryInfo(_T("LegalTrademarks"));
    m_VersionInfo.strPrivateBuild = _QueryInfo(_T("PrivateBuild"));
    m_VersionInfo.strFileVersion = _QueryInfo(_T("FileVersion"));
    m_VersionInfo.strOriginalFilename = _QueryInfo(_T("OriginalFilename"));
    m_VersionInfo.strSpecialBuild = _QueryInfo(_T("SpecialBuild"));
    m_VersionInfo.strFileVersionEx = GetFileVersionEx();
    m_VersionInfo.strProductVersionEx = GetProductVersionEx();

    m_VersionInfo.FileVerNumber = m_VersionInfo.strFileVersionEx.c_str();
    m_VersionInfo.ProductVerNumber = m_VersionInfo.strProductVersionEx.c_str();

}

_tstring CFileVersion::_QueryInfo(const _tstring& strName) const
{
    _tstring strRes;
    TCHAR strQuery[MAX_PATH] = { 0 };
    LPCTSTR lpQueryRes = NULL;
    UINT uQueryCchSize;

    do
    {
        if (!m_lpVerData)
        {
            break;
        }

        (void)::StringCchPrintf(strQuery, _countof(strQuery),
            _T("\\StringFileInfo\\%04x%04x\\%s"),
            m_Translate.wLanguage,
            m_Translate.wCodePage,
            strName.c_str());

        if (!::VerQueryValue(m_lpVerData, strQuery, (LPVOID*)&lpQueryRes, &uQueryCchSize))
        {
            break;
        }

        strRes = lpQueryRes;

    } while (false);

    return strRes;
}

_tstring CFileVersion::GetComments() const
{
    return m_VersionInfo.strComments;
}

_tstring CFileVersion::GetInternalName() const
{
    return m_VersionInfo.strInternalName;
}

_tstring CFileVersion::GetProductName() const
{
    return m_VersionInfo.strProductName;
}

_tstring CFileVersion::GetCompanyName() const
{
    return m_VersionInfo.strCompanyName;
}

_tstring CFileVersion::GetLegalCopyright() const
{
    return m_VersionInfo.strLegalCopyright;
}

_tstring CFileVersion::GetProductVersion() const
{
    return m_VersionInfo.strProductVersion;
}

_tstring CFileVersion::GetFileDescription() const
{
    return m_VersionInfo.strFileDescription;
}

_tstring CFileVersion::GetLegalTrademarks() const
{
    return m_VersionInfo.strLegalTrademarks;
}

_tstring CFileVersion::GetPrivateBuild() const
{
    return m_VersionInfo.strPrivateBuild;
}

_tstring CFileVersion::GetFileVersion() const
{
    return m_VersionInfo.strFileVersion;
}

_tstring CFileVersion::GetOriginalFilename() const
{
    return m_VersionInfo.strOriginalFilename;
}

_tstring CFileVersion::GetSpecialBuild() const
{
    return m_VersionInfo.strSpecialBuild;
}

_tstring CFileVersion::GetFileVersionEx() const
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    (void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
        HIWORD(m_VsFixedFileInfo.dwFileVersionMS),
        LOWORD(m_VsFixedFileInfo.dwFileVersionMS),
        HIWORD(m_VsFixedFileInfo.dwFileVersionLS),
        LOWORD(m_VsFixedFileInfo.dwFileVersionLS)
    );

    return szBuf;
}

_tstring CFileVersion::GetProductVersionEx() const
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    (void)::StringCchPrintf(szBuf, _countof(szBuf), _T("%hd.%hd.%hd.%hd"),
        HIWORD(m_VsFixedFileInfo.dwProductVersionMS),
        LOWORD(m_VsFixedFileInfo.dwProductVersionMS),
        HIWORD(m_VsFixedFileInfo.dwProductVersionLS),
        LOWORD(m_VsFixedFileInfo.dwProductVersionLS)
    );

    return szBuf;
}

VS_FIXEDFILEINFO CFileVersion::GetFixedFileInfo() const
{
    return m_VsFixedFileInfo;
}

FILE_VERSION_INFO CFileVersion::GetVersionInfo() const
{
    return m_VersionInfo;
}

main.cpp

#include <locale.h>
#include "Win32Utils/CFileVersion.h"

int _tmain(int argc, LPCTSTR argv[])
{
    setlocale(LC_ALL, "");
    FILE_VERSION_INFO info = CFileVersion::GetCurrentModuleVersionInfo();
    return 0;
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到