Produktversion aus Exe-Datei auslesen



  • Hallo Leute,

    Erst mal möchte ich mich kurz vorstellen:

    Ich bin eigentlich PHP-Programmierer und habe dort schon einige Jahre Erfahrung. C++ hingegen hatte ich nur in der Schulzeit und habe mich danach aber nicht weiter damit befasst. Vom PHP her kenne ich natürliche viele Sachen wie Vars, Klassen usw. aber C++ ist doch ein bisschen anders. Hab jetzt die letzten 3 Wochen schon meine ersten 500 Zeilen geschrieben und bin auch im großen und ganzen ziemlich zu Frieden, scheiter aber immer wieder an Kleinigkeiten.

    Hier mal mein aktuelles Problem:
    Ich muss aus einer Exe-Datei die Produktversion auslesen, welche man mit Rechtsklick > Details findet. Das ganze ist ein String mit Buchstaben usw., daher brauche ich es wieder in einem String.

    Folgendes konnte ich bereits mit der Suche finden und erfolgreich lösen:

    - Die Version.lib in den Build-Optionen verlinken

    Bei folgendem habe ich noch Problem:

    - Einfache Funktion bauen, mit der ich die Produktversion möglichst unkompliziert auslesen kann. Die Ziel-Exe ist 32Bit, das auslesen soll aber von Win XP SP3 - Win 8 32/64Bit funktionieren.

    Folgendes habe ich bereits ausprobiert:

    - http://www.c-plusplus.net/forum/312228-full
    Ich kann die Funktion nicht aufrufen, weil er major und minor als Übergabe nicht akzeptiert. Kann mir da jemand sagen, wie ich die Funktion aufrufen muss, damit ich das Ergebnis in eine String-Variable speichern kann?

    - http://stackoverflow.com/questions/940707/how-do-i-programatically-get-the-version-of-a-dll-or-exe-file
    Die Anzeige funktioniert, aber der angezeigte Wert dürfte etwas anderes sein. Ich bekomme 0.1.0.185, per Rechtsklick>Details bekomme ich aber V7...

    Hänge da schon seit 1 Woche fest und bin langsam demotiviert. Bin zwar froh, dass meine anderen Programmierungen weiter gehen, aber das wäre ein wichtiges Feature. Wäre toll, wenn mir jemand helfen könnte.

    Schöne Grüße aus Tirol!



  • Wenn der Ersteller der exe mit Hilfe seines Compilers da nirgendwo eine Produktversion wie 1.0.0.0 hineingeschrieben hat, nützt alles Suchen nichts, weil nicht zu finden.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (auch C++0x und C++11) in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Das Problem ist, dass es viele Wege gibt, eine Version zu definieren. Wenn da irgendwo V7 steht, dann wahrsch. in der "Dateibeschreibung"?!



  • scheiter aber immer wieder an Kleinigkeiten.

    Das was du hier vorhast, ist keine. Die korrekte Verwendung von der Funktion von mgaeckler in http://www.c-plusplus.net/forum/312228-full ist aber eine. Beschäftige dich noch mal mit Zeigern!
    Außerdem erledigt die Funktion auch nicht das, was du möchtest (Dateiversion als zwei 32-bit Integer).
    Du willst die Produktversion als String, diese _kann_ jedoch mehrmalig in verschiedenen Sprachen, vorkommen. Welche willst du in diesem Fall?
    Wieso reicht die Produktversion als zwei 32-bit Integer nicht aus? Dafür hast du ja bereits Code gefunden.



  • Danke für eure Antworten bis jetzt. Das mit der mehrfachen Versionsdeklaration war mit noch nicht klar.

    Hier der genaue Weg, wo die Version eingetragen ist:

    Rechtsklick > Eigenschaften > Reiter Details > Eigenschaft "Beschreibung" > Untereigenschaft "Produktversion", eingetragen als String.

    Der Grund, warum ich genau die brauche ist, dass der Entwickler der exe nur diesen Versionsnummer verändert (die andere Versionsnummer, welche mit dem Beispielcode ausgelesen wird, offensichtlich nicht).

    Ich bräuchte also genau diesen String, damit ich ihn weiterverarbeiten kann. Einfluss auf den Programmierer der Exe habe ich leider nicht.

    Gibts eine Möglichkeit auf diese Dateieingeschaften zugreifen zu können?
    GetFileVersionInfo scheint ja demnach nicht das richtige für mich zu sein.



  • Oh, das ist natürlich ein Grund. Wenn die EXE nur eine Dateiinfoübersetzung hat, kannst du die Schleife ja herausnehmen, die Funktion in get_product_version umbenennen und einen std::wstring zurückgeben. Eine richtige Fehlerüberprüfung kann natürlich auch noch hinzugefügt werden.

    #include <iostream>
    #include <iomanip>
    #include <string>
    #include <sstream>
    #include <memory>
    #include <Windows.h>
    
    #pragma comment(lib, "version.lib")
    
    static bool
    print_product_versions(std::wstring const & file_name)
    {
    	DWORD size = GetFileVersionInfoSizeW(file_name.c_str(), nullptr);
    	if (size == 0)
    	{
    		return false;
    	}
    
    	std::unique_ptr<BYTE[]> data(new BYTE[size]);
    	if (data.get() == nullptr)
    	{
    		return false;
    	}
    
    	if (!GetFileVersionInfoW(file_name.c_str(), 0, size, data.get()))
    	{
    		return false;
    	}
    
    	struct { WORD langID, charsetID; } *translations;
    	UINT translations_cb;
    	if (!VerQueryValueW(data.get(), L"\\VarFileInfo\\Translation", reinterpret_cast<PVOID*>(&translations), &translations_cb))
    	{
    		return false;
    	}
    
    	do
    	{
    		std::wostringstream sub_block_ss;
    		sub_block_ss << L"\\StringFileInfo\\" <<
    			std::hex << std::setw(4) << std::setfill(L'0') << translations->langID <<
    			std::hex << std::setw(4) << std::setfill(L'0') << translations->charsetID <<
    			L"\\ProductVersion";
    		std::wstring sub_block(sub_block_ss.str());
    		PWCHAR product_version;
    		UINT product_version_size;
    
    		if (!VerQueryValueW(data.get(), sub_block.c_str(), reinterpret_cast<PVOID*>(&product_version), &product_version_size))
    		{
    			return false;
    		}
    
    		std::wcout << L'`' << sub_block << L"': " << product_version << L'\n';
    
    		++translations;
    	}
    	while (translations_cb -= sizeof(*translations));
    
    	return true;
    }
    
    int
    main()
    {
    	std::wcout << L"File Name: ";
    	std::wstring file_name;
    	std::getline(std::wcin, file_name);
    	if (!print_product_versions(file_name))
    	{
    		std::wcerr << L"Some error occured!\n";
    	}
    }
    


  • Das sieht schon mal ganz gut aus. Hätte ich selbst so nie hin bekommen. Vielen Dank auf jeden Fall. 👍

    Habs versucht umzusetzen und bekomme noch folgende Fehler:

    nullptr ist von C++ 11. Ist offensichtlich in meinem GCC-Compiler von Code::Blocks nicht drin. Habe deshalb NULL verwendet und jetzt wird nicht mehr gemeckert.

    Folgende sind mir noch nicht ganz klar:

    In function 'bool print_product_versions(const wstring&)':|
    225|error: 'unique_ptr' is not a member of 'std'|
    225|error: expected primary-expression before '[' token|
    225|error: expected primary-expression before ']' token|
    225|error: 'data' was not declared in this scope|

    Liegt das an dem GCC-Compiler? Hm... vielleicht gibt es dafür auch alte Wörter.



  • "alte Wörter" LOL.
    Ja, gibt es std::auto_ptr<>. Aber schaue mal in Settings->Compiler. Dort gibt es so eine Option: "Have g++ follow the C++11 ISO...". Die hilft da. Denn wenn C++11 ein Compiler kann, dann ist es der gcc.



  • Haha, alte Wörter. Seh auch grad, was ich da geschrieben habe. Vermutlich ist mir das wegen Programmier"sprache" eingefallen. 🕶

    Perfekt. Habs in den Build-Optionen eingestellt und jetzt geht der obere Code einwandfrei und liefert genau das richtige Ergebnis.

    Herzlichen Dank an alle für eure tolle Unterstützung! 👍


Anmelden zum Antworten