16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"アンインストールプログラム"
この発言に対し以下のコメントが寄せられています
#01402 牧原 博司 さん RE:アンインストールプログラム
アンインストール用プログラムです。
ファイルのコピーには、Delphi5\Demos\Doc\Filmanex にある FmxUtils.pas
のCopyFileを使っています。
Uninst.exe(親プロセス) を実行すると、Windows ディレクトリにコピー
し、コピーしたUninst.exe(子プロセス) を実行します。実行した
Uninst.exe(子プロセス)が Uninst.exe(親プロセス)を停止・ファイル削除
し、Win9x では WinInit.ini を作成、WinNT では MoveFileEx で Windows 再
起動後にUninst.exe(子プロセス)を削除します。
nifty:FDELPHI/MES/16/1225 のTNさんの発言、「子プロセスに自分を殺さ
せる」のコードを使用させていただきました。
----------------------------------------------------------------------
program Uninst;
uses
Forms, Controls, Dialogs, Windows, ShlObj,
FmxUtils, IniFiles, Classes, SysUtils, FileCtrl;
{$R *.RES}
// Windows ディレクトリを返す
function GetWinDir: string;
var
Buffer: array[0..MAX_PATH - 1] of Char;
begin
SetString(Result, Buffer,
GetWindowsDirectory(Buffer,SizeOf(Buffer)));
end;
// 自分自身を削除するための「WinInit.ini」を作成する
procedure CreateWinInit;
var
Ini: TIniFile;
begin
Ini := TIniFile.Create(GetWinDir + '\WinInit.ini');
try
Ini.WriteString('rename', 'NUL', Application.Exename);
finally
Ini.Free;
end;
end;
// ファイルが存在したら、削除する
function DelFile(FileName: string): boolean;
begin
Result := True;
if not FileExists(FileName) then Exit;
Result := DeleteFile(FileName);
end;
// ディレクトリが存在したら、削除する
function DeleteDir(DirName: string): boolean;
begin
Result := True;
try
if DirectoryExists(DirName) then
RmDir(DirName);
except
on EInOutError do Result := False;
end;
end;
var
SecAttr: TSecurityAttributes;
S: string;
Ph: THandle;
St: TStringList;
ReportList: TStringList;
i: integer;
// 子プロセスから親プロセスを殺せるように、継承ハンドルを
// テキストファイルに保存して、CreateProcessを実行する
procedure _CreateProcess(ExeFileName, HandleFileName: string);
var
Si: TStartupInfo;
Pi: TProcessInformation;
begin
GetStartupInfo(Si);
SecAttr.bInheritHandle := True;
SecAttr.nLength := Sizeof(SecAttr);
if Windows.CreateProcess( nil,
PChar( ExeFileName ),
@SecAttr, @SecAttr, True,
CREATE_DEFAULT_ERROR_MODE,
nil, PChar(GetCurrentDir), Si, Pi)
then
begin
DuplicateHandle( GetCurrentProcess, GetCurrentProcess,
Pi.hProcess,
@Ph, 0, False, DUPLICATE_SAME_ACCESS );
St := TStringList.Create;
try
St.Add( InttoStr( Ph ) );
St.SaveToFile(HandleFileName);
finally
St.Free;
end;
end;
end;
// アンインストール処理
procedure Proc_Uninstall;
begin
{
// ファイル削除の場合
if not DelFile(S) then ReportList.Add(S);
// ディレクトリ削除の場合
if not DeleteDir(S) then ReportList.Add(S);
// exeファイル(親プロセス)のあるディレクトリの削除は、
// もちろん、exeファイル(親プロセス)の削除です。
}
end;
begin
Application.Initialize;
Application.Title := 'Uninstall';
Application.Run;
if (ParamCount=2) and
(UpperCase(ParamStr(1))='/UNINSTALL') then
begin
ReportList := TStringList.Create;
try
// 元々の exe
S := ParamStr(2) + '\' + ExtractFileName(Application.Exename);
// Windows 再起動時に自分自身を削除する
if Win32PlatForm=VER_PLATFORM_WIN32_NT then
MoveFileEx(PChar(Application.Exename), nil,
MOVEFILE_DELAY_UNTIL_REBOOT)
else if Win32PlatForm=VER_PLATFORM_WIN32_WINDOWS then
CreateWinInit;
// アンインストール処理
Proc_Uninstall;
// 親プロセス 停止
St := TStringList.Create;
try
St.LoadFromFile(GetWinDir + '\_Handle.Dat');
Ph := StrToInt( St[0] );
finally
St.Free;
end;
TerminateProcess( Ph, 0 );
// テキストファイル(継承ハンドル)削除
if FileExists(GetWinDir + '\_Handle.Dat') then
SysUtils.DeleteFile(GetWinDir + '\_Handle.Dat');
// exeファイル(親プロセス) 削除
if not DelFile(S) then ReportList.Add(S);
if ReportList.Count=0 then
S := 'アンインストールしました'
else
begin
S := 'アンインストールしました' + #13 +
'一部削除できませんでした' + #13#13;
for i:=0 to ReportList.Count-1 do
S := S + ReportList[i] + #13;
end;
finally
ReportList.Free;
end;
end
else
begin
SysUtils.Beep;
if MessageDlg('アンインストールを実行してよろしいですか?',
mtConfirmation,[mbYes,mbNo],0)=mrNo then Exit;
// 自分自身をWindows ディレクトリにコピーする
S := GetWinDir + '\' + ExtractFileName(Application.Exename);
if Application.Exename=S then
begin
MessageDlg('Windows ディレクトリでは実行できません,
mtError,[mbOK],0);
Exit;
end;
FmxUtils.CopyFile(Application.Exename, S);
// Windows ディレクトリにコピーした exe を実行する
// 第一パラメータ = '/UNINSTALL'
// 第二パラメータ = 実行したディレクトリ
S := S +' /UNINSTALL "'+ ExtractFileDir(Application.Exename)+'"';
// コピーした exe を実行する
// 子プロセスから親プロセスを殺せるように、継承ハンドルを
// テキストファイルに保存して、CreateProcessを実行する
_CreateProcess(PChar(S), GetWinDir + '\_Handle.Dat');
end;
end.
----------------------------------------------------------------------
牧原 博司 hiroshi.makihara@nifty.ne.jp - 2001/11/19 (Mon) 21:44 -
Original document by 牧原 博司 氏 ID:(QZS03450)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|