Wie erhalte ich programmgesteuert die Version einer DLL- oder EXE-Datei?

73

Ich muss die Produktversion und die Dateiversion für eine DLL- oder EXE-Datei mit nativen Win32-APIs in C oder C ++ abrufen. Ich suche nicht nach der Windows-Version, sondern nach den Versionsnummern, die Sie sehen, wenn Sie mit der rechten Maustaste auf eine DLL-Datei klicken, "Eigenschaften" auswählen und dann auf die Registerkarte "Details" klicken. Dies ist normalerweise eine vierteilige gepunktete Versionsnummer xxxx

JSB ձոգչ
quelle
Welche Sprache benutzt du?
Overslacked
GetFileVersionInfo ()
Matt Schmidt
7
Es spielt keine Rolle, ob er nur Win32-API-Aufrufe möchte. Jede Sprache, die das Aufrufen von System-DLLs unterstützt, sollte in Ordnung sein.
Crashmstr
Bearbeitet, um zu verdeutlichen, dass es sich um C / C ++ handelt.
JSB 2

Antworten:

107

Sie würden die GetFileVersionInfo- API verwenden.

Siehe Verwenden von Versionsinformationen auf der MSDN-Site.

Stichprobe:

DWORD  verHandle = 0;
UINT   size      = 0;
LPBYTE lpBuffer  = NULL;
DWORD  verSize   = GetFileVersionInfoSize( szVersionFile, &verHandle);

if (verSize != NULL)
{
    LPSTR verData = new char[verSize];

    if (GetFileVersionInfo( szVersionFile, verHandle, verSize, verData))
    {
        if (VerQueryValue(verData,"\\",(VOID FAR* FAR*)&lpBuffer,&size))
        {
            if (size)
            {
                VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
                if (verInfo->dwSignature == 0xfeef04bd)
                {

                    // Doesn't matter if you are on 32 bit or 64 bit,
                    // DWORD is always 32 bits, so first two revision numbers
                    // come from dwFileVersionMS, last two come from dwFileVersionLS
                    TRACE( "File Version: %d.%d.%d.%d\n",
                    ( verInfo->dwFileVersionMS >> 16 ) & 0xffff,
                    ( verInfo->dwFileVersionMS >>  0 ) & 0xffff,
                    ( verInfo->dwFileVersionLS >> 16 ) & 0xffff,
                    ( verInfo->dwFileVersionLS >>  0 ) & 0xffff
                    );
                }
            }
        }
    }
    delete[] verData;
}
Crashmstr
quelle
1
int revision = HIWORD(verInfo->dwProductVersionLS); int build = LOWORD(verInfo->dwProductVersionLS);
Igor Jerosimić
6
Ich weiß, es ist eine Weile her, aber für Neulinge wie mich erhalten Sie so den .exe-Dateinamen:TCHAR szVersionFile[MAX_PATH]; GetModuleFileName(NULL, szVersionFile, MAX_PATH );
BurninatorDor
1
@ BurninatorDor Nenne dich nicht Neuling. Ich programmiere bisher seit 6 Jahren in MFC, und das hat mir geholfen.
Neil
2
Diese Antwort wurde bearbeitet, weil die Versionsnummern falsch berechnet wurden. Aus den MSDN-Dokumenten für dwProductVersionMS: "Die höchstwertigen 32 Bit der binären Versionsnummer der Datei. Dieses Mitglied wird mit dwFileVersionLS verwendet, um einen 64-Bit-Wert zu bilden, der für numerische Vergleiche verwendet wird." Sie verwenden also beide, um die Versionsnummer zu berechnen. Die ersten beiden (Dur / Moll) befinden sich in versionMS und die letzten beiden (Revision / Build) in versionLS. Es spielt keine Rolle, ob Sie 32/64 Bit haben, DWORD ist immer 32 Bit.
Mgandi
1
NULLsollte nicht mit DWORDs verwendet werden ( 0wäre stattdessen korrekt)
MM
20

Alle diese Lösungen funktionierten nicht richtig (mit meinem System). Ich fand heraus, dass jeder der vier Teile der Versionsnummer als 16-Bit-Wert gespeichert ist.

Die ersten beiden Nummern werden im 32-Bit-DWORD dwFileVersionMS und die zweiten beiden in dwFileVersionLS gespeichert. Also habe ich Ihren Code im Ausgabeabschnitt folgendermaßen bearbeitet:

    TRACE( "File Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwFileVersionMS >> 16 ) & 0xffff,
        ( pFileInfo->dwFileVersionMS >>  0 ) & 0xffff,
        ( pFileInfo->dwFileVersionLS >> 16 ) & 0xffff,
        ( pFileInfo->dwFileVersionLS >>  0 ) & 0xffff
        );

Und es funktioniert perfekt. Die Ausgabe ist wie auf meinem System formatiert:

major.minor.build.revision

Dave Chandler
quelle
19

Sie erhalten diese Informationen über die Versionsinformations-APIs . Hier ist ein Beispiel:

void PrintFileVersion( TCHAR *pszFilePath )
{
    DWORD               dwSize              = 0;
    BYTE                *pbVersionInfo      = NULL;
    VS_FIXEDFILEINFO    *pFileInfo          = NULL;
    UINT                puLenFileInfo       = 0;

    // Get the version information for the file requested
    dwSize = GetFileVersionInfoSize( pszFilePath, NULL );
    if ( dwSize == 0 )
    {
        printf( "Error in GetFileVersionInfoSize: %d\n", GetLastError() );
        return;
    }

    pbVersionInfo = new BYTE[ dwSize ];

    if ( !GetFileVersionInfo( pszFilePath, 0, dwSize, pbVersionInfo ) )
    {
        printf( "Error in GetFileVersionInfo: %d\n", GetLastError() );
        delete[] pbVersionInfo;
        return;
    }

    if ( !VerQueryValue( pbVersionInfo, TEXT("\\"), (LPVOID*) &pFileInfo, &puLenFileInfo ) )
    {
        printf( "Error in VerQueryValue: %d\n", GetLastError() );
        delete[] pbVersionInfo;
        return;
    }

    // pFileInfo->dwFileVersionMS is usually zero. However, you should check
    // this if your version numbers seem to be wrong

    printf( "File Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwFileVersionLS >> 24 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >> 16 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >>  8 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >>  0 ) & 0xff
        );

    // pFileInfo->dwProductVersionMS is usually zero. However, you should check
    // this if your version numbers seem to be wrong.

    printf( "Product Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwProductVersionLS >> 24 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >> 16 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >>  8 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >>  0 ) & 0xff
        );
}
JSB ձոգչ
quelle
2
Ich denke das ist falsch. Für die Dateiversion 1.0.0.1 gibt mir diese Funktion "0.0.0.1". Ich endete mit @Vasyas Antwort
Liorda
7

Dieser Code zeigt die Versionsnummern der Datei korrekt an.

( pFileInfo->dwFileVersionMS >> 16 ) & 0xff,
( pFileInfo->dwFileVersionMS >> 0 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  16 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  0 ) & 0xff);
Vasya
quelle
4
Können Sie dieser Antwort einen Kontext geben? Es scheint unvollständig zu sein. Wenn es sich um eine Korrektur einer anderen Antwort handelt, hinterlassen Sie bitte einen Kommentar dazu oder bearbeiten Sie diese Antwort. Sie wird von einem erfahreneren Benutzer genehmigt.
Deanna
Dies funktioniert definitiv nicht richtig, wenn die Version eine Komponente größer als 255 enthält, z. B. 6.1.3709.2. Die vier Komponenten sind 16-Bit-Zahlen, keine 8-Bit-Zahlen.
Spike0xff
Das ist nicht richtig. Die einzelnen Teile der Versionen sind 16-Bit-Werte. Der Code sollte (pFileInfo-> dwFileVersionMS >> 16) & 0xffff, (pFileInfo-> dwFileVersionMS >> 0) & 0xffff, (pFileInfo-> dwFileVersionLS >> 16) & 0xffff, (pFileInfo-> dwFileVersionLS >> sein) 0xffff);
DaveCleland
Wie schon vor langer Zeit !!! Aber ich kann die Lösung teilen. Ich habe mich dann geweigert, Informationen über ausführbare Dateien vom Kerneltreiber zu erhalten. Ich habe diese Funktion dann auf den Dienst übertragen. Der Fahrer übermittelte Informationen über den Beginn des Prozesses und erwartete eine Lösung vom Dienst
Vasya
4

Am einfachsten ist es, die API-Funktionen GetFileVersionInfoEx oder GetFileVersionInfo zu verwenden.

Sie können dies auch aus Ihren Anwendungsressourcen heraus tun, wie hier erläutert .

Dani van der Meer
quelle
-2

Da keine der Antworten dies erwähnt ... Ich habe herausgefunden, dass Sie unterschiedliche Berechnungen durchführen müssen, je nachdem, ob Sie auf 32- oder 64-Bit-Systemen arbeiten . Deshalb finden Sie, dass bestimmte Antworten in dieser Frage für Sie funktionieren und andere nicht.

Hier ist eine Beispielimplementierung, die ich verwende:

if(IsWow64())
{
        // 64 bit build
        major =     (verInfo->dwProductVersionMS >> 16) & 0xffff;
        minor =     (verInfo->dwProductVersionMS >>  0) & 0xffff;
        revision =  (verInfo->dwProductVersionLS >> 16) & 0xffff;
        build =     (verInfo->dwProductVersionLS >>  0) & 0xffff;
} 
else
{
        // 32 bit build
        major =     HIWORD(verInfo->dwProductVersionMS);
        minor =     LOWORD(verInfo->dwProductVersionMS);
        revision =  HIWORD(verInfo->dwProductVersionLS);
        build =     LOWORD(verInfo->dwProductVersionLS);
}

Und die Implementierung von IsWow64 (nicht von mir):

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            // Handle error...
        }
    }
    return bIsWow64;
}
Amadeus Hein
quelle
Können Sie einen Fall angeben, in dem sich diese beiden Bedingungen unterscheiden? Alle Werte sind feste Längen DWORDs, die in zwei WORDs aufgeteilt werden können. Ihre 64-Bit-Bedingungen scheinen auch jeden Wert auf 255 anstatt auf 32767 zu kürzen.
Deanna
Ihr Code ist falsch. Das Erstellen eines UND mit 0xFF lähmt die Versionsnummer. Einige Anwendungen haben eine Versionsnummer von beispielsweise "2.32.1.1300". Ihr Code würde zu falschen Ergebnissen führen. Richtig ist AND mit 0xFFFF, was das gleiche Ergebnis wie bei Verwendung von LOWORD / HIWORD ergeben würde. Dieser Beitrag sollte herabgestuft werden, da er definitiv falsch ist.
Elmue
Oder Sie können die Bearbeitung @Elmue vorschlagen. Wenn Sie editauf den Beitrag klicken , sollten Sie die Möglichkeit haben, Änderungsvorschläge zu erstellen, die die Moderatoren dann genehmigen / ablehnen.
KayleeFrye_onDeck
5
Warum benötigen Sie unterschiedliche Berechnungen für 32bit und 64bit? Die Versions- / Produktnummern sind feste 32-Bit- DWORDWerte für 32-Bit- und 64-Bit-Builds. Bei einem 64-Bit-Build verlängern die Makros HIWORD()und LOWORD()das DWORDs auf null bis 64 DWORD_PTRBit, bevor sie bitverschoben werden. Das Endergebnis sind jedoch dieselben Werte. Außerdem IsWow64()erkennt ein 64bit Build sowieso nicht. IsWow64Process()Gibt TRUE nur für einen 32-Bit-Build zurück, der in WOW64 ausgeführt wird. Es handelt sich also immer noch um einen 32-Bit-Build. Um zwischen 32-Bit- und 64-Bit-Builds zu unterscheiden, müssen Sie #if(n)def _WIN64stattdessen verwenden.
Remy Lebeau
Wie @RemyLebeau sagt, variiert die Größe der Werte nicht zwischen 32 Bit und 64 Bit. Sie erhalten also identische Ergebnisse aus beiden Berechnungen.
DaveCleland