재배포 가능한 파일의 버전 확인

업데이트: 2007년 11월

항상 최신 버전의 파일만 설치되도록 하는 것이 중요합니다. 거의 모든 경우 새 버전의 DLL이나 구성 요소 위에 이전 버전을 설치하는 것이 아니라 이전 버전의 DLL이나 구성 요소 위에 새 버전을 설치해야 합니다. Kernel32.dll, User32.dll, Ole32.dll, ShDocVW.dll 등과 같은 시스템 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);
}

참고 항목

기타 리소스

배포(C++)