84

I need to get the product version and file version for a DLL or EXE file using Win32 native APIs in C or C++. I'm not looking for the Windows version, but the version numbers that you see by right-clicking on a DLL file, selecting "Properties", then looking at the "Details" tab. This is usually a four-part dotted version number x.x.x.x.

Cœur
  • 37,241
  • 25
  • 195
  • 267
JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169

6 Answers6

114

You would use the GetFileVersionInfo API.

See Using Version Information on the MSDN site.

Sample:

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;
}
crashmstr
  • 28,043
  • 9
  • 61
  • 79
  • 2
    `int revision = HIWORD(verInfo->dwProductVersionLS); int build = LOWORD(verInfo->dwProductVersionLS);` – Igor Jerosimić Dec 02 '13 at 23:49
  • 8
    I know it has been a while, but for newbies like me this is how you get the .exe filename: `TCHAR szVersionFile[MAX_PATH]; GetModuleFileName(NULL, szVersionFile, MAX_PATH );` – BurninatorDor Sep 05 '14 at 18:36
  • 1
    @BurninatorDor Don't call yourself a newbie. I've been programming in MFC for 6 years thus far, and this helped me. – Neil Sep 11 '14 at 09:33
  • 2
    edited this answer because it was calculating the version numbers wrong. From the MSDN docs for dwProductVersionMS: "The most significant 32 bits of the file's binary version number. This member is used with dwFileVersionLS to form a 64-bit value used for numeric comparisons." , so you use both of them to calculate the version number. First two (major / minor) are in versionMS and last two (revision / build) are in versionLS. It doesn't matter if you are in 32/64 bit, DWORD is always 32 bits. – mgrandi Nov 12 '14 at 00:28
  • Make sure to link to libversion.a for MingW. See here for copy-pastable example: http://pastebin.com/sYZCVpfw – Aralox Sep 26 '15 at 02:50
  • 1
    `NULL` should not be used with `DWORD`s (`0` would be correct instead) – M.M Mar 10 '17 at 09:32
  • Have to add version.lib to additional linker dependences. Referencing Mincore.lib as official docs suggest didn't work for me. – Aleksandr May 04 '18 at 05:48
  • How to get file version for MSI files, GetFileVersionInfoSize giving error 1812 – user3664223 Feb 18 '22 at 06:50
  • @user3664223 It is possible that a MSI file may not have that information block. – crashmstr Feb 18 '22 at 15:30
22

All these solutions did not work properly (with my system). I found out that each of the four parts of the version number are saved as a 16-bit value.

The first two numbers are saved in the 32-bit DWORD dwFileVersionMS, and the second two in dwFileVersionLS. So I edited your code at the output section like this:

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

And it works perfectly. The output is formatted like on my system:

major.minor.build.revision

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dave Chandler
  • 651
  • 6
  • 17
20

You get this information using the version information APIs. Here is a sample:

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
        );
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
6

Found these articles...sorry, but I don't have direct experience with how to do this using native APIs, so I deferred to an Internet search:

Hope these help!

Steve J
  • 667
  • 6
  • 10
5

This code shows the file version numbers correctly.

( pFileInfo->dwFileVersionMS >> 16 ) & 0xff,
( pFileInfo->dwFileVersionMS >> 0 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  16 ) & 0xff,
( pFileInfo->dwFileVersionLS >>  0 ) & 0xff);
Nathan
  • 8,093
  • 8
  • 50
  • 76
Vasya
  • 103
  • 1
  • 4
  • 4
    Can you provide some context to this answer? It seems to be incomplete. If it was a correction to another answer, please leave a comment on it, or edit that answer and it will be approved by a more experianced user. – Deanna Oct 16 '12 at 08:00
  • 1
    this will definitely _not_ work correctly, if the version includes any component greater than 255, e.g. 6.1.3709.2 The four components are 16-bit numbers, not 8-bit. – Spike0xff Nov 23 '16 at 02:39
  • This is not correct. The individual parts of the versions are 16-bit values. The code should be ( pFileInfo->dwFileVersionMS >> 16 ) & 0xffff, ( pFileInfo->dwFileVersionMS >> 0 ) & 0xffff, ( pFileInfo->dwFileVersionLS >> 16 ) & 0xffff, ( pFileInfo->dwFileVersionLS >> 0 ) & 0xffff); – DaveCleland Apr 11 '20 at 16:56
  • As it was a long time ago !!! But I can share the solution. I then refused to receive information about executable files from the kernel driver. I then transferred this function to the service. The driver transmitted information about the start of the process and expected a resolution from the service – Vasya Apr 12 '20 at 19:44
4

The easiest way is to use the GetFileVersionInfoEx or GetFileVersionInfo API functions.

You can also do it from within your application resources as explained here.

Dani van der Meer
  • 6,169
  • 3
  • 26
  • 45