【问题标题】:Getting application version from within application从应用程序中获取应用程序版本
【发布时间】:2012-09-13 11:30:42
【问题描述】:

有没有一种简单的方法可以在运行时从资源文件中获取应用程序的版本信息?

实际上,我想做的是能够在运行时显示“版本 X.Y.Z”,而无需在某个地方有一个单独的变量,我必须与我的 ProductVersion 和 FileVersion 保持同步。

澄清一下:是的,这是一个标准的 C++ Windows 项目。我知道GetFileVersionInfo 方法,但是为了查询版本信息而不得不从内存中的版本中打开二进制文件似乎很愚蠢-我确定我在这里遗漏了一些明显的东西:-)

【问题讨论】:

    标签: c++ windows winapi versioning


    【解决方案1】:

    如果操作系统是 Windows,请使用 GetFileVersionInfo 和 VerQueryValue 函数。

    【讨论】:

    • 根据我的编辑 - 这将涉及必须打开文件,如果它存在,我想要一个更优雅的解决方案。
    • 每个二进制文件都有版本信息。相比之下,内存中的图像是由几个文件组成的。加载到内存中的 PE 映像没有文件版本。它只包括链接器版本和操作系统版本。
    • 版本信息是 PE 资源的一部分,位于.rsrc 部分,除非标记为可丢弃,否则它会驻留在内存中。版本资源是可本地化的,因此建议使用专门的版本信息 Windows API 来访问它们。
    【解决方案2】:

    我认为没有比打开文件并使用 GetFileVersionInfo 和 VerQueryValue 更简单的方法了。我使用以下代码,以防万一:

    static CString GetProductVersion()
    {
        CString strResult;
    
        char szModPath[ MAX_PATH ];
        szModPath[ 0 ] = '\0';
        GetModuleFileName( NULL, szModPath, sizeof(szModPath) );
        DWORD dwHandle;
        DWORD dwSize = GetFileVersionInfoSize( szModPath, &dwHandle );
    
        if( dwSize > 0 )
        {
            BYTE* pbBuf = static_cast<BYTE*>( alloca( dwSize ) );
            if( GetFileVersionInfo( szModPath, dwHandle, dwSize, pbBuf ) )
            {
                UINT uiSize;
                BYTE* lpb;
                if( VerQueryValue( pbBuf,
                                   "\\VarFileInfo\\Translation",
                                   (void**)&lpb,
                                   &uiSize ) )
                {
                    WORD* lpw = (WORD*)lpb;
                    CString strQuery;
                    strQuery.Format( "\\StringFileInfo\\%04x%04x\\ProductVersion", lpw[ 0 ], lpw[ 1 ] );
                    if( VerQueryValue( pbBuf,
                                       const_cast<LPSTR>( (LPCSTR)strQuery ),
                                       (void**)&lpb,
                                       &uiSize ) && uiSize > 0 )
                    {
                        strResult = (LPCSTR)lpb;
                    }
                }
            }
        }
    
        return strResult;
    }
    

    大卫

    【讨论】:

    • C 风格的演员表?!你是谁,大卫在哪里? ;-) 感谢您的 sn-p
    • 是的,有效的批评。还为使用静态全局函数和 CString 表示歉意。在我的软弱辩护中,这只是一个爱好项目!
    【解决方案3】:

    唯一官方支持的方法是使用GetFileVersionInfo() 和VerQueryValue()。但是,正如您所注意到的,GetFileVersionInfo() 要求您传入可执行文件的文件名。 There is a reason for this。虽然使用GetModuleFileName() 获取正在运行的进程的文件名很简单,但这并不是最有效的选择,尤其是当可执行文件从远程共享运行时,如果可执行文件已在进程开始运行后的硬盘。

    您可以访问已经在内存中运行的进程的版本信息,通过调用FindResource()来定位进程的RT_VERSION资源,然后使用LoadResource()和LockResource()获取指向其数据的指针。然后将该指针作为VerQueryValue() 的pBlock 参数传递是很诱人的,但要小心,因为这样做can crash your code!如果您直接访问RT_VERSION 资源,那么您最好不要使用VerQueryValue()。 format of the RT_VERSION resource 有文档记录,可以手动解析原始数据,难度不大。

    【讨论】:

      【解决方案4】:

      如前所述,没有简单的方法。

      您可以找到 here 一个很好的工作示例(无 ATL)。

      【讨论】:

        猜你喜欢
        • 2011-03-21
        • 2014-01-29
        • 1970-01-01
        • 1970-01-01
        • 2018-01-12
        • 1970-01-01
        • 1970-01-01
        • 2011-09-25
        • 1970-01-01
        相关资源
        最近更新 更多