2008-11-25 14 views
30

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++

+0

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

Répondre

30

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

Où trouvez-vous l'identifiant de la langue? –

+0

@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) . –

+0

Les deux dernières lignes me donnent un '' void ATL :: CSimpleStringT :: SetString (const char *, int) ': impossible de convertir l'argument 1 de' LPCTSTR 'en' const char * '. '. J'ai '#include ' –

5

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

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.

7

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

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

13

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

merci, c'est très intéressant, excellente solution! – ghiboz

+0

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". –

0

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