2009-02-24 20 views
20

La última vez que hice una pregunta similar, pero eso era sobre svn relacionado con la información de versiones. Ahora me pregunto cómo consultar el atributo "Versión de archivo" de Windows, por ejemplo. un dll. Presté atención también a los módulos wmi y win32file sin éxito.Python windows File Version atributo

Respuesta

4

Encontré esta solución en el sitio "timgolden". Funciona bien.

from win32api import GetFileVersionInfo, LOWORD, HIWORD 

def get_version_number (filename): 
    info = GetFileVersionInfo (filename, "\\") 
    ms = info['FileVersionMS'] 
    ls = info['FileVersionLS'] 
    return HIWORD (ms), LOWORD (ms), HIWORD (ls), LOWORD (ls) 

if __name__ == '__main__': 
    import os 
    filename = os.environ["COMSPEC"] 
    print ".".join ([str (i) for i in get_version_number (filename)]) 
18

Mejor agregar una try/excepto en caso de que el archivo no tenga ningún atributo de número de versión.

filever.py


from win32api import GetFileVersionInfo, LOWORD, HIWORD 

def get_version_number (filename): 
    try: 
     info = GetFileVersionInfo (filename, "\\") 
     ms = info['FileVersionMS'] 
     ls = info['FileVersionLS'] 
     return HIWORD (ms), LOWORD (ms), HIWORD (ls), LOWORD (ls) 
    except: 
     return 0,0,0,0 

if __name__ == '__main__': 
    import os 
    filename = os.environ["COMSPEC"] 
    print ".".join ([str (i) for i in get_version_number (filename)]) 

yourscript.py:


import os,filever 

myPath="C:\\path\\to\\check" 

for root, dirs, files in os.walk(myPath): 
    for file in files: 
     file = file.lower() # Convert .EXE to .exe so next line works 
     if (file.count('.exe') or file.count('.dll')): # Check only exe or dll files 
      fullPathToFile=os.path.join(root,file) 
      major,minor,subminor,revision=filever.get_version_number(fullPathToFile) 
      print "Filename: %s \t Version: %s.%s.%s.%s" % (file,major,minor,subminor,revision) 

Salud!

10

se puede utilizar el módulo de pyWin32 de http://sourceforge.net/projects/pywin32/:

from win32com.client import Dispatch 

ver_parser = Dispatch('Scripting.FileSystemObject') 
info = ver_parser.GetFileVersion(path) 

if info == 'No Version Information Available': 
    info = None 
+1

funciona perfectamente y simple de todas las soluciones! Gracias. – 0x1mason

+0

¿Hay alguna forma en que pueda obtener la descripción del archivo también? No vi ningún método en FileSystemObject que haga eso :( –

+0

Funcionó como un amuleto. ¡Gracias! – Suneelm

21

Aquí es una función que lee todos los atributos de archivo como un diccionario:

import win32api 

#============================================================================== 
def getFileProperties(fname): 
#============================================================================== 
    """ 
    Read all properties of the given file return them as a dictionary. 
    """ 
    propNames = ('Comments', 'InternalName', 'ProductName', 
     'CompanyName', 'LegalCopyright', 'ProductVersion', 
     'FileDescription', 'LegalTrademarks', 'PrivateBuild', 
     'FileVersion', 'OriginalFilename', 'SpecialBuild') 

    props = {'FixedFileInfo': None, 'StringFileInfo': None, 'FileVersion': None} 

    try: 
     # backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struc 
     fixedInfo = win32api.GetFileVersionInfo(fname, '\\') 
     props['FixedFileInfo'] = fixedInfo 
     props['FileVersion'] = "%d.%d.%d.%d" % (fixedInfo['FileVersionMS']/65536, 
       fixedInfo['FileVersionMS'] % 65536, fixedInfo['FileVersionLS']/65536, 
       fixedInfo['FileVersionLS'] % 65536) 

     # \VarFileInfo\Translation returns list of available (language, codepage) 
     # pairs that can be used to retreive string info. We are using only the first pair. 
     lang, codepage = win32api.GetFileVersionInfo(fname, '\\VarFileInfo\\Translation')[0] 

     # any other must be of the form \StringfileInfo\%04X%04X\parm_name, middle 
     # two are language/codepage pair returned from above 

     strInfo = {} 
     for propName in propNames: 
      strInfoPath = u'\\StringFileInfo\\%04X%04X\\%s' % (lang, codepage, propName) 
      ## print str_info 
      strInfo[propName] = win32api.GetFileVersionInfo(fname, strInfoPath) 

     props['StringFileInfo'] = strInfo 
    except: 
     pass 

    return props 
+1

Guau, excelente trabajo. ¿Cómo descubriste las cosas de StringFileInfo ... eso es lo que necesito. Muchas gracias. – iridescent

+1

Para aquellos a los que les importa, 65536 es la mitad de DWORD (2 ** 16) – theannouncer

10

Aquí es una versión que también trabaja en la no de Windows entornos, usando el pefile-module:

import pefile 

def LOWORD(dword): 
    return dword & 0x0000ffff 
def HIWORD(dword): 
    return dword >> 16 
def get_product_version(path): 

    pe = pefile.PE(path) 
    #print PE.dump_info() 

    ms = pe.VS_FIXEDFILEINFO.ProductVersionMS 
    ls = pe.VS_FIXEDFILEINFO.ProductVersionLS 
    return (HIWORD (ms), LOWORD (ms), HIWORD (ls), LOWORD (ls)) 


if __name__ == "__main__": 
    import sys 
    try: 
     print "%d.%d.%d.%d" % get_product_version(sys.argv[1]) 
    except: 
     print "Version info not available. Maybe the file is not a Windows executable" 
+0

Esto lo veo perfectamente en el trabajo, pero lleva más de 10s hacerlo en un exe de 30mb :( – Steve

+3

Me di cuenta de la fuente que puedes cortar ese 10s hasta 1s/2s al analizar solo el directorio de recursos, woo !: 'pe = pefile.PE (path, fast_load = True) pe.parse_data_directories (directorios = [pefile.DIRECTORY_ENTRY ['IMAGE_DIRECTORY_ENTRY_RESOURCE']])' – Steve

+0

Agradable! Quería sugerir algo así. – flocki

2

Aquí hay una versión que no requiere ninguna biblioteca adicional. No podía utilizar win32api como todo el mundo había sugerido:

Desde: https://mail.python.org/pipermail//python-list/2006-November/402797.html

Sólo copiado aquí por si el original va a faltar.

import array 
from ctypes import * 

def get_file_info(filename, info): 
    """ 
    Extract information from a file. 
    """ 
    # Get size needed for buffer (0 if no info) 
    size = windll.version.GetFileVersionInfoSizeA(filename, None) 
    # If no info in file -> empty string 
    if not size: 
     return '' 
    # Create buffer 
    res = create_string_buffer(size) 
    # Load file informations into buffer res 
    windll.version.GetFileVersionInfoA(filename, None, size, res) 
    r = c_uint() 
    l = c_uint() 
    # Look for codepages 
    windll.version.VerQueryValueA(res, '\\VarFileInfo\\Translation', 
            byref(r), byref(l)) 
    # If no codepage -> empty string 
    if not l.value: 
     return '' 
    # Take the first codepage (what else ?) 
    codepages = array.array('H', string_at(r.value, l.value)) 
    codepage = tuple(codepages[:2].tolist()) 
    # Extract information 
    windll.version.VerQueryValueA(res, ('\\StringFileInfo\\%04x%04x\\' 
+ info) % codepage, 
             byref(r), byref(l)) 
    return string_at(r.value, l.value) 

usados ​​de esta manera:

print get_file_info(r'C:\WINDOWS\system32\calc.exe', 'FileVersion') 
+0

'WindowsError: excepción: violación de acceso al leer 0x0000000082E47858' al obtener las páginas de códigos. string_at (r.value, l.value) 'falla allí :( – ewerybody