私のプロジェクトでは、プログラムファイルディレクトリにコピーするファイルがいくつかあり、1つの実行可能ファイルのショートカットを作成し、他のファイルはインストールのように機能します。
CAB ファイルなどのパッケージ内のストア ファイルを使用してアプリケーションでこれを実行し、進行状況バーにインストールを表示したいと考えています。
最初に msi ラッパーについて考えましたが、一部のユーザーはそれが非常に遅いと言いました。
どうすればこれを最善の方法で行うことができますか?
私のプロジェクトでは、プログラムファイルディレクトリにコピーするファイルがいくつかあり、1つの実行可能ファイルのショートカットを作成し、他のファイルはインストールのように機能します。
CAB ファイルなどのパッケージ内のストア ファイルを使用してアプリケーションでこれを実行し、進行状況バーにインストールを表示したいと考えています。
最初に msi ラッパーについて考えましたが、一部のユーザーはそれが非常に遅いと言いました。
どうすればこれを最善の方法で行うことができますか?
開始用の小さなテンプレートを次に示します。
unit Unit1;
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
StdCtrls
, JwaMsi, windows // Units needed for MSI manipulation & for some type declarations
type
{ TForm1 }
TForm1 = class(TForm)
btnDoIt: TButton;
lbxMsg: TListBox;
procedure btnDoItClick(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// Callback function
// Here you must handle type and content of messages from MSI (see MSDN for details)
function MSICallback(pvContext: LPVOID; iMessageType: Cardinal; szMessage: LPCSTR): Integer; stdcall;
var
s: string;
begin
// Convert PChar to string. Just for convenience.
s := szMessage;
// Add info about message to the ListBox
Form1.lbxMsg.Items.Add(Format('Type: %d, Msg: %s', [iMessageType, s]));
// Repaint form (may be it is not necessary)
Form1.Refresh;
Application.ProcessMessages;
If iMessageType = INSTALLMESSAGE_TERMINATE then
ShowMessage('Done');
end;
{ TForm1 }
procedure TForm1.btnDoItClick(Sender: TObject);
begin
// Do not show native MSI UI
MsiSetInternalUI(INSTALLUILEVEL_NONE + INSTALLUILEVEL_SOURCERESONLY, nil);
// Set hook to MSI
MsiSetExternalUI(
@MSICallback, // Callback function
$FFFFFFFF, // Receive all types of messages
nil);
// Install product (change path to installation package)
MsiInstallProduct(
'D:\install\games\_old\corewar\nMarsFull.0.9.5.win.msi',
nil);
end;
end.