EXEファイルやDLLファイルなどに含まれているバージョンリソースから情報を取り出すにはGetFileVersionInfoSize、GetFileVersionInfo、VerQueryValueの3つを利用する。
ファイルによってはバージョン情報リソースが複数の言語分だけ用意されていたり、ひとつもなかったりすることもある。ここではGetThreadLocaleで得られるロケールのリソースから取得を試みて、ダメならファイルにあるリソースから順番に取得した。
#include "DnpFileVersion.h"
void Test()
{
CDnpFileVersion ver;
CAtlString str;
ver.Load(_T("c:\\windows\\system32\\acw.exe"));
ver.GetProductVersion(str);
ver.Unload();
::MessageBox(NULL,str,_T(""),MB_OK);
}
#pragma once
#include "atlstr.h"
#pragma comment(lib,"Version.lib")
///
///\brief
/// バージョン情報リソース取得クラス///
///■使用例
/** \code
bool Test()
{
CAtlString strData;
CDnpFileVersion cInfo;
cInfo.Load("C:\\WINDOWS\\system32\\cmd.exe");
cInfo.GetValue("FileDescription",strData);
cInfo.GetComments(strData);
cInfo.GetInternalName(strData);
cInfo.GetProductName(strData);
cInfo.GetCompanyName(strData);
cInfo.GetLegalCopyright(strData);
cInfo.GetProductVersion(strData);
cInfo.GetFileDescription(strData);
cInfo.GetLegalTrademarks(strData);
cInfo.GetPrivateBuild(strData);
cInfo.GetFileVersion(strData);
cInfo.GetOriginalFilename(strData);
cInfo.GetSpecialBuild(strData);
return true;
}
\endcode
*///
///
class CDnpFileVersion
{
protected:
///
///\brief
/// LCIDを展開するための構造体
///
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
};
BYTE* _pVersionInfo; //!< 保持しているバージョンリソース LANGANDCODEPAGE* _pTranslation; //!< コードページ情報配列
UINT _nTranslationLen; //!< コードページ情報配列サイズ(要素数)
UINT _nTranslationDefault; //!< デフォルトで用いるコードページ情報配列へのインデックス
public:
CDnpFileVersion()
{
_pVersionInfo = NULL;
_pTranslation = NULL;
_nTranslationLen = 0;
_nTranslationDefault = 0;
}
~CDnpFileVersion()
{
Unload();
}
///
///\brief
/// バージョン情報のロード ///
///このクラス内にバージョン情報を保持する
///
///\param[in] pszFile
/// バージョン情報を取得したファイルへのパス(EXEやDLLなど)
///
///\retval true 成功
///\retval false 失敗
///
bool Load(LPCTSTR pszFile)
{
BOOL ret;
DWORD dwSize;
BYTE* pData;
BYTE* pResult;
UINT nLen;
Unload();
dwSize = ::GetFileVersionInfoSize(pszFile,NULL);
if(dwSize == 0)
return false;
pData = new BYTE[dwSize];
if(pData == NULL)
return false;
ret = ::GetFileVersionInfo(pszFile,NULL,dwSize,pData);
if(ret)
ret = ::VerQueryValue(pData,_T("\\VarFileInfo\\Translation"),(void**)&pResult,&nLen);
if(ret == FALSE)
{
delete pData;
return false;
}
//デフォルトのコードページがみつかればそれを_nTranslationDefaultに保存しておく
//
///\todo
/// //■■デフォルトLCIDが見つからなかったら、ニュートラル言語などほかのを取得しておくべき
{
UINT i;
LANGANDCODEPAGE* pLcid;
LCID nCurr;
pLcid = (LANGANDCODEPAGE*)pResult;
nCurr = ::GetThreadLocale();
for(i = 0; i < nLen / sizeof(LANGANDCODEPAGE); i++)
{
if(pLcid[i].wLanguage != nCurr)
continue;
_nTranslationDefault = i;
}
}
_pVersionInfo = pData;
_pTranslation = (LANGANDCODEPAGE*)pResult;
_nTranslationLen = nLen / sizeof(LANGANDCODEPAGE);
return true;
}
///
///\brief
/// 保持している情報の破棄
///
void Unload(void)
{
if(_pVersionInfo)
delete _pVersionInfo;
_pVersionInfo = NULL;
_pTranslation = NULL;
_nTranslationLen = 0;
_nTranslationDefault = 0;
}
///
///\brief
/// バージョンリソースの項目を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[in] pszBlockName
/// 取得したいバージョンリソースの名前
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetValue(LPCTSTR pszBlockName,CAtlString& strValue)
{
UINT i;
BOOL ret;
UINT nLen;
BYTE* pData;
CAtlString strPath;
strValue = _T("");
if(_pVersionInfo == NULL || _pTranslation == NULL || _nTranslationLen == 0)
return false;
//最初にデフォルトロケールで探しておく(_nTranslationDefault==0ならどのみちforで最初に検索されるから問題なし)
if(_nTranslationDefault)
{
i = _nTranslationDefault;
strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
if(ret)
{
strValue = (TCHAR*)pData;
return true;
}
}
for(i = 0; i < _nTranslationLen; i++)
{
strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
if(ret == FALSE)
continue;
strValue = (TCHAR*)pData;
return true;
}
return false;
}
///
///\brief
/// バージョン情報の「Comments」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetComments(CAtlString& strValue)
{
return GetValue(_T("Comments"),strValue);
}
///
///\brief
/// バージョン情報の「InternalName」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetInternalName(CAtlString& strValue)
{
return GetValue(_T("InternalName"),strValue);
}
///
///\brief
/// バージョン情報の「ProductName」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetProductName(CAtlString& strValue)
{
return GetValue(_T("ProductName"),strValue);
}
///
///\brief
/// バージョン情報の「CompanyName」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetCompanyName(CAtlString& strValue)
{
return GetValue(_T("CompanyName"),strValue);
}
///
///\brief
/// バージョン情報の「LegalCopyright」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetLegalCopyright(CAtlString& strValue)
{
return GetValue(_T("LegalCopyright"),strValue);
}
///
///\brief
/// バージョン情報の「ProductVersion」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetProductVersion(CAtlString& strValue)
{
return GetValue(_T("ProductVersion"),strValue);
}
///
///\brief
/// バージョン情報の「FileDescription」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetFileDescription(CAtlString& strValue)
{
return GetValue(_T("FileDescription"),strValue);
}
///
///\brief
/// バージョン情報の「LegalTrademarks」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetLegalTrademarks(CAtlString& strValue)
{
return GetValue(_T("LegalTrademarks"),strValue);
}
///
///\brief
/// バージョン情報の「PrivateBuild」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetPrivateBuild(CAtlString& strValue)
{
return GetValue(_T("PrivateBuild"),strValue);
}
///
///\brief
/// バージョン情報の「FileVersion」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetFileVersion(CAtlString& strValue)
{
return GetValue(_T("FileVersion"),strValue);
}
///
///\brief
/// バージョン情報の「OriginalFilename」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetOriginalFilename(CAtlString& strValue)
{
return GetValue(_T("OriginalFilename"),strValue);
}
///
///\brief
/// バージョン情報の「SpecialBuild」を取得する
///
///\attention
/// 複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
///最初に見つかったリソースから文字列を返す
///
///\param[out] strValue
/// 取得した文字列
///
///\retval true 取得成功
///\retval false 失敗
///
bool GetSpecialBuild(CAtlString& strValue)
{
return GetValue(_T("SpecialBuild"),strValue);
}
};