Delphi Programming / Object Pascal
[掲載 2017年11月19日] [更新 2017年11月21日] Delphi サンプルプログラム集
354_MSI ( Microsoft Installer ) でインストールしたアプリのリスト
動作確認等
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
354_InstalledSoftByMSI.zip [1,106 KB] 2017年11月21日版 (EXE 同梱)
01_ MSI ( Microsoft Installer ) でインストールしたアプリのリスト
MSI (Microsoft Installer) でインストールしたアプリを列挙するサンプルです.
Windows Installer の API (MSI API または Microsoft Installer API) を使用していますが,Delphi XE にはこれらの関数類が実装されていないので,JEDI API ライブラリを使用しています.
JEDI API ライブラリには,JwaMsi.pas 以外にも JwaMsiDefs.pas, JwaMsiQuery.pas に MSI API 関係の関数類があります.
WMI の Win32_Product クラスでも MSI でインストールしたアプリの情報を取得することができますが,非常に時間がかかります.
[備考]
Windows Installer CleanUp というツールがマイクロソフトから提供されていました.
これは MSI でインストールしたアプリのアンインストールが正常に実行されない場合に,インストール情報を削除するツールでした.2017年11月19日現在,このツールは提供されていません.同様なツールがマイクロソフトから提供されています.
図1
実行結果
リスト1
MSI ( Microsoft Installer ) でインストールしたアプリのリスト
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses
JwaMsi;
{$R *.dfm}
// -----------------------------------------------------------------------------
// MSIでインストールしたアプリのプロパティの取得
// AProduct : インストールされているアプリのプロダクト名
// MsiEnumProducts関数で取得した値
// AProperty : 取得したいプロパティの定数名
// 使用可能な定数名はMsiGetProductInfo関数の説明を参照
// -----------------------------------------------------------------------------
function GetMsiPropertyValueStr(AProduct: PChar; AProperty: PChar): string ;
var
LValue : PChar;
LLen : DWORD;
begin
// 取得に必要なバッファサイズを取得(第3引数をnilにする)
LLen := 0 ;
MsiGetProductInfo(AProduct, AProperty, nil , @LLen);
// 取得したバッファサイズにnul終端文字分が含まれないとのことなので追加
LLen := LLen + 1 ;
LValue := StrAlloc(LLen);
try
MsiGetProductInfo(AProduct, AProperty, LValue, @LLen);
Result := LValue;
finally
StrDispose(LValue);
end ;
end ;
// =============================================================================
// MSIでインストールしたアプリをリスト
//
// JEDI API ライブラリのMSI API(Microsoft Installer API)関係の関数類を利用
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIndex : Integer;
LpProduct : PChar;
LText : string ;
begin
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
LIndex := 0 ;
LpProduct := StrAlloc(MAX_PATH);
try
while MsiEnumProducts(LIndex, LpProduct) = ERROR_SUCCESS do begin
Memo1.Lines.Add(string (LpProduct));
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_PACKAGENAME);
Memo1.Lines.Add(LText);
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_INSTALLEDPRODUCTNAME);
Memo1.Lines.Add(LText);
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_VERSIONSTRING);
Memo1.Lines.Add(LText);
Memo1.Lines.Add('' );
inc(LIndex);
end ;
finally
StrDispose(LpProduct);
end ;
Memo1.Lines.EndUpdate;
Label1.Caption := '合計 : ' + IntToStr(LIndex);
end ;
end .
02_ ジェネリクス TList<T> に格納後にソートして表示
次のサンプルは,アプリのプロパティをジェネリクス TList<T> に全て格納した後にソートして表示する例です.こうすることにより,必要なアプリだけを抽出したり,結果の表示を加工したり,ソートする等の操作が容易にできるようになります.また,プロパティを取得する時に操作するよりもコードの見通しもよくなります.
各アプリのプロパティは,レコード型を定義してそのメンバにセットしています.ソードには無名関数を使用しています.
図2
実行結果
リスト2
MSI ( Microsoft Installer ) でインストールしたアプリのリスト
ジェネリクス TList<T> に格納後にソートして表示
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Generics.Collections, Generics.Defaults;
type
TForm1 = class (TForm)
Button1: TButton;
Memo1: TMemo;
Label1: TLabel;
CheckBox1: TCheckBox;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses
JwaMsi;
{$R *.dfm}
// ----------------------------------------------
// 取得したプロパティの値を格納するレコード型
// ----------------------------------------------
type
TSoftRecord = record
Product : string ;
Name : string ;
PkgName : string ;
InstDate : TDateTime;
Publisher : string ;
VerStr : string ;
end ;
PSoftRecord = ^TSoftRecord;
// -----------------------------------------------------------------------------
// MSIでインストールしたアプリのプロパティの取得
// AProduct : インストールされているアプリのプロダクト名
// MsiEnumProducts関数で取得した値
// AProperty : 取得したいプロパティの定数名
// 使用可能な定数名はMsiGetProductInfo関数の説明を参照
// -----------------------------------------------------------------------------
function GetMsiPropertyValueStr(AProduct: PChar; AProperty: PChar): string ;
var
LValue : PChar;
LLen : DWORD;
begin
// 取得に必要なバッファサイズを取得(第3引数をnilにする)
LLen := 0 ;
MsiGetProductInfo(AProduct, AProperty, nil , @LLen);
// 取得したバッファサイズにnul終端文字分が含まれないとのことなので追加
LLen := LLen + 1 ;
LValue := StrAlloc(LLen);
try
MsiGetProductInfo(AProduct, AProperty, LValue, @LLen);
Result := LValue;
finally
StrDispose(LValue);
end ;
end ;
// =============================================================================
// MSIでインストールしたアプリをリスト
//
// JEDI API ライブラリのMSI API(Microsoft Installer API)関係の関数類を利用
// TList<T>の使用にはusesにGenerics.Collectionsが必要
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIndex : Integer;
LpProduct : PChar;
LText : string ;
LSoftRec : TSoftRecord;
LSoftList : TList<TSoftRecord>;
begin
LIndex := 0 ;
LpProduct := StrAlloc(MAX_PATH);
LSoftList := TList<TSoftRecord>.Create;
try
while MsiEnumProducts(LIndex, LpProduct) = ERROR_SUCCESS do begin
LSoftRec.Product := string (LpProduct);
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_INSTALLEDPRODUCTNAME);
LSoftRec.Name := LText;
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_PACKAGENAME);
LSoftRec.PkgName := LText;
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_PUBLISHER);
LSoftRec.Publisher := LText;
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_INSTALLDATE);
LSoftRec.InstDate := StrToDate(FormatFloat('0000/00/00' , StrToFloat(LText)));
LText := GetMsiPropertyValueStr(LpProduct, INSTALLPROPERTY_VERSIONSTRING);
LSoftRec.VerStr := LText;
LSoftList.Add(LSoftRec);
inc(LIndex);
end ;
// -------------------------------------------------------------------------
// TLst<T>のソート
// TComparer関係の使用にはusesにGenerics.Defaultsが必要
// -------------------------------------------------------------------------
if CheckBox1.Checked then begin
LSoftList.Sort(TComparer<TSoftRecord>.Construct(
function (const Left, Right: TSoftRecord): Integer
begin
// Name(INSTALLPROPERTY_INSTALLEDPRODUCTNAME)の値でソート
Result := SysUtils.CompareText(Left.Name, Right.Name);
// TDateTime型の日付でソートする場合の例
// Result := (Trunc(Left.InstDate) - Trunc(Right.InstDate));
end )
);
end ;
// -------------------------------------------------------------------------
// 結果の表示
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
for LSoftRec in LSoftList do begin
Memo1.Lines.Add(LSoftRec.Name);
Memo1.Lines.Add(LSoftRec.PkgName);
Memo1.Lines.Add(LSoftRec.Publisher);
Memo1.Lines.Add(DateTimeToStr(LSoftRec.InstDate));
Memo1.Lines.Add(LSoftRec.VerStr);
Memo1.Lines.Add(LSoftRec.Product);
Memo1.Lines.Add('' );
end ;
Memo1.Lines.EndUpdate;
Label1.Caption := '合計 : ' + IntToStr(LIndex);
finally
StrDispose(LpProduct);
FreeAndNil(LSoftList);
end ;
end ;
end .