Freigeben über


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);
}

Siehe auch

Weitere Ressourcen

Bereitstellung (C++)