У меня есть ресурс версии в моих ресурсах в проекте C++, который содержит номер версии, авторские права и данные сборки. Есть ли простой способ получить доступ к этому во время выполнения, чтобы заполнить мой диалог help/about, так как я в настоящее время поддерживаю отдельные значения константы этой информации. В идеале решение должно работать для Windows/CE мобильных и более ранних версий Visual C++ (6.0 вверх).Как я могу прочитать из ресурса версии в Visual C++
ответ
Это сокращенная версия моего первоначального ответа.
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;
}
Где вы находите идентификатор языка? – 2016-03-23 18:56:10
@JeffB Я бы начал на странице MSDN [Константы и строки идентификатора языка] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx) , – 2016-03-23 20:05:37
Что-то, как это даст вам необработанный доступ к данным ресурсам и вы начали:
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);
Хорошо, немного больше googleing нашел following на CodeGuru. В основном этот подход использует объект CFileVersionInfo для доступа к любому файлу. Будет интересно посмотреть, работает ли он в текущем рабочем файле .EXE и в Windows CE.
Нечто подобное могло бы, чтобы вы начали, возможно:
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));
Опасайтесь! Использование функции FindResource..LockResource неверно. Иногда он работает (как это было в моей маленькой демонстрационной программе) и иногда вызывает нарушения доступа (пример: производственный код, который я делал для демонстрации).
В документации VerQueryValue() указано, что вместо этого вы должны вызывать GetFileVersionInfoSize и GetFileVersionInfo. Рэймонд Чен объясняет, см http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx
Чтобы получить независимый от языка результата изменения ответа Марка:
// 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;
}
Для
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));
Иногда я получаю нарушение прав доступа при использовании VerQueryValueA
. Но я никогда не получал эту ошибку при использовании VerQueryValueW
. Я думаю, что-то не так с VerQueryValueA
в версии.dll. Поэтому я использую VerQueryValueW
вместо VerQueryValueA
даже в проектах Многобайтовая кодировка символов. Here is my code of ReadVersion
function
Следует отметить, что использование `_get_pgmptr()` или `_get_wpgmptr()` лучше, чем `GetModuleFileName (NULL, szFilename, MAX_PATH)`; избавляет вас от ненужного распределения и уточняет ваше намерение. – q12 2017-01-08 13:00:18