Проверка версий распространяемых файлов
Обновлен: Ноябрь 2007
Необходимо устанавливать самые последние версии файлов. Почти всегда требуется устанавливать последнюю версию DLL или компонента поверх старой версии, но не наоборот. Системные библиотеки DLL (например, Kernel32.dll, User32.dll, Ole32.dll и ShDocVW.dll) не являются распространяемыми. Если необходимо распространять какие-либо файлы, прочтите соответствующее лицензионное соглашение и убедитесь, что эти файлы можно распространять для соответствующих версий операционных систем и расположения установленного продукта. Как правило, за контроль версий отвечает программа установки.
Если вы создаете собственную программу установки, при установке распространяемых файлов она должна сама проверять номера версий. Этот раздел включает пример программы, которая проверяет номера версий файлов, либо, если номера отсутствуют, — отметки времени.
Пример
Описание
Следующий пример демонстрирует метод проверки версий двух динамических библиотек или исполняемых файлов.
Код
// 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);
}