Obtendo a versão de um EXE ou DLL

Publicado: 03/08/2008 em C++/CLI

Olá Pessoal como vão?
Acredito que depois de uma bela comida típica é hora de voltar ao trabalho, certo?

Então, estava trabalhando estes dias em um código em C++ para obter a versão de executáveis e dll’s e vou compartilhar com vocês o resultado.
A minha solução precisava funcionar tanto no Windows para C++ e .Net quanto para C++ nativo no Windows Mobile e a solução foi uma mistura de API do Windows e C++/CLI para resolver este problema e possibilitar a solução nos dois mundos.

A API do Windows fornece uma função que obtém a informação de versão de um determinado arquivo, ela se chama GetFileVersionInfo()

Por coincidência encontramos um código como exemplo na página da API (uma raridade, devemos comemorar encontrar algum sample direto na documentação de código nativo), o código poderia ser melhor, mas eu resolvi utilizá-lo sem fazer modificações 😀 (preguiça mode ON)

Segue o código do meu GetFileVersion.h

// GetFileVersion.h

#include <windows.h>

bool GetFileVersion( LPCWSTR LibName, WORD *MajorVersion, WORD *MinorVersion, WORD *BuildNumber, WORD *RevisionNumber )
{
    DWORD dwHandle, dwLen; UINT BufLen;
    LPTSTR lpData;
    VS_FIXEDFILEINFO *pFileInfo;
    dwLen = GetFileVersionInfoSize( LibName, &dwHandle );

    if (!dwLen)  
        return false;
    lpData = (LPTSTR) malloc (dwLen);
    if (!lpData)  
        return false;

    if( !GetFileVersionInfo( LibName, dwHandle, dwLen, lpData ) )
    { 
        free (lpData); 
        return false;
    }

    if( VerQueryValue( lpData, L"\", (LPVOID*) &pFileInfo, (PUINT)&BufLen ) )
    { 
        *MajorVersion = HIWORD(pFileInfo->dwFileVersionMS); 
        *MinorVersion = LOWORD(pFileInfo->dwFileVersionMS); 
        *BuildNumber = HIWORD(pFileInfo->dwFileVersionLS); 
        *RevisionNumber = LOWORD(pFileInfo->dwFileVersionLS);
        free (lpData);

        return true;
    }
    free (lpData);

    return false;
}

Para consumier esta função solitária:

    WORD MajorVersion;
    WORD MinorVersion;
    WORD BuildNumber;
    WORD RevisionNumber;

    // Unmanaged
    if( GetFileVersion( L"C:\MyFILE.exe", &MajorVersion, &MinorVersion, &BuildNumber, &RevisionNumber ) )
        cout << "Unmanaged: " << MajorVersion << "." << MinorVersion << "." << BuildNumber << "." << RevisionNumber << endl;
    else
        cout << "Unmanaged: File Version Not Found";

Simples não? Já resolvemos o problema do Win32 e Windows Mobile, basta que inclua-se no projeto este Header e pronto!

Agora precisamos disponibilizar este código para o pessoal do C# e do VB.Net (:P)
Como não temos um componente registrado e nada do gênero, uma excelente solução é utilizar os recursos de interoperabilidade do C++/CLI que faz uma ponte perfeita entre o mundo nativo e o gerenciado.

Vejamos a minha classe para resolver este problema de uma forma que não fique traumático para o desenvolvedor .Net consumir este recurso.

// FileVersionInfo.h

#pragma once

#include <msclrmarshal.h>
#include "GetFileVersion.h"

using namespace System;
using namespace std;
using namespace msclr::interop;

namespace SystemInfo {

    public ref class FileVersionInfo
    {
    public:
        static Version^ GetFileVersion( String^ fileName )
        {
            WORD MajorVersion;
            WORD MinorVersion;
            WORD BuildNumber;
            WORD RevisionNumber;
            marshal_context context;

            if( !::GetFileVersion( context.marshal_as< LPCWSTR, System::String^>( fileName ), &MajorVersion, &MinorVersion, &BuildNumber, &RevisionNumber ) )
                throw gcnew System::Exception( "File Version Not Found" );

            return gcnew System::Version( MajorVersion, MinorVersion, BuildNumber, RevisionNumber );
        }
    };
}

Isto num um projeto do tipo Dynamic Library(.dll) com a opção /clr do compilador ativada gera um assembly .Net totalmente transparente para ser utilizado pelo pessoal do C# e do VB.Net (:P:P) heheheh

Para consumir no .Net fica bem simples

System.Version version = SystemInfo.FileVersionInfo.GetFileVersion( "

C:\MyFILE.exe" );

Utilizar um try/catch vai muito bem 😀

Este é um dos grandes motivos pode eu gostar muito do C++/CLI, esta facilidade de trabalhar nos dois mundos é fascinante e fornece muito poder ao nosso software.
Notem no código a utilização do context.marshal_as, para fazermos a conversão da string gernciada para um dos vários tipos de strings que podemos usar no mundo nativo, tudo isto está acontecendo e teremos muito mais para tornar nosso software cada vez mais power!

Fiquem ligados e divirtam-se!

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s