c++ GetFileVersionInfo

markzw

Grünschnabel
Hallo zusammen,

Ich habe eine Methode in C++ welche abhängig von MFC ist.
Die Methode wird aber in einem Projekt hinzugefügt in dem MFC nicht existiert.

Das Programm wird auf Win XP (32Bit) kompiliert und ausgeführt. Der Compiler ist von Visual Studio 9.0

Nun, die anderen Methoden konnte ich so umschreiben, dass sie nicht mehr von MFC abhängig sind. Nur bei GetFileVersionInfo() komme ich nicht weiter.

Code:
CString CWriteLog::GetFileVersionInfoString(CString strFile, CString strProperty)
{
    int rc;
    UINT nLen;
    DWORD nSize;
    DWORD dwHandle = 0;
    CString strBuffer;
    CString strValue;
	CString returnValue;
    CString strBlock;
    void *lpPropertyBuffer;

    struct LANGANDCODEPAGE
    {
      WORD wLanguage;
      WORD wCodePage;
    } *lpTranslate;

    nSize = GetFileVersionInfoSize(strFile.GetBuffer(), &dwHandle);
    if(::GetFileVersionInfo(strFile.GetBuffer(), 0, nSize, strBuffer.GetBuffer(nSize)))
	{
		// Read the list of languages and code pages.
		if (VerQueryValue(strBuffer.GetBuffer(), "\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &nLen))
		{
			strBlock.Format("\\StringFileInfo\\%04x%04x\\%s",
				lpTranslate->wLanguage,
				lpTranslate->wCodePage,
				strProperty);
			rc = VerQueryValue(strBuffer.GetBuffer(), strBlock.GetBuffer(nSize), &lpPropertyBuffer, &nLen);
			if (rc != 0 && nLen > 0)
			{
				strncpy(strValue.GetBuffer(nLen + 1), (char *) lpPropertyBuffer, nLen);
				strValue.ReleaseBuffer(nLen);
			}
		}
		returnValue=strValue;
    }
	else returnValue="no data";
    return returnValue;
}

Beim Aufruf GetFileVersionInfoSize(strFile.GetBuffer(),... )
ist der Aufruf strFile.GetBuffer() zu 100% MFC abhängig. Weiter habe ich nicht herausgefunden wie die GetBuffer() Funktion funktioniert. Was tut die genau oder wie kann ich diesen Aufruf MFC unabhängig machen?

Freundliche Grüsse
Mark
 
Hi und Willkommen im Forum

Zu deinem Problem: etFileVersionInfo ist nicht MFC abhängig, aber wie du schon richtig erkannt hast, das GetBuffer()
Die Methode ist ein Teil von der CString-Klasse, und die ist leider als komplettes MFC-spezifisch...
besser du lasst das cstring und nimmst normale charpointer.
Gruß
 
C++:
const std::wstring CWriteLog::GetFileVersionInfoString(std::wstring const& file, std::wstring const& property)
{

        DWORD temp(0);
        const DWORD size(::GetFileVersionInfoSizeW(file.c_str(), &temp);
       if (size == 0) throw std::invalid_argument("invalid filename");

    
    unsigned char* ptr_buffer(new unsigned char[size]);

        if (::GetFileVersionInfoW(file.c_str(), 0, size, reinterpret_cast<LPVOID>(ptr_buffer)) == 0) throw std::invalid_argument("invalid file");


    if (::VerQueryValueW(ptr_buffer, L"\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &nLen))
    {
usw ...
 
Hey, vielen Dank für eure Antworten :)

Ich konnte schon einiges umsetzen.
Es gibt jedoch einen weiteren Methodenaufruf, den es nur für die Klasse CString gibt.
Dabei Handelt es sich um strBlock.Format(...)

Code:
CString strBlock;
....
struct LANGANDCODEPAGE
{
       WORD wLanguage;
       WORD wCodePage;
       } *lpTranslate;
...
strBlock.Format("\\StringFileInfo\\%04x%04x\\%s",
       lpTranslate->wLanguage,
       lpTranslate->wCodePage,
       strProperty);

wie funktioniert diese Methode genau und wie könnte man sie anpassen, damit sie von der Klasse CString unabhängig wäre?


Die ganze Methode, welche CString unabhängig sein soll, erhält zwei strings mit Dateiname und dem was ausgelesen werden soll.
z.B. GetFileVersionInfoString("myProgramm.exe","FileVersion")
als return wert erhält man dann z.B. 1.0.0.1
 
vielen Dank für deine Antwort.

Weisst du zufälligerweise wie die Methode heisst?
Bis jetzt konnte ich via google keinen Ansatz finden, wie ich ostringstream anwenden soll.
 
Ich habe eine Lösung für die Methode Format gefunden.
Da gibt es eine Library StrUtils mit der Methode Format(...) die genau das macht, was sie soll :)


nun bin ich noch beim debuggen:
die Methode sieht nun so aus, nur ist es so, dass sie noch nichts zurückgibt. (also keine Versionsnummer usw...)

Code:
const std::string CWriteLog::GetFileVersionInfoString(std::string strFile, std::string strProperty)
{
    int rc;
    UINT nLen;
    DWORD nSize;
    DWORD dwHandle = 0;
	std::string strBuffer;
    char* strValue;
	std::string returnValue;
	std::string strBlock;
    void *lpPropertyBuffer;

	struct LANGANDCODEPAGE
		{
		  WORD wLanguage;
		  WORD wCodePage;
		} *lpTranslate;

	DWORD temp(0);
	const DWORD size(::GetFileVersionInfoSize(strFile.c_str(), &temp));
	unsigned char* ptr_buffer(new unsigned char[size]);
	if(::GetFileVersionInfo(strFile.c_str(), 0, size, reinterpret_cast<LPVOID>(ptr_buffer)))
	{
		if(::VerQueryValueW(ptr_buffer,L"\\VarFileInfo\\Translation",(LPVOID *) &lpTranslate,&nLen))
		{
			strBlock=Format("\\StringFileInfo\\%04x%04x\\%s",
				lpTranslate->wLanguage,
				lpTranslate->wCodePage,
				strProperty.c_str());
		}
		rc=VerQueryValue(ptr_buffer,strBlock.c_str(), &lpPropertyBuffer,&nLen);
		if (rc!=0 && nLen > 0)
		{
			strncpy(strValue, (char *) lpPropertyBuffer, nLen);
		           //	strValue(nLen);
		}
	}
	else returnValue="no data";
    return returnValue;
}


Edit:
Der Fehler muss in diesem CodeAbschnitt liegen. Beim Kompilieren grieg ich keine Errors, jedoch beim Ausführen:
Unhandled exception at 0x1026fb25 (msvcr90d.dll) in Testclass.exe: 0xC0000005: Access violation writing location 0x00422990.

Der Methodenaufruf Format tut das richtige.
Die Fehlermeldung wird in der Funktion strncpy() ausgelöst.

Code:
rc=VerQueryValue(ptr_buffer,strBlock.c_str(), &lpPropertyBuffer,&nLen);
if (rc!=0 && nLen > 0)
	{
	strncpy(strValue, (char *) lpPropertyBuffer, nLen);
	//strValue(nLen);
	}
 
Zuletzt bearbeitet:
Ich nehme mal an, dass strncpy in Ordnung ist...
da werden deine übergebenen Parameter nicht passen.
Nullpointer, Überlange?
 
danke sheel,

es liegt an den übergabeparamter.
Wenn ich strValue mit der CStringKlasse deklariere, funktioniert es.
wie kann man GetBuffer() und ReleaseBuffer(nLen) CString unabhängig machen?

Wäre echt toll, wenn sich das noch jemand anschauen könnte. So kurz vor dem Ziel :)

Code:
CString strValue
....
strValue.GetBuffer(nLen+1);
strValue.ReleaseBuffer(nLen);
 
Hi.

Wie es aussieht hast du den Zeiger strValue nicht initialisiert:
C++:
char* strValue = 0;
...
rc=VerQueryValue(ptr_buffer,strBlock.c_str(), &lpPropertyBuffer,&nLen);
if (rc!=0 && nLen > 0)
{
    strValue = new char[nLen+1];
    strncpy(strValue, (char *) lpPropertyBuffer, nLen);
}
...
delete[] strValue;
Gruß
 
Zurück