2008-11-25 5 views
30

У меня есть ресурс версии в моих ресурсах в проекте C++, который содержит номер версии, авторские права и данные сборки. Есть ли простой способ получить доступ к этому во время выполнения, чтобы заполнить мой диалог help/about, так как я в настоящее время поддерживаю отдельные значения константы этой информации. В идеале решение должно работать для Windows/CE мобильных и более ранних версий Visual C++ (6.0 вверх).Как я могу прочитать из ресурса версии в Visual C++

+0

Следует отметить, что использование `_get_pgmptr()` или `_get_wpgmptr()` лучше, чем `GetModuleFileName (NULL, szFilename, MAX_PATH)`; избавляет вас от ненужного распределения и уточняет ваше намерение. – q12 2017-01-08 13:00:18

ответ

30

Это сокращенная версия моего первоначального ответа.

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; 
} 
+0

Где вы находите идентификатор языка? – 2016-03-23 18:56:10

+0

@JeffB Я бы начал на странице MSDN [Константы и строки идентификатора языка] (https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693 (v = vs.85) .aspx) , – 2016-03-23 20:05:37

5

Что-то, как это даст вам необработанный доступ к данным ресурсам и вы начали:

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); 
0

Хорошо, немного больше googleing нашел following на CodeGuru. В основном этот подход использует объект CFileVersionInfo для доступа к любому файлу. Будет интересно посмотреть, работает ли он в текущем рабочем файле .EXE и в Windows CE.

7

Нечто подобное могло бы, чтобы вы начали, возможно:

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)); 
4

Опасайтесь! Использование функции FindResource..LockResource неверно. Иногда он работает (как это было в моей маленькой демонстрационной программе) и иногда вызывает нарушения доступа (пример: производственный код, который я делал для демонстрации).

В документации VerQueryValue() указано, что вместо этого вы должны вызывать GetFileVersionInfoSize и GetFileVersionInfo. Рэймонд Чен объясняет, см http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx

13

Чтобы получить независимый от языка результата изменения ответа Марка:

// 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)); 
0

Иногда я получаю нарушение прав доступа при использовании VerQueryValueA. Но я никогда не получал эту ошибку при использовании VerQueryValueW. Я думаю, что-то не так с VerQueryValueA в версии.dll. Поэтому я использую VerQueryValueW вместо VerQueryValueA даже в проектах Многобайтовая кодировка символов. Here is my code of ReadVersion function