Ich habe eine Versionsressource in meinen Ressourcen in einem C++ - Projekt, das Versionsnummer, Copyright und Build-Details enthält. Gibt es eine einfache Möglichkeit, um diese zur Laufzeit zu erreichen, um meine Hilfe/über Dialog zu füllen, wie ich derzeit separate const Werte dieser Informationen pflege. Im Idealfall sollte die Lösung für Windows Mobile Mobile und frühere Versionen von Visual C++ (6.0 aufwärts) funktionieren.Wie lese ich aus einer Versionsressource in Visual C++
Antwort
Dies ist eine bearbeitete Version meiner ursprünglichen Antwort.
bool GetProductAndVersion(CStringA & strProductName, CStringA & strProductVersion)
{
// get the filename of the executable containing the version resource
TCHAR szFilename[MAX_PATH + 1] = {0};
if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
{
TRACE("GetModuleFileName failed with error %d\n", GetLastError());
return false;
}
// allocate a block of memory for the version info
DWORD dummy;
DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
if (dwSize == 0)
{
TRACE("GetFileVersionInfoSize failed with error %d\n", GetLastError());
return false;
}
std::vector<BYTE> data(dwSize);
// load the version info
if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0]))
{
TRACE("GetFileVersionInfo failed with error %d\n", GetLastError());
return false;
}
// get the name and version strings
LPVOID pvProductName = NULL;
unsigned int iProductNameLen = 0;
LPVOID pvProductVersion = NULL;
unsigned int iProductVersionLen = 0;
// replace "040904e4" with the language ID of your resources
if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductName"), &pvProductName, &iProductNameLen) ||
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
strProductName.SetString((LPCSTR)pvProductName, iProductNameLen);
strProductVersion.SetString((LPCSTR)pvProductVersion, iProductVersionLen);
return true;
}
Wo finden Sie die Sprach-ID? –
@ JeffB Ich würde auf der MSDN-Seite [Language Identifier Constants und Strings] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx) starten . –
Beide Ihre letzten zwei Zeilen gibt mir eine '' void ATL :: CSimpleStringT
So etwas werden Sie rohen Zugriff auf die Ressourcen-Daten geben und Ihnen den Einstieg:
HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(MY_VERSION_ID), RT_VERSION);
DWORD size = ::SizeofResource(NULL, res);
HGLOBAL mem = ::LoadResource(NULL, res);
LPVOID raw_data = ::LockResource(mem);
...
::FreeResource(mem);
Ok, fand ein bisschen mehr googleing die following auf MS-Office. Im Grunde verwendet dieser Ansatz das CFileVersionInfo Objekt, um eine beliebige Datei zu erhalten. Es sollte interessant sein zu sehen, ob es auf der aktuell laufenden .EXE-Datei und auf Windows CE funktioniert.
So etwas könnte man beginnen, vielleicht:
TCHAR moduleName[MAX_PATH+1];
(void)GetModuleFileName(AfxGetInstanceHandle(), moduleName, MAX_PATH);
DWORD dummyZero;
DWORD versionSize = GetFileVersionInfoSize(moduleName, &dummyZero);
if(versionSize == 0)
{
return NULL;
}
void* pVersion = malloc(versionSize);
if(pVersion == NULL)
{
return NULL;
}
if(!GetFileVersionInfo(moduleName, NULL, versionSize, pVersion))
{
free(pVersion);
return NULL;
}
UINT length;
VS_FIXEDFILEINFO* pFixInfo;
VERIFY(VerQueryValue(pVersionInfo, const_cast<LPTSTR>("\\"), (LPVOID*)&pFixInfo, &length));
Vorsicht! Verwenden von FindResource..LockResource ist nicht korrekt. Es funktioniert manchmal (wie in meinem kleinen Demo-Programm) und verursacht manchmal Zugriffsverletzungen (Beispiel: der Produktionscode, für den ich die Demo gemacht habe).
Die VerQueryValue() - Dokumentation besagt, dass Sie stattdessen GetFileVersionInfoSize und GetFileVersionInfo aufrufen sollten. Raymond Chen erklärt, siehe http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx
Um eine Sprache unabhängiges Ergebnis zu Marks Antwort Änderung zu erhalten:
// replace "040904e4" with the language ID of your resources
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
Um
UINT uiVerLen = 0;
VS_FIXEDFILEINFO* pFixedInfo = 0; // pointer to fixed file info structure
// get the fixed file info (language-independent)
if(VerQueryValue(&data[0], TEXT("\\"), (void**)&pFixedInfo, (UINT *)&uiVerLen) == 0)
{
return false;
}
strProductVersion.Format("%u.%u.%u.%u",
HIWORD (pFixedInfo->dwProductVersionMS),
LOWORD (pFixedInfo->dwProductVersionMS),
HIWORD (pFixedInfo->dwProductVersionLS),
LOWORD (pFixedInfo->dwProductVersionLS));
Danke, das ist sehr interessant, großartige Lösung! – ghiboz
Das bekommt andere Informationen von Mark Ransoms Antwort. Die Werte, die Sie abrufen, sind vier Ganzzahlen von der obersten Zeile von PRODUCTVERSION in der Ressourcendatei. Die Antwort von Marks ruft jedoch die Zeichenfolge "ProductVersion" unter dem Block "StringFileInfo" ab. –
Manchmal Zugriffsverletzung, wenn die Verwendung VerQueryValueA
I erhalten. Aber ich habe nie diesen Fehler bei der Verwendung VerQueryValueW
. Ich denke etwas stimmt nicht mit VerQueryValueA
in version.dll. Daher verwende ich VerQueryValueW
statt VerQueryValueA
sogar in Projekten Multi-Byte-Zeichencodierung. Here is my code of ReadVersion
function
Sie sollten beachten, dass '_get_pgmptr()' oder '_get_wpgmptr()' ist besser als 'GetModuleFileName (NULL, szFilename, MAX_PATH)'; erspart Ihnen unnötige Zuweisung und klärt Ihre Absicht. – q12