VS_VERSION_INFO信息的读取

本文介绍了一种在MFC应用程序中读取EXE文件版本信息的方法,通过使用自定义CMiyaVersion类来实现对VS_VERSION_INFO资源的读取,并提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在整理东西,打算把一些小东西分类整理下,与大家分享一下:

很早以前用MFC开始在做工业软件时,经常会遇到版本备份啊什么之类的问题,那时候,不太懂,后来研究了一下API,发现了如何读取VS_VERSION_INFO。

我们知道,MFC生成的exe的所有信息都是在RC\Version\VS_VERSION_INFO里设置的,我们只要在CAboutDlg里,把PRODUCTVERSION的信息读出来,在CAboutDlg里显示出来,这样只需要每次在VVI里修改相关信息,而不用再去考虑相关信息的一致性了,因为信息源只有这一个。


新建一个CMiyaVersion类,

MiyaVersion.h文件:

接口函数为GetFileVersionInfo以及GetValue,使用时,要先调用GetFileVersionInfo获取exe的所有版本信息即:m_pVersionInfo,当然这里提供一个常用的返回信息版本号:lpszVersion,若想获得其它信息,可使用GetValue去获取

  1. CompanyName:获取公:司名称
  2. FileDescription:
  3. FileVersion:
  4. InternalName:
  5. LegalCopyright:
  6. OriginalFilename:
  7. ProductName:
  8. ProductVersion:

#pragma once
  
namespace MiyaVersion
{
#include <shlwapi.h>
#pragma comment(linker, "/defaultlib:version.lib")
 
class CMiyaVersion : public VS_FIXEDFILEINFO
{
public:
	CMiyaVersion();
	virtual ~CMiyaVersion();
 
public:
 	bool     GetFileVersionInfo(LPCTSTR lpszModuleName, LPCTSTR lpszVersion);
 	CString  GetValue(LPCTSTR lpKeyName);
 
protected:
 
	static bool DllGetVersion(LPCTSTR lpszModuleName, DLLVERSIONINFO& dvi);
 
protected:
 
	BYTE* m_pVersionInfo;   // all version info
	
	typedef struct tag_TRANSLATION
	{
		WORD langID;         // language ID
		WORD charset;        // character set (code page)
 
	} TRANSLATION, *LPTRANSLATION;
	
	TRANSLATION m_translation;
}; 
}

MiyaVersion.cpp文件

#include "stdafx.h"
#include "MiyaVersion.h"
  
using namespace MiyaVersion;
 
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
 
CMiyaVersion::CMiyaVersion()
{
    m_pVersionInfo = NULL;
}
 
CMiyaVersion::~CMiyaVersion()
{
	if (m_pVersionInfo != NULL)
	{
		delete []m_pVersionInfo;
		m_pVersionInfo = NULL;
	}
}
 
bool CMiyaVersion::GetFileVersionInfo(LPCTSTR lpszModuleName, LPCTSTR lpszVersion)
{ 
	// default = ANSI code page
	m_translation.charset = 1252;
	memset((VS_FIXEDFILEINFO*)this, 0, sizeof(VS_FIXEDFILEINFO));
	
	// get module handle
	TCHAR chFileName[_MAX_PATH] = {0};
	HMODULE hModule = ::GetModuleHandle(lpszModuleName);
	if (hModule==NULL && lpszModuleName!=NULL)
	{
		return false;
	}
 
	// get module file name
	DWORD dwLen = GetModuleFileName(hModule, chFileName, sizeof(chFileName)/sizeof(chFileName[0]));
	if (dwLen <= 0)
	{
		return false;
	}
 
	// read file version info
	DWORD dwDummyHandle = 0; // will always be set to zero
	dwLen = GetFileVersionInfoSize(chFileName, &dwDummyHandle);
	if (dwLen <= 0)
	{
		return false;
	}
 
	if (m_pVersionInfo != NULL)
	{
		delete []m_pVersionInfo;
		m_pVersionInfo = NULL;
	}
	m_pVersionInfo = new BYTE[dwLen]; // allocate version info
	if (!::GetFileVersionInfo(chFileName, 0, dwLen, m_pVersionInfo))
	{
		if (m_pVersionInfo != NULL)
		{
			delete []m_pVersionInfo;
			m_pVersionInfo = NULL;
		}
 
		return false;
	}
 
	LPVOID lpvi = NULL;
	UINT nLen = 0;
	if (!VerQueryValue(m_pVersionInfo, _T("\\"), &lpvi, &nLen))
	{
		if (m_pVersionInfo != NULL)
		{
			delete []m_pVersionInfo;
			m_pVersionInfo = NULL;
		}
 
		return false;
	}
 
	// copy fixed info to myself, which am derived from VS_FIXEDFILEINFO
	*(VS_FIXEDFILEINFO*)this = *(VS_FIXEDFILEINFO*)lpvi;
	
	// Get translation info
	if (VerQueryValue(m_pVersionInfo, _T("\\VarFileInfo\\Translation"), &lpvi, &nLen) && nLen >= 4)
	{
		m_translation = *(TRANSLATION*)lpvi;
	}
 
	CString strVersion(_T(""));
	strVersion.Format(_T("%d.%d.%d.%d"), \
		HIWORD(this->dwFileVersionMS), LOWORD(this->dwFileVersionMS), \
		HIWORD(this->dwFileVersionLS), LOWORD(this->dwFileVersionLS));
	UINT nTemp = wcslen(strVersion)+1;
 
	lstrcpyn((LPTSTR)lpszVersion, strVersion, nTemp);
  
	return (dwSignature == VS_FFI_SIGNATURE);
}
 
CString CMiyaVersion::GetValue(LPCTSTR lpKeyName)
{
	CString strVal(_T(""));
 
	if (m_pVersionInfo != NULL)
	{      
	   CString strQuery;
	   strQuery.Format(_T("\\StringFileInfo\\%04x%04x\\%s"), m_translation.langID, m_translation.charset, lpKeyName);
		
		LPCTSTR pVal = NULL;
		UINT nLenVal = 0;
		if (VerQueryValue(m_pVersionInfo, (LPTSTR)(LPCTSTR)strQuery, (LPVOID*)&pVal, &nLenVal)) 
		{
			strVal = pVal;
		}
	}
 
	return strVal;
}
 
typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
 
bool CMiyaVersion::DllGetVersion(LPCTSTR lpszModuleName, DLLVERSIONINFO& dvi)
{
	HINSTANCE hInst = LoadLibrary(lpszModuleName);
	if (hInst == NULL)
	{
		return false;
	}
 
	DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hInst, ("DllGetVersion"));
	
	if (pDllGetVersion == NULL)
	{
		return false;
	}
 
	memset(&dvi, 0, sizeof(dvi));        // clear
	dvi.cbSize = sizeof(dvi);            // set size for Windows
	
	return SUCCEEDED((*pDllGetVersion)(&dvi));
}


### 如何通过 GCC 查看 libc 版本或获取与 `__libc_version` 相关的信息 为了验证当前系统中使用的 glibc 或其他实现的 C 标准库版本,可以通过多种方式完成此操作。以下是几种常见且有效的方法: #### 方法一:编译并运行一个显示 glibc 版本的小型程序 构建一段能够访问 `gnu/libc-version.h` 头文件中的函数 `gnu_get_libc_version()` 的源码片段,该头文件提供了关于正在使用的 GNU C Library 的版本信息。 ```c #include <stdio.h> #include <gnu/libc-version.h> // 提供了 gnu_get_libc_version 函数定义 int main() { const char* version = gnu_get_libc_version(); printf("Current GNU libc version: %s\n", version); return 0; } ``` 保存以上代码为 `check_libc.c` 文件后,使用 GCC 编译并执行它: ```bash gcc check_libc.c -o check_libc && ./check_libc ``` 这会输出形如 `Current GNU libc version: 2.31` 的字符串[^1]。 #### 方法二:探索预定义宏 `_LIBC_VERSION` 某些情况下可以直接利用编译器内置的宏来判断所链接的标准库及其版本号。然而需要注意的是,并非所有的标准库都支持这一机制。下面是一个例子演示如何检测是否存在这样的宏定义: ```c #include <stdio.h> #ifdef _LIBC_VERSION #define LIBC_VER_STR "_LIBC_VERSION" #else #define LIBC_VER_STR "Not Defined" #endif int main(){ puts(LIBC_VER_STR); return 0; } ``` 如果确实存在,则可能返回具体的数值形式表示其版本;否则表明未启用此类特性或者根本不存在对应的概念[^4]。 #### 方法三:借助调试工具读取已生成的目标文件属性 除了主动编写测试脚本来提取所需的数据外,还可以依靠外部实用程序辅助完成任务。例如,针对已经成功建立起来的应用程序镜像(ELF格式),可以运用 `readelf` 命令查找其中涉及共享对象的部分,进而推测出它们所属的具体系列及修订等级。 假设有一个名为 `a.out` 的可执行文件,那么可以用下列指令序列来进行分析: ```bash readelf --dyn-syms a.out | grep 'GLIBC' ``` 这样可以获得一系列匹配项列表,每条记录均标明了各自最低需求满足条件——即至少需要达到哪一个 GLIBC 发布版才能正常运作这些接口[^5]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值