S-JIS[2006-09-09/2006-09-14]

バージョン取得方法

実行ファイル(DLLやEXE)のバージョンを確認する方法。


リソースで設定した「バージョン」

VC++でプロジェクトを作ると、リソースのひとつに「Version」(IDはVS_VERSION_INFO)というものがある。
ここで設定したFileVersionやProductVersion(「1, 0, 0, 1」という感じの値)は、 実行ファイルを右クリックしてプロパティを開くと、バージョンタブ内の「ファイルバージョン」や「製品バージョン」で確認できる。
プログラムからは、Win32APIのGetFileVersionInfoVerQueryValueを使用して取得できる。

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;
}

defファイルで設定した「バージョン」

DLLを作成するときによく使われるdefファイルだが、その中でVERSIONという値 (「1.0」という感じ)を設定することが出来る。
ここで設定したバージョンは、dumpbinDependency Walkerによって確認できる。

>dumpbin.exe /headers 実行ファイル名 | findstr /c:"image version"

プログラムから取得する方法は無いっぽい。
(DLLやEXEといった実行ファイルはPEヘッダーと呼ばれるデータを持っており、defファイルで設定したイメージバージョンはこの中に入っているらしい。で、PEヘッダーの内容を取得するAPIは無いらしい。やるなら自分で解析するしかないらしい…)


WindowsカーネルのDLLの「バージョン」

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");

参考


VC++ページへ戻る / 技術メモへ戻る
メールの送信先:ひしだま