在整理程序内部显示版本信息相关的实现.
程序在开发中的时候, 随便硬编码.
现在准备和程序rc资源中的版本信息对应起来, 这样的话, 程序升级后, 只需要改rc中的信息, 不用担心程序中用到的版本信息的硬编码问题.
以前也见过这种类实现, 没存货. 用了2个小时, 自己封装了一个类. 好用.
类变量定义
CInternalVersionInfo* m_pFileVersionInfo;
主程序初始化时(和UI无关, 可以尽早初始化), 初始化类变量.
CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
{
m_pFileVersionInfo = new CInternalVersionInfo(NULL); // 参数1是BlockHeader的name, 默认是中文rc => _T("080404b0")
// 在类构造函数中, 就取到了工程版本信息
// 等要用工程版本信息时, 就拿这个类指针取值来用
}
如果是其他语言rc, 可以看工程实际rc的Block Header的实际值.
程序销毁前, 删除new出来的类实例
void CMoneyCostParserDlg::OnDestroy()
{
__super::OnDestroy();
// ...
if (NULL != m_pFileVersionInfo)
{
delete m_pFileVersionInfo;
m_pFileVersionInfo = NULL;
}
}
// @file CInternalVersionInfo.h
// @brief 取工程内部资源中的文件版本的所有信息, 取的信息等同于右键文件属性看到的文件版本信息
#ifndef __CINTERNALVERSIONINFO_H__
#define __CINTERNALVERSIONINFO_H__
/
Version
//
//VS_VERSION_INFO VERSIONINFO
// FILEVERSION 1,0,0,1
// PRODUCTVERSION 1,0,0,1
// FILEFLAGSMASK 0x3fL
//#ifdef _DEBUG
// FILEFLAGS 0x1L
//#else
// FILEFLAGS 0x0L
//#endif
// FILEOS 0x40004L
// FILETYPE 0x1L
// FILESUBTYPE 0x0L
//BEGIN
// BLOCK "StringFileInfo"
// BEGIN
// BLOCK "080404b0"
// BEGIN
// VALUE "CompanyName", "xx公司"
// VALUE "FileDescription", "xxProg"
// VALUE "FileVersion", "1.0.0.1"
// VALUE "InternalName", "xx.exe"
// VALUE "LegalCopyright", "(C) xx公司 20xx-2023"
// VALUE "OriginalFilename", "xx.exe"
// VALUE "ProductName", "progName"
// VALUE "ProductVersion", "1.0.0.1"
// END
// END
// BLOCK "VarFileInfo"
// BEGIN
// VALUE "Translation", 0x804, 1200
// END
//END
class CInternalVersionInfo
{
public:
CInternalVersionInfo(const TCHAR* pszBlockHeder);
virtual ~CInternalVersionInfo();
// 公开的接口
// 程序顶部显示给用户看的程序标题(效果 => xx程序 Vx.x.x.x)
CString getAppTitle() { return (m_csProductName + _T(" V") + m_csProductVersion); }
// 共有成员
CString m_csCompanyName; // VALUE "CompanyName", "xx公司" => "xx公司"
CString m_csFileDescription; // VALUE "FileDescription", "xxProg" => "xxProg"
CString m_csFileVersion; // VALUE "FileVersion", "1.0.0.1" => "1.0.0.1"
CString m_csInternalName; // VALUE "InternalName", "xx.exe" => "xx.exe"
CString m_csLegalCopyright; // VALUE "LegalCopyright", "(C) xx公司 20xx-2023" => "(C) xx公司 20xx-2023"
CString m_csOriginalFilename; // VALUE "OriginalFilename", "xx.exe" => "xx.exe"
CString m_csProductName; // VALUE "ProductName", "progName" => "progName"
CString m_csProductVersion; // VALUE "ProductVersion", "1.0.0.1" => "1.0.0.1"
private:
const TCHAR* getBlockHeader() { return (LPCWSTR)m_csBlockHeader; }
CString m_csBlockHeader; // BLOCK "080404b0" => "080404b0"
CString get_FileInfoValue(BYTE* byData, const TCHAR* pszValueName);
};
#endif // #ifndef __CINTERNALVERSIONINFO_H__
// @file CInternalVersionInfo.cpp
#include "pch.h" // 其他缺的头文件放在预编译头文件中 e.g. framework.h
#include <winver.h>
#pragma comment(lib, "Version.lib")
#include "CInternalVersionInfo.h"
CInternalVersionInfo::CInternalVersionInfo(const TCHAR* pszBlockHeder)
: m_csBlockHeader(_T("080404b0"))
{
TCHAR szAppName[MAX_PATH];
DWORD dwSize = 0;
DWORD dwHandle = 0;
BYTE* byData = NULL;
TCHAR* lpVers = NULL;
unsigned int uLen = 0;
CString csQuery;
CString csTmp;
if (NULL != pszBlockHeder)
{
m_csBlockHeader = pszBlockHeder;
}
_stprintf(szAppName, _T("%s.exe"), AfxGetApp()->m_pszExeName);
dwSize = GetFileVersionInfoSize(szAppName, &dwHandle);
byData = new BYTE[dwSize + 0x10];
if (NULL != byData)
{
memset(byData, 0, dwSize + 0x10);
GetFileVersionInfo(szAppName, NULL, dwSize, byData);
// VALUE "CompanyName", "xx公司"
m_csCompanyName = get_FileInfoValue(byData, _T("CompanyName"));
// VALUE "FileDescription", "xxProg"
m_csFileDescription = get_FileInfoValue(byData, _T("FileDescription"));
// VALUE "FileVersion", "1.0.0.1"
m_csFileVersion = get_FileInfoValue(byData, _T("FileVersion"));
// VALUE "InternalName", "MoneyCostParser.exe"
m_csInternalName = get_FileInfoValue(byData, _T("InternalName"));
// VALUE "LegalCopyright", "(C) xx公司 2019-2023"
m_csLegalCopyright = get_FileInfoValue(byData, _T("LegalCopyright"));
// VALUE "OriginalFilename", "xx.exe"
m_csOriginalFilename = get_FileInfoValue(byData, _T("OriginalFilename"));
// VALUE "ProductName", "电商账单分析处理"
m_csProductName = get_FileInfoValue(byData, _T("ProductName"));
// VALUE "ProductVersion", "1.0.0.1"
m_csProductVersion = get_FileInfoValue(byData, _T("ProductVersion"));
delete[]byData;
}
}
CInternalVersionInfo::~CInternalVersionInfo()
{
}
CString CInternalVersionInfo::get_FileInfoValue(BYTE* byData, const TCHAR* pszValueName)
{
CString csQuery;
CString csRc;
TCHAR* lpVers = NULL;
unsigned int uLen = 0;
_ASSERT(NULL != pszValueName);
csQuery.Format(_T("\\StringFileInfo\\%s\\%s"), getBlockHeader(), pszValueName);
_ASSERT(NULL != byData);
VerQueryValue(byData, (LPCWSTR)csQuery, (void**)&lpVers, &uLen);
if ((uLen > 0) && (NULL != lpVers))
{
csRc = lpVers;
}
return csRc;
}
要在程序标题上显示一个和实际程序名称版本一致的信息. 在类中封了一个常用函数getAppTitle(), 当然用到时再拼字符串也行, 不过麻烦.
BOOL CMoneyCostParserDlg::OnInitDialog()
{
// ...
// TODO: 在此添加额外的初始化代码
if (NULL != m_pFileVersionInfo)
{
this->SetWindowText(m_pFileVersionInfo->getAppTitle());
}