PythonでEXEファイルのバージョン取得

Windows環境のPythonで、EXEファイルやDLLファイルのバージョンを調べようと思ったとき、ctypesをうまく使うことで、簡単にバージョン情報を手に入れることができたので、記述しておこうと思います。

そもそも、WindowsC++プログラミングをしていても、バージョンを取得するにはversion.libをソフトウェアに抱えるか、version.dllを呼び出す必要があるようです。

version.dllには、バージョンを扱うための関数GetFileVersionInfoSize、GetFileVersionInfo、VerQueryValueが含まれています。

これをPythonで利用することで、EXEやDLLのバージョン取得を容易に行うことができるようになります。

#!/usr/bin/env python
# coding: utf-8

import array
from ctypes import *

def get_file_version(file_name = '', info = ''):
    if '' == file_name or '' == info:
        return ''
    # get file version size
    size = windll.version.GetFileVersionInfoSizeA(file_name, None)
    if not size:
        return ''
    # create buffer
    res = create_string_buffer(size)
    # get file version info
    windll.version.GetFileVersionInfoA(file_name, None, size, res)
    r = c_uint()
    l = c_uint()
    # query value
    windll.version.VerQueryValueA(res, '\\VarFileInfo\\Translation',
                                  byref(r), byref(l))
    if not l.value:
        return ''
    # create array
    codepages = array.array('H', string_at(r.value, l.value))
    codepage = tuple(codepages[:2].tolist())
    # query value
    windll.version.VerQueryValueA(res,
                                  ('\\StringFileInfo\\%04x%04x\\' + info) % codepage,
                                  byref(r), byref(l))
    return string_at(r.value, l.value)

if __name__ == '__main__':
    file_name = 'C:\\windows\\system32\\notepad.exe'
    info = 'FileVersion'
    version = get_file_version(file_name, info)
    print('%s: %s' % (file_name, version))

GetFileVersionInfoAの4番目の引数は文字列型のポインタなのですが、これはスクリプト側でcreate_string_bufferしておく必要があるようです。

一回目のVerQueryValueAで、OSの言語のコードページというものを取得します。
二回目のVerQueryValueAで、先ほどのコードページを元にして、バージョンを手に入れます。

このスクリプトを実行するとnotepadのバージョンを出力します。

Pythonのライブラリには、「Win32 Extensions for Python」を使ってもできそうです。
ただ、バージョン確認のためだけに、ライブラリをインストールするのは忍びないという方は、今回のスクリプトを使うと良いと思います。

他にもctypesを利用すれば、いろいろなWin32 APIを利用できるようなので、調査すると良いかもしれませんね。