Introduction
There are many instances where it is necessary to know which version of a DLL you are using. For
instance, the commctrl32.dll that drives the main Windows GUI is notorious for changing with every
incarnation of Internet Explorer. While it is nice to be able to use the new features of the updated
DLL, it is wise to check that the particular version of that DLL is on the machine before you start
using it. This will avoid embarrassing crashes in your programs.
The following class retrieves the DLL versions. It is based on the original code by Eran Yariv,
and has been updated by Kenneth Lea (with help from John Allen Booth so that it will work with Executables as well
Header File
#if !defined(AFX_DLLVERSION_H__88B3F8C1_27F2_11D3_80A3_0090276F9F55__INCLUDED_)
#define AFX_DLLVERSION_H__88B3F8C1_27F2_11D3_80A3_0090276F9F55__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif
#ifndef _DLL_VERSION_H_
#define _DLL_VERSION_H_
#ifndef DLLVERSIONINFO
typedef struct _DllVersionInfo
{
DWORD cbSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformID;
}DLLVERSIONINFO;
#endif
#ifndef DLLGETVERSIONPROC
typedef int (FAR WINAPI *DLLGETVERSIONPROC) (DLLVERSIONINFO *);
#endif
class CDLLVersion
{
typedef enum { WIN_DIR,
SYS_DIR,
CUR_DIR,
NO_DIR}
FileLocationType;
public:
CDLLVersion (LPSTR szDLLFileName) :
m_dwMajor (0),
m_dwMinor (0),
m_dwBuild (0)
{
m_bValid = GetDLLVersion (szDLLFileName, m_dwMajor, m_dwMinor, m_dwBuild);
}
virtual ~CDLLVersion () {};
DWORD GetMajorVersion ()
{
return m_dwMajor;
}
DWORD GetMinorVersion ()
{
return m_dwMinor;
}
DWORD GetBuildNumber ()
{
return m_dwBuild;
}
BOOL IsValid ()
{
return m_bValid;
}
CString GetFullVersion()
{
return m_stFullVersion;
}
private:
char *getVersion(char *fileName);
BOOL GetDLLVersion (LPSTR szDLLFileName,
DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);
BOOL CheckFileVersion (LPSTR szFileName, int FileLoc,
DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);
BOOL ParseVersionString (LPSTR lpVersion,
DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);
BOOL ParseVersionString1 (LPSTR lpVersion,
DWORD &dwMajor, DWORD &dwMinor,
DWORD &dwBuildNumber);
BOOL FixFilePath (char * szFileName, int FileLoc);
DWORD m_dwMajor,
m_dwMinor,
m_dwBuild;
BOOL m_bValid;
CString m_stFullVersion;
};
#endif
#endif
The Version cpp file
#include "stdafx.h"
#include "DLLVersion.h"
#include "Global.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
BOOL CDLLVersion::GetDLLVersion (LPSTR szDLLFileName,
DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber)
{
HINSTANCE hDllInst;
char szFileName [_MAX_PATH];
BOOL bRes = TRUE;
lstrcpy (szFileName, szDLLFileName);
hDllInst = LoadLibrary(TEXT(szFileName));
if(hDllInst)
{
DLLGETVERSIONPROC pDllGetVersion;
pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hDllInst,
TEXT("DllGetVersion"));
if(pDllGetVersion)
{
DLLVERSIONINFO dvi;
ZeroMemory(&dvi, sizeof(dvi));
dvi.cbSize = sizeof(dvi);
HRESULT hr = (*pDllGetVersion)(&dvi);
if(SUCCEEDED(hr))
{
dwMajor = dvi.dwMajorVersion;
dwMinor = dvi.dwMinorVersion;
dwBuildNumber = dvi.dwBuildNumber;
}
else
bRes = FALSE;
}
else
bRes = FALSE;
FreeLibrary(hDllInst);
}
else
bRes = FALSE;
if (!bRes)
{
for(int iDir = WIN_DIR; iDir <= NO_DIR; iDir++)
{
lstrcpy (szFileName, szDLLFileName);
bRes = CheckFileVersion (szFileName, iDir,
dwMajor, dwMinor, dwBuildNumber);
if(bRes)
break;
};
return bRes;
}
else
return TRUE;
}
BOOL CDLLVersion::CheckFileVersion (LPSTR szFileName, int FileLoc,
DWORD &dwMajor, DWORD &dwMinor,
DWORD &dwBuildNumber)
{
LPSTR lpVersion;
DWORD dwVerHnd=0;
FixFilePath (szFileName, FileLoc);
DWORD dwVerInfoSize = GetFileVersionInfoSize (szFileName, &dwVerHnd);
if (!dwVerInfoSize)
return FALSE;
LPSTR lpstrVffInfo = (LPSTR) malloc (dwVerInfoSize);
if (lpstrVffInfo == NULL)
return FALSE;
if (!GetFileVersionInfo(szFileName, dwVerHnd, dwVerInfoSize, lpstrVffInfo))
{
free (lpstrVffInfo);
return FALSE;
}
lpVersion = getVersion(szFileName);
m_stFullVersion = getVersion(szFileName);
BOOL bRes = ParseVersionString (lpVersion, dwMajor, dwMinor, dwBuildNumber);
if(!bRes)
bRes = ParseVersionString1 (lpVersion, dwMajor, dwMinor, dwBuildNumber);
free (lpstrVffInfo);
return bRes;
}
BOOL CDLLVersion::ParseVersionString (LPSTR lpVersion,
DWORD &dwMajor, DWORD &dwMinor,
DWORD &dwBuildNumber)
{
LPSTR token = strtok( lpVersion, TEXT (".") );
if (token == NULL)
return FALSE;
dwMajor = atoi (token);
token = strtok (NULL, TEXT ("."));
if (token == NULL)
return FALSE;
dwMinor = atoi (token);
token = strtok (NULL, TEXT ("."));
if (token == NULL)
return FALSE;
dwBuildNumber = atoi (token);
return TRUE;
}
BOOL CDLLVersion::FixFilePath (char * szFileName, int FileLoc)
{
char szPathStr [_MAX_PATH];
switch (FileLoc)
{
case WIN_DIR:
if (GetWindowsDirectory (szPathStr, _MAX_PATH) == 0)
return FALSE;
break;
case SYS_DIR:
if (GetSystemDirectory (szPathStr, _MAX_PATH) == 0)
return FALSE;
break;
case CUR_DIR:
if (GetCurrentDirectory (_MAX_PATH, szPathStr) == 0)
return FALSE;
break;
case NO_DIR:
lstrcpy (szPathStr,"");
break;
default:
return FALSE;
}
lstrcat (szPathStr, _T("\\"));
lstrcat (szPathStr, szFileName);
lstrcpy (szFileName, szPathStr);
return TRUE;
}
/***************************************************************************
Function: ParseVersionString
Purpose: Parse version information string into 3 different numbers
Input: The version string formatted as "MajorVersion.MinorVersion.BuildNumber"
Reference to Major number
Reference to Minor number
Reference to Build number
Output: TRUE only if successful
Remarks:
****************************************************************************/
BOOL CDLLVersion::ParseVersionString1 (LPSTR lpVersion,
DWORD &dwMajor, DWORD &dwMinor,
DWORD &dwBuildNumber)
{
// Get first token (Major version number)
LPSTR token = strtok( lpVersion, TEXT (",") );
if (token == NULL) // End of string
return FALSE; // String ended prematurely
dwMajor = atoi (token);
token = strtok (NULL, TEXT (",")); // Get second token (Minor version number)
if (token == NULL) // End of string
return FALSE; // String ended prematurely
dwMinor = atoi (token);
token = strtok (NULL, TEXT (",")); // Get third token (Build number)
if (token == NULL) // End of string
return FALSE; // String ended prematurely
dwBuildNumber = atoi (token);
return TRUE;
}
// a static buffer is used to hold the version, calling this function
// a second time will erase previous information.
// long paths may be used for this function.
char *CDLLVersion::getVersion(char *fileName)
{
DWORD vSize;
DWORD vLen,langD;
BOOL retVal;
LPVOID version=NULL;
LPVOID versionInfo=NULL;
static char fileVersion[256];
bool success = true;
vSize = GetFileVersionInfoSize(fileName,&vLen);
if (vSize)
{
versionInfo = malloc(vSize+1);
if (GetFileVersionInfo(fileName,vLen,vSize,versionInfo))
{
sprintf(fileVersion,"\\VarFileInfo\\Translation");
retVal = VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen);
if (retVal && vLen==4)
{
memcpy(&langD,version,4);
sprintf(fileVersion, "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion",
(langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24,
(langD & 0xff0000)>>16);
}
else
sprintf(fileVersion, "\\StringFileInfo\\%04X04B0\\FileVersion",
GetUserDefaultLangID());
retVal = VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen);
if (!retVal) success = false;
}
else
success = false;
}
else
success=false;
if (success)
{
if (vLen<256)
strcpy(fileVersion,(char *)version);
else
{
strncpy(fileVersion,(char *)version,250);
fileVersion[250]=0;
}
if (versionInfo) free(versionInfo);
versionInfo = NULL;
return fileVersion;
}
else
{
if (versionInfo) free(versionInfo);
versionInfo = NULL;
return NULL;
}
}