Pregunta

Tengo un recurso de versión en mis recursos en un proyecto C ++ que contiene número de versión, derechos de autor y detalles de compilación. ¿Hay una manera fácil de acceder a esto en tiempo de ejecución para completar mi cuadro de diálogo ayuda / acerca de ya que actualmente mantengo valores constantes separados de esta información. Idealmente, la solución debería funcionar para Windows / CE mobile y versiones anteriores de Visual C ++ (6.0 en adelante).

¿Fue útil?

Solución

Esta es una versión editada de mi respuesta original.

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

Otros consejos

Para obtener un resultado independiente del idioma para el cambio de respuesta 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;
}

Para

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

Algo así podría ayudarlo a comenzar, tal vez:

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

Algo como esto le dará acceso sin procesar a los datos de recursos y lo ayudará a comenzar:

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

¡Cuidado! Usar FindResource..LockResource no es correcto. A veces funcionará (como lo hizo en mi pequeño programa de demostración) y a veces causará violaciones de acceso (por ejemplo: el código de producción para el que estaba haciendo la demostración).

La documentación de VerQueryValue () establece que debe llamar a GetFileVersionInfoSize y GetFileVersionInfo en su lugar. Raymond Chen explica, consulte http://blogs.msdn.com /oldnewthing/archive/2006/12/26/1365215.aspx

Ok, un poco más googleing encontró el siguiente en CodeGuru. Básicamente, este enfoque utiliza el objeto CFileVersionInfo para acceder a cualquier archivo dado. Debería ser interesante ver si funciona en el archivo .EXE actualmente en ejecución y en Windows CE.

A veces recibo Infracción de acceso cuando uso VerQueryValueA . Pero nunca recibí este error cuando uso VerQueryValueW . Creo que algo anda mal con VerQueryValueA en version.dll. Por lo tanto, uso VerQueryValueW en lugar de VerQueryValueA incluso en proyectos de codificación de caracteres de varios bytes. Aquí está mi código de la función ReadVersion

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top