再配布可能なファイルのバージョンの確認

更新 : 2007 年 11 月

最新バージョンのファイルだけをインストールしてください。ほとんどすべての場合、新しいバージョンの DLL を古いバージョンの上にインストールし、その逆は行いません。システム DLL (Kernel32.dll、User32.dll、Ole32.dll、ShDocVW.dll など) は再配布しないでください。再配布する必要がある場合は、必ず使用許諾契約書を読み、対応するオペレーティング システムのバージョンおよびインストール場所へのファイルの再配布が可能であることを確認してください。通常、バージョン チェックはセットアップ プログラムが行います。

カスタム セットアップ プログラムを記述した場合は、再配布可能なファイルのインストール時に手動でバージョン情報をチェックする必要があります。次のサンプル プログラムでは、バージョン番号をチェックします。バージョン番号がファイルにない場合は、タイムスタンプをチェックします。

サンプル

説明

2 つのダイナミック ライブラリまたは実行可能プログラム間でバージョン番号をチェックする例を次に示します。

コード

// 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++)