実行ファイル(DLLやEXE)のバージョンを確認する方法。
VC++でプロジェクトを作ると、リソースのひとつに「Version」(IDはVS_VERSION_INFO)というものがある。
ここで設定したFileVersionやProductVersion(「1, 0, 0, 1」という感じの値)は、
実行ファイルを右クリックしてプロパティを開くと、バージョンタブ内の「ファイルバージョン」や「製品バージョン」で確認できる。
プログラムからは、Win32APIのGetFileVersionInfoやVerQueryValueを使用して取得できる。
GetFileVersionInfoに実行ファイルのファイル名を指定することで、ファイル内に保持されたリソースを取得できる。
リソースは日本語以外の言語でも設定できるので、ファイルバージョンやプロダクトバージョン等は それぞれの言語ごとに実行ファイルに記録されている。
具体的には、言語とコードページという数値によって区別している。(日本語で作った実行ファイルは、041104b0。先頭の0411が
「日本語」(「英語(アメリカ)」だと0409)で、後尾の04b0が「UNICODE」。いずれも十六進数2バイト)
これらの情報は階層構造になっており、VerQueryValueでは階層を(ディレクトリを辿るのと同様に)指定する。[2006-09-14]
階層の例 | 値の例 | 内容 | |||
---|---|---|---|---|---|
\ | VarFileInfo | Translation | 040904b0 041104b0 |
保持している言語とコードページの一覧 | |
StringFileInfo | 040904b0 | ProductVersion | 1, 0, 0, 1 | 製品バージョン(英語) | |
FileVersion | 1, 0, 0, 1 | ファイルバージョン(英語) | |||
Comment | sample | コメント(英語) | |||
041104b0 | ProductVersion | 1, 0, 0, 1 | 製品バージョン(日本語) | ||
FileVersion | 1, 0, 0, 1 | ファイルバージョン(日本語) | |||
Comment | サンプル | コメント(日本語) |
//dllファイルやexeファイル内のリソースのバージョン情報を表示する BOOL PrintFileVersion(char* path) { #pragma comment(lib, "version.lib") DWORD dwZero = 0; DWORD dwVerInfoSize = GetFileVersionInfoSize(path, &dwZero); if(dwVerInfoSize == 0) { printError("GetFileVersionInfoSize", GetLastError()); return FALSE; } unsigned char *pBlock; pBlock = new unsigned char[dwVerInfoSize]; if(pBlock == NULL) return FALSE; GetFileVersionInfo(path, dwZero, dwVerInfoSize, pBlock); //バージョンを取得する為のバッファ void *pvVersion; UINT VersionLen; //全言語のプロダクトバージョンを表示する例 struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *lpTranslate; UINT TranslateLen; VerQueryValue(pBlock, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &TranslateLen); for(UINT i=0;i<TranslateLen/sizeof(*lpTranslate);i++){ //コードページを指定 char name[256]; wsprintf(name, TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage ); if(VerQueryValue(pBlock, name, &pvVersion, &VersionLen)){ printf("ProductVersion[%04x%04x]:%d:%s\n", lpTranslate[i].wLanguage, lpTranslate[i].wCodePage, VersionLen, pvVersion ); } } //言語のコードページが分かっている場合は、それを直接指定すればよい //プロダクトバージョン if(VerQueryValue(pBlock, TEXT("\\StringFileInfo\\041104b0\\ProductVersion"), &pvVersion, &VersionLen)){ printf("ProductVersion:%d:%s\n", VersionLen, pvVersion); } //ファイルバージョン if(VerQueryValue(pBlock, TEXT("\\StringFileInfo\\041104b0\\FileVersion"), &pvVersion, &VersionLen)){ printf("FileVersion:%d:%s\n", VersionLen, pvVersion); } //×イメージバージョンはリソースではないので取得できない(エラーになる) //if(VerQueryValue(pBlock, TEXT("\\StringFileInfo\\041104b0\\ImageVersion"), &pvVersion, &VersionLen)){ // printf("ImageVersion:%d:%s\n", VersionLen, pvVersion); //} //×StringFileInfo全体を取得することはできない(エラーにはならないが、長さは0が返ってくる) //if(VerQueryValue(pBlock, TEXT("\\StringFileInfo"), &pvVersion, &VersionLen)){ // printf("FileInfo:%d:%s\n", VersionLen, pvVersion); //→len=0 //} delete [] pBlock; return TRUE; }
DLLを作成するときによく使われるdefファイルだが、その中でVERSIONという値
(「1.0」という感じ)を設定することが出来る。
ここで設定したバージョンは、dumpbinやDependency
Walkerによって確認できる。
>dumpbin.exe /headers 実行ファイル名 | findstr /c:"image version"
プログラムから取得する方法は無いっぽい。
(DLLやEXEといった実行ファイルはPEヘッダーと呼ばれるデータを持っており、defファイルで設定したイメージバージョンはこの中に入っているらしい。で、PEヘッダーの内容を取得するAPIは無いらしい。やるなら自分で解析するしかないらしい…)
Windowsが提供しているDLLの中には、DLLGetVersionという関数を呼べばバージョンが取得できるものがあるらしい。
(つまり、そのDLLの中に DLLGetVersionという関数が定義されている、というだけのことだが)
#include <shlwapi.h>
//DLLGetVersionという関数があるDLLでは、それを使ってバージョンが取得できる
void PrintWinDllVersion(const char *path)
{
HMODULE hModule = LoadLibrary(path);
if(hModule == NULL){
printError("LoadLibrary", GetLastError());
return;
}
DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hModule, "DllGetVersion");
if(DllGetVersion == NULL){
printError("GetProcAddress(DLLGetVersion)", GetLastError());
return;
}
DLLVERSIONINFO dvi = { 0 };
dvi.cbSize = sizeof(dvi);
HRESULT hr = DllGetVersion(&dvi);
if(SUCCEEDED(hr)){
printf("%s version:%x.%x\n", path, dvi.dwMajorVersion, dvi.dwMinorVersion);
}
FreeLibrary(hModule);
}
使用例:
PrintWinDllVersion("shlwapi.dll"); PrintWinDllVersion("Shell32.dll");