J'ai une ressource de version dans mes ressources dans un projet C++ qui contient le numéro de version, les droits d'auteur et les détails de construction. Existe-t-il un moyen facile d'accéder à cela au moment de l'exécution pour remplir mon aide/sur le dialogue comme je suis en train de maintenir les valeurs const séparées de cette information. Idéalement, la solution devrait fonctionner pour Windows/CE mobile et les versions antérieures de Visual C++ (6.0 vers le haut).Comment lire à partir d'une ressource de version dans Visual C++
Répondre
Ceci est une version éditée de ma première réponse.
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;
}
Où trouvez-vous l'identifiant de la langue? –
@JeffB Je commencerais à la page MSDN [Constantes et chaînes d'identificateurs de langue] (https://msdn.microsoft.com/fr-fr/library/windows/desktop/dd318693 (v = vs.85) .aspx) . –
Les deux dernières lignes me donnent un '' void ATL :: CSimpleStringT
Quelque chose comme cela vous donnera un accès brut aux données de ressources et vous aider à démarrer:
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, un peu plus googleing a trouvé le following sur CodeGuru. Fondamentalement, cette approche utilise l'objet CFileVersionInfo pour obtenir un fichier donné. Il devrait être intéressant de voir si cela fonctionne sur le fichier .EXE en cours d'exécution et sur Windows CE.
Quelque chose comme peut vous aider à démarrer, peut-être:
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));
Attention! L'utilisation de FindResource..LockResource n'est pas correcte. Cela fonctionnera parfois (comme dans mon petit programme de démonstration) et occasionnera parfois des violations d'accès (exemple: le code de production pour lequel je faisais la démo).
La documentation VerQueryValue() indique que vous devez appeler GetFileVersionInfoSize et GetFileVersionInfo à la place. Raymond Chen explique, voir http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx
Pour obtenir une langue résultat indépendant au changement de réponse de Mark:
// 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;
}
Pour
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));
merci, c'est très intéressant, excellente solution! – ghiboz
Cela obtient des informations différentes de la réponse de Mark Ransom. Les valeurs que vous récupérez sont quatre entiers de la ligne de niveau supérieur PRODUCTVERSION dans le fichier de ressources; Cependant, la réponse de Marks récupère la chaîne "ProductVersion" dans le bloc "StringFileInfo". –
Parfois, je reçois Violation d'accès lors de l'utilisation VerQueryValueA
. Mais je n'ai jamais eu cette erreur lors de l'utilisation VerQueryValueW
. Je pense que quelque chose ne va pas avec VerQueryValueA
dans version.dll. Par conséquent, j'utilise VerQueryValueW
au lieu de VerQueryValueA
même dans les projets de codage de caractères multi-octets. Here is my code of ReadVersion
function
Vous devriez noter qu'utiliser '_get_pgmptr()' ou '_get_wpgmptr()' est meilleur que 'GetModuleFileName (NULL, szFilename, MAX_PATH)'; vous évite des affectations inutiles et clarifie votre intention. – q12