ホーム >プログラム >Delphi 6 ローテクTips >必要なTWindowsMediaPlayerのバージョン判定

必要なバージョンのTWindowsMediaPlayerがインストールされているかを確認しようというページ。



TWindowsMediaPlayerはVer 9以降がOSにインストールされていないとプログラムに取り込んで使うことはできません。
Ver 9以降がインストールされているOSでTWindowsMediaPlayerを取り込みコンパイルしたプログラムを、Ver 9以降がインストールされていないOSで動かそうとすると起動時にエラーが起きプログラムが異常終了してしまいます。
最近のOS(XPのSP3にはVer 9がインストールされていました)ではVer 9以降がインストール済みなので問題になることはありませんが、2000や古いXPでは問題になり得ます。

ということでTWindowsMediaPlayerのversionInfoプロパティに頼らずTWindowsMediaPlayerのバージョンを知る方法を探り、起動時に必要なバージョンのTWindowsMediaPlayerがあるか判定しましょうということです。


interface

function gfnbAppReadyWMP(iVer: Integer; sTitle: String): Boolean;


implementation
uses
  Forms,
  Windows,
  SysUtils;

//------------------------------------------------------------------------------
function gfnsSystem32DirGet: WideString;
//System32ディレクトリを返す
var
  li_Size: UINT;
  lp_Buff: PWideChar;
begin
  Result := '';
  li_Size := GetSystemDirectoryW(nil, 0);
  if (li_Size > 0) then begin
    lp_Buff := AllocMem(li_Size * 2);
    try
      li_Size := GetSystemDirectoryW(lp_Buff, li_Size);
      if (li_Size > 0) then begin
        Result := WideString(lp_Buff);
      end;
    finally
      FreeMem(lp_Buff);
    end;
  end;
end;


function gfnsFileVersionGet(sFile: WideString): WideString;
//ファイルのバージョン情報を返す
//http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=13#0226.txt
type
  TLangAndCodePage = record
    iLanguage: WORD;
    iCodePage: WORD;
  end;
  PLangAndCodePage = ^TLangAndCodePage;
var
  li_Size, li_Reserved, li_Len: DWORD;
  lp_Buff, lp_Dat: Pointer;
  lp_LangPage: PLangAndCodePage;
  ls_FileInfo: WideString;
begin
  Result := '';

  // 必要なバッファのサイズを取得
  li_Size := GetFileVersionInfoSizeW(PWideChar(sFile), li_Reserved);
  if (li_Size > 0) then begin
    //メモリ確保
    lp_Buff := AllocMem((li_Size +1) * 2);
    try
      if (GetFileVersionInfoW(PWideChar(sFile), 0, li_Size, lp_Buff)) then begin
        //変数情報ブロック内の変換テーブルを指定
        if (VerQueryValueW(lp_Buff, '\VarFileInfo\Translation', Pointer(lp_LangPage), li_Len) and (li_Len > 0)) then begin
          //'\StringFileInfo\040904B0\'というような文字列
          ls_FileInfo := WideString(Format('\StringFileInfo\%.4x%.4x\', [lp_LangPage^.iLanguage, lp_LangPage^.iCodePage]));

          //ファイルバージョン
          if (VerQueryValueW(lp_Buff, PWideChar(ls_FileInfo + 'FileVersion'), lp_Dat, li_Len) and (li_Len > 0)) then begin
            Result := WideString(PWideChar(lp_Dat));
          end;
        end;
      end;
    finally
      // 解放
      FreeMem(lp_Buff);
    end;
  end;
end;

//------------------------------------------------------------------------------
function gfnbAppReadyWMP(iVer: Integer; sTitle: String): Boolean;
//WindowsMediaPlayerのiVer以上がインストールされていればTrueを返す。
//そうでなければエラーメッセージを出しFalseを返す。
const
  lcs_WMPDLL = 'wmp.dll';
var
  li_Num, li_Code: Integer;
  ls_Wmpdll, ls_Ver: WideString;
begin
  Result := True;

  ls_Wmpdll := gfnsSystem32DirGet + '\' + lcs_WMPDLL;
  if not(FileExists(ls_Wmpdll)) then begin
    Application.MessageBox(PChar(Format('システムに必要なコンポーネントがインストールされていません。'#13'WindowsMediaPlayerのVer %d 以上がインストールされている必要があります', [iVer])), PChar(sTitle), MB_OK);
    Result := False;
  end else begin
    ls_Ver := gfnsFileVersionGet(ls_Wmpdll);
    Val(ls_Ver, li_Num, li_Code);
    if (li_Num < iVer) then begin
      Application.MessageBox(PChar(Format('システムにWindowsMediaPlayerのVer %d 以上がインストールされている必要があります'#13'現在インストールされているWindowsMediaPlayerのバージョンは %s です', [iVer, ls_Ver])), PChar(sTitle), MB_OK);
      Result := False;
    end;
  end;
end;

要はTWindowsMediaPlayerがインストールされていればシステムディレクトリにwmp.dllというファイルが存在するはずなので、そのファイルがあるかどうか、あればそのバージョン情報を取得して比較するというだけのことです。

システムディレクトリはGetSystemDirectoryW APIを使って取得します。
(GetSystemDirectoryWではなくGetSystemDirectoryでも良いのですが、一応念のため)

ファイルのバージョン情報はGetFileVersionInfoSizeWとGetFileVersionInfoWとVerQueryValueWという三つのAPIを使います。
(これまたGetFileVersionInfoSizeとGetFileVersionInfoとVerQueryValueでも良いのですが、一応念のため)
ちょっとややこしいです。

        if (VerQueryValueW(lp_Buff, '\VarFileInfo\Translation', Pointer(lp_LangPage), li_Len) and (li_Len > 0)) then begin
         //'\StringFileInfo\040904B0\'というような文字列
          ls_FileInfo := WideString(Format('\StringFileInfo\%.4x%.4x\', [lp_LangPage^.iLanguage, lp_LangPage^.iCodePage]));

最初のVerQueryValueWの呼び出しで第二引数に'\VarFileInfo\Translation'をセットすることでlp_LangPageに「言語識別子」と「文字セット識別子」の二つの情報がセットされます。
この「言語識別子」と「文字セット識別子」を16進数の文字列に変換して二度目のVerQueryValueWの第二引数に、取り出したいバージョン情報のキーと組み合わせて指定することで希望する値が得られます。
一口にバージョン情報と言っても、よくある「バージョン3.1」などのおなじみのものだけでなく、エクスプローラで.exeファイルや.dllファイルを選択、右クリックして「プロパティ」を選んでバージョン情報タブを選択すると現れる一連の情報を含めたものになります。
これらの一連の情報の中から下の図で言えば'9.0.0.4503'という「ファイルバージョン」を得ようということです。



この色々ある情報を取り出すのに上で述べたようにVerQueryValueWの第二引数に、'Comments'や'InternalName'や'ProductName'などのキーを「言語識別子」と「文字セット識別子」につけて渡すわけです。
これらのキーの中で、ファイルバージョンは'FileVersion'を使います。

          //ファイルバージョン
          if (VerQueryValueW(lp_Buff, PWideChar(ls_FileInfo + 'FileVersion'), lp_Dat, li_Len) and (li_Len > 0)) then begin
            Result := WideString(PWideChar(lp_Dat));
          end;

第二引数に希望するキーを「言語識別子」と「文字セット識別子」と組み合わせて指定すると三引数のlp_Datに希望する値がセットされるのでPWideCharとWideStringでキャストして取り出します。

あとはこの取り出したファイルバージョンのメジャーバージョンのみを数値として取り出し、必要とするメディアプレーヤーのバージョンと比較するだけです。

    ls_Ver := gfnsFileVersionGet(ls_Wmpdll);
    Val(ls_Ver, li_Num, li_Code);
    if (li_Num < iVer) then begin
      Application.MessageBox(PChar(Format('システムにWindowsMediaPlayerのVer %d 以上がインストールされている必要があります'#13'現在インストールされているWindowsMediaPlayerのバージョンは %s です', [iVer, ls_Ver])), PChar(sTitle), MB_OK);
      Result := False;
    end;

2009-08-09