Versionsprüfung bei verteilbaren Dateien
Aktualisiert: November 2007
Es ist wichtig, dass nur die aktuellste Version einer Datei installiert wird. In fast allen Fällen möchten Sie eine aktuellere Version einer DLL oder Komponente über einer älteren Version installieren und nicht umgekehrt. System-DLLs (z. B. Kernel32.dll, User32.dll, Ole32.dll und ShDocVW.dll) dürfen nicht weiterverteilt werden. Wenn Sie Dateien weiterverteilen müssen, lesen Sie unbedingt die entsprechenden Lizenzverträge, und stellen Sie sicher, dass die Dateien im Hinblick auf entsprechende Betriebssystemversionen und den Installationsort weiterverteilt werden können. In der Regel ist die Versionsprüfung Aufgabe des Setupprogramms.
Wenn Sie ein benutzerdefiniertes Setupprogramm schreiben, muss dieses bei der Installation verteilbarer Dateien die Versionsinformationen manuell prüfen. Dieses Thema enthält ein Beispielprogramm, das eine Prüfung auf Versionsnummern oder, falls eine Datei keine Versionsnummer enthält, auf Timestamps ausführt.
Beispiel
Beschreibung
Im folgenden Beispiel wird eine Methode gezeigt, um zwei dynamische Bibliotheken oder ausführbare Dateien zu überprüfen.
Code
// 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);
}