Verifica della versione dei file ridistribuibili
Aggiornamento: novembre 2007
È importante installare solo la versione più recente di un file. In genere, si desidera installare una versione più recente di una DLL o un componente in sostituzione di una versione precedente, ma non viceversa. Le DLL di sistema, ad esempio Kernel32.dll, User32.dll, Ole32.dll, ShDocVW.dll e così via, non devono essere ridistribuite. Se è necessario ridistribuire alcuni file, leggere i contratti di licenza corrispondenti e assicurarsi che sia consentita la ridistribuzione dei file per le versioni di sistema operativo e la posizione di installazione corrispondenti. La verifica delle versioni viene solitamente eseguita dal programma di installazione.
Se si scrive un programma di installazione personalizzato, le informazioni sulla versione dovranno essere verificate manualmente durante l'installazione dei file ridistribuibili.In questo argomento è incluso un programma di esempio, che consente la verifica dei numeri di versione o, nel caso in cui i numeri di versione non siano presenti in un file, dei timestamp.
Esempio
Descrizione
Nell'esempio riportato di seguito viene illustrato un metodo per il controllo tra due eseguibili o librerie dinamiche.
Codice
// checkversion.cpp
// compile with: /link version.lib
#include <windows.h>
#include <stdio.h>
void EmitErrorMsg (HRESULT hr);
HRESULT GetFileVersion (char *filename, VS_FIXEDFILEINFO *vsf);
HRESULT GetFileDate (char *filename, FILETIME *pft);
HRESULT LastError();
int WhichIsNewer (char *fname1, char *fname2);
void printtime (FILETIME *t)
{
FILETIME lft;
FILETIME *ft = &lft;
FileTimeToLocalFileTime(t,ft);
printf_s("%08x %08x",ft->dwHighDateTime,ft->dwLowDateTime);
{
SYSTEMTIME stCreate;
BOOL bret = FileTimeToSystemTime(ft,&stCreate);
printf_s(" %02d/%02d/%d %02d:%02d:%02d\n",
stCreate.wMonth, stCreate.wDay, stCreate.wYear,
stCreate.wHour, stCreate.wMinute,
stCreate.wSecond);
}
}
int main(int argc, char* argv[])
{
printf_s("usage: checkversion file1 file2\n"
"\tReports which file is newer, first by checking "
"the file version in "
"\tthe version resource, then by checking the date\n\n" );
if (argc != 3)
return 1;
int newer = WhichIsNewer(argv[1],argv[2]);
switch(newer)
{
case 1:
case 2:
printf_s("%s is newer\n",argv[newer]);
break;
case 3:
printf_s("they are the same version\n");
break;
case 0:
default:
printf_s("there was an error\n");
break;
}
return !newer;
}
int WhichIsNewer (char *fname1, char *fname2)
{
// 1 if argv[1] is newer
// 2 if argv[2] is newer
// 3 if they are the same version
// 0 if there is an error
int ndxNewerFile;
HRESULT ret;
VS_FIXEDFILEINFO vsf1,vsf2;
if ( SUCCEEDED((ret=GetFileVersion(fname1,&vsf1))) &&
SUCCEEDED((ret=GetFileVersion(fname2,&vsf2))))
{
// both files have a file version resource
// compare by file version resource
if (vsf1.dwFileVersionMS > vsf2.dwFileVersionMS)
{
ndxNewerFile = 1;
}
else
if (vsf1.dwFileVersionMS < vsf2.dwFileVersionMS)
{
ndxNewerFile = 2;
}
else {
// if (vsf1.dwFileVersionMS == vsf2.dwFileVersionMS)
if (vsf1.dwFileVersionLS > vsf2.dwFileVersionLS) {
ndxNewerFile = 1;
}
else
if (vsf1.dwFileVersionLS < vsf2.dwFileVersionLS) {
ndxNewerFile = 2;
}
else
{
// if (vsf1.dwFileVersionLS == vsf2.dwFileVersionLS)
ndxNewerFile = 3;
}
}
}
else
{
// compare by date
FILETIME ft1,ft2;
if (SUCCEEDED((ret=GetFileDate(fname1,&ft1))) &&
SUCCEEDED((ret=GetFileDate(fname2,&ft2))))
{
LONG x = CompareFileTime(&ft1,&ft2);
if (x == -1)
ndxNewerFile = 2;
else
if (x == 0)
ndxNewerFile = 3;
else
if (x == 1)
ndxNewerFile = 1;
else
{
EmitErrorMsg(E_FAIL);
return 0;
}
}
else
{
EmitErrorMsg(ret);
return 0;
}
}
return ndxNewerFile;
}
HRESULT GetFileDate (char *filename, FILETIME *pft)
{
// we are interested only in the create time
// this is the equiv of "modified time" in the
// Windows Explorer properties dialog
FILETIME ct,lat;
HANDLE hFile = CreateFile(filename, GENERIC_READ,FILE_SHARE_READ |
FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);
if (hFile == INVALID_HANDLE_VALUE)
return LastError();
BOOL bret = GetFileTime(hFile,&ct,&lat,pft);
if (bret == 0)
return LastError();
return S_OK;
}
// This function gets the file version info structure
HRESULT GetFileVersion (char *filename, VS_FIXEDFILEINFO *pvsf)
{
DWORD dwHandle;
DWORD cchver = GetFileVersionInfoSize(filename,&dwHandle);
if (cchver == 0)
return LastError();
char* pver = new char[cchver];
BOOL bret = GetFileVersionInfo(filename,dwHandle,cchver,pver);
if (!bret)
return LastError();
UINT uLen;
void *pbuf;
bret = VerQueryValue(pver,"\\",&pbuf,&uLen);
if (!bret)
return LastError();
memcpy(pvsf,pbuf,sizeof(VS_FIXEDFILEINFO));
delete[] pver;
return S_OK;
}
HRESULT LastError ()
{
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr))
return E_FAIL;
return hr;
}
// This little function emits an error message
// based on WIN32 error messages
void EmitErrorMsg (HRESULT hr)
{
char szMsg[1024];
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
szMsg,
1024,
NULL
);
printf_s("%s\n",szMsg);
}