如何以编程方式获取DLL或EXE文件的版本?


74

我需要使用C或C ++中的Win32本机API获取DLL或EXE文件的产品版本和文件版本。我不是在寻找Windows版本,而是在DLL文件上单击鼠标右键,选择“属性”,然后查看“详细信息”选项卡所看到的版本号。这通常是一个四部分的虚线版本号xxxx


您使用哪种语言?
2009年


7
是否只需要Win32 API调用都没关系。任何支持调用系统DLL的语言都应该可以。
crashmstr

编辑以澄清这与C / C ++有关。
JSBձոգչ09年

Answers:


109

您将使用GetFileVersionInfo API。

请参阅MSDN站点上的使用版本信息

样品:

DWORD  verHandle = 0;
UINT   size      = 0;
LPBYTE lpBuffer  = NULL;
DWORD  verSize   = GetFileVersionInfoSize( szVersionFile, &verHandle);

if (verSize != NULL)
{
    LPSTR verData = new char[verSize];

    if (GetFileVersionInfo( szVersionFile, verHandle, verSize, verData))
    {
        if (VerQueryValue(verData,"\\",(VOID FAR* FAR*)&lpBuffer,&size))
        {
            if (size)
            {
                VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
                if (verInfo->dwSignature == 0xfeef04bd)
                {

                    // Doesn't matter if you are on 32 bit or 64 bit,
                    // DWORD is always 32 bits, so first two revision numbers
                    // come from dwFileVersionMS, last two come from dwFileVersionLS
                    TRACE( "File Version: %d.%d.%d.%d\n",
                    ( verInfo->dwFileVersionMS >> 16 ) & 0xffff,
                    ( verInfo->dwFileVersionMS >>  0 ) & 0xffff,
                    ( verInfo->dwFileVersionLS >> 16 ) & 0xffff,
                    ( verInfo->dwFileVersionLS >>  0 ) & 0xffff
                    );
                }
            }
        }
    }
    delete[] verData;
}

1
int revision = HIWORD(verInfo->dwProductVersionLS); int build = LOWORD(verInfo->dwProductVersionLS);
IgorJerosimić13年

6
我知道已经有一段时间了,但是对于像我这样的新手,这就是您获取.exe文件名的方式:TCHAR szVersionFile[MAX_PATH]; GetModuleFileName(NULL, szVersionFile, MAX_PATH );
BurninatorDor 2014年

1
@BurninatorDor不要称自己为新手。到目前为止,我已经在MFC中编程了6年,这对我有所帮助。
尼尔2014年

2
编辑了此答案,因为它错误地计算了版本号。来自dwProductVersionMS的MSDN文档:“文件二进制版本号的最高32位。此成员与dwFileVersionLS一起使用,以形成用于数字比较的64位值。” ,因此您可以同时使用它们来计算版本号。前两个(主要/次要)在versionMS中,后两个(修订/内部版本)在versionLS中。不管您是32/64位,DWORD始终是32位。
mgrandi 2014年

1
NULL不应与DWORDs配合使用(0取而代之的是正确的)
MM

20

所有这些解决方案均无法正常运行(在我的系统上)。我发现版本号的四个部分中的每个部分都保存为16位值。

前两个数字保存在32位DWORD dwFileVersionMS中,后两个数字保存在dwFileVersionLS中。所以我在输出部分编辑了您的代码,如下所示:

    TRACE( "File Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwFileVersionMS >> 16 ) & 0xffff,
        ( pFileInfo->dwFileVersionMS >>  0 ) & 0xffff,
        ( pFileInfo->dwFileVersionLS >> 16 ) & 0xffff,
        ( pFileInfo->dwFileVersionLS >>  0 ) & 0xffff
        );

而且效果很好。输出的格式类似于我的系统:

主要,次要,修订版本


19

您可以使用版本信息API获得此信息。这是一个示例:

void PrintFileVersion( TCHAR *pszFilePath )
{
    DWORD               dwSize              = 0;
    BYTE                *pbVersionInfo      = NULL;
    VS_FIXEDFILEINFO    *pFileInfo          = NULL;
    UINT                puLenFileInfo       = 0;

    // Get the version information for the file requested
    dwSize = GetFileVersionInfoSize( pszFilePath, NULL );
    if ( dwSize == 0 )
    {
        printf( "Error in GetFileVersionInfoSize: %d\n", GetLastError() );
        return;
    }

    pbVersionInfo = new BYTE[ dwSize ];

    if ( !GetFileVersionInfo( pszFilePath, 0, dwSize, pbVersionInfo ) )
    {
        printf( "Error in GetFileVersionInfo: %d\n", GetLastError() );
        delete[] pbVersionInfo;
        return;
    }

    if ( !VerQueryValue( pbVersionInfo, TEXT("\\"), (LPVOID*) &pFileInfo, &puLenFileInfo ) )
    {
        printf( "Error in VerQueryValue: %d\n", GetLastError() );
        delete[] pbVersionInfo;
        return;
    }

    // pFileInfo->dwFileVersionMS is usually zero. However, you should check
    // this if your version numbers seem to be wrong

    printf( "File Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwFileVersionLS >> 24 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >> 16 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >>  8 ) & 0xff,
        ( pFileInfo->dwFileVersionLS >>  0 ) & 0xff
        );

    // pFileInfo->dwProductVersionMS is usually zero. However, you should check
    // this if your version numbers seem to be wrong.

    printf( "Product Version: %d.%d.%d.%d\n",
        ( pFileInfo->dwProductVersionLS >> 24 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >> 16 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >>  8 ) & 0xff,
        ( pFileInfo->dwProductVersionLS >>  0 ) & 0xff
        );
}

2
我认为这是错误的。对于文件版本1.0.0.1,此功能给我“ 0.0.0.1”。我以@Vasya的答案告终
liorda


6

此代码正确显示文件版本号。

( pFileInfo->dwFileVersionMS >> 16 ) & 0xff,
( pFileInfo->dwFileVersionMS >> 0 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  16 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  0 ) & 0xff);

4
您能否提供此答案的背景信息?这似乎是不完整的。如果它是对另一个答案的更正,请在其上留下评论,或编辑该答案,它将得到经验更多的用户的认可。
Deanna 2012年

1
如果版本包含大于255的任何组件,例如6.1.3709.2,则这绝对不能正常工作。这四个组件是16位数字,而不是8位。
Spike0xff '16

这是不正确的。版本的各个部分均为16位值。代码应为(pFileInfo-> dwFileVersionMS >> 16)&0xffff,(pFileInfo-> dwFileVersionMS >> 0)&0xffff,(pFileInfo-> dwFileVersionLS >> 16)&0xffff,(pFileInfo-> dwFileVersionLS >> 0)&0xffff 0xffff);
DaveCleland'4

由于很久以前!但我可以分享解决方案。然后,我拒绝从内核驱动程序接收有关可执行文件的信息。然后,我将此功能转移到服务中。驾驶员传输了有关该过程开始的信息,并期望该服务提供解决方案
Vasya


-2

由于没有答案提到它...我发现您必须根据在32位或64位系统上运行来进行不同的计算。这就是为什么您会发现此问题中的某些答案对您有用,而其他答案则没有。

这是我使用的示例实现:

if(IsWow64())
{
        // 64 bit build
        major =     (verInfo->dwProductVersionMS >> 16) & 0xffff;
        minor =     (verInfo->dwProductVersionMS >>  0) & 0xffff;
        revision =  (verInfo->dwProductVersionLS >> 16) & 0xffff;
        build =     (verInfo->dwProductVersionLS >>  0) & 0xffff;
} 
else
{
        // 32 bit build
        major =     HIWORD(verInfo->dwProductVersionMS);
        minor =     LOWORD(verInfo->dwProductVersionMS);
        revision =  HIWORD(verInfo->dwProductVersionLS);
        build =     LOWORD(verInfo->dwProductVersionLS);
}

并执行IsWow64(不是我的):

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            // Handle error...
        }
    }
    return bIsWow64;
}

您能否提供这两个条件不同的情况?所有值都是固定长度DWORDs,可以分为两个WORDs。您的64位条件也似乎每个值截断为255,而不是32767
迪安娜

您的代码是错误的。用0xFF进行AND操作会破坏版本号。某些应用程序的版本号例如为“ 2.32.1.1300”。您的代码将给出错误的结果。正确的是AND与0xFFFF,其结果与使用LOWORD / HIWORD相同。该帖子应该被否决,因为它绝对是错误的。
Elmue'3

或者,您可以建议编辑@Elmue -如果单击edit该帖子,则应该能够创建建议的更改,然后由主持人批准/拒绝。
kayleeFrye_onDeck

5
为什么对32位和64位需要不同的计算?DWORD在32位和64位版本上,版本号/产品号都是固定的32位值。在64位版本中,HIWORD()andLOWORD()宏会将DWORDs零扩展到64位,DWORD_PTR然后再对它们进行位移位,但是最终结果将是相同的值。此外,IsWow64()无论如何都不会检测到64位版本。IsWow64Process()仅对于在WOW64内部运行的32位版本返回TRUE,因此它仍然是32位版本。要区分32位和64位版本,您需要使用#if(n)def _WIN64
雷米·勒博

正如@RemyLebeau所说,值的大小在32位和64位之间不变化。因此,您从任一计算中都将获得相同的结果。
DaveCleland '04
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.