gimp/build/windows/installer/util_uninst.isi

339 lines
8.1 KiB
Plaintext

#if 0
[Code]
#endif
var
asUninstInf: TArrayOfString; //uninst.inf contents (loaded at start of uninstall, executed at the end)
function SplitRegParams(const pInf: String; var oRootKey: Integer; var oKey,oValue: String): Boolean;
var sRootKey: String;
d: Integer;
begin
Result := False;
d := Pos('/',pInf);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing /): ' + pInf);
exit;
end;
sRootKey := Copy(pInf,1,d - 1);
oKey := Copy(pInf,d + 1,Length(pInf));
if oValue <> 'nil' then
begin
d := RevPos('\',oKey);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing \): ' + pInf);
exit;
end;
oValue := Decode(Copy(oKey,d+1,Length(oKey)));
oKey := Copy(oKey,1,d-1);
end;
DebugMsg('SplitRegParams','Root: '+sRootKey+', Key:'+oKey + ', Value:'+oValue);
case sRootKey of
'HKCR': oRootKey := HKCR;
'HKLM': oRootKey := HKLM;
'HKU': oRootKey := HKU;
'HKCU': oRootKey := HKCU;
else
begin
DebugMsg('SplitRegParams','Unrecognised root key: ' + sRootKey);
exit;
end;
end;
Result := True;
end;
procedure UninstInfRegKey(const pInf: String; const pIfEmpty: Boolean);
var sKey,sVal: String;
iRootKey: Integer;
begin
sVal := 'nil';
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if pIfEmpty then
begin
if not RegDeleteKeyIfEmpty(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIfEmpty failed');
end
else
begin
if not RegDeleteKeyIncludingSubkeys(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIncludingSubkeys failed');
end;
end;
procedure UninstInfRegVal(const pInf: String);
var sKey,sVal: String;
iRootKey: Integer;
begin
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if not RegDeleteValue(iRootKey,sKey,sVal) then
DebugMsg('UninstInfREG','RegDeleteKeyIncludingSubkeys failed');
end;
procedure UninstInfFile(const pFile: String);
begin
DebugMsg('UninstInfFile','File: '+pFile);
if not DeleteFile(pFile) then
DebugMsg('UninstInfFile','DeleteFile failed');
end;
procedure UninstInfDir(const pDir: String);
begin
DebugMsg('UninstInfDir','Dir: '+pDir);
if not RemoveDir(pDir) then
DebugMsg('UninstInfDir','RemoveDir failed');
end;
procedure CreateMessageForm(var frmMessage: TForm; const pMessage: String);
var lblMessage: TNewStaticText;
begin
frmMessage := CreateCustomForm();
with frmMessage do
begin
BorderStyle := bsDialog;
ClientWidth := ScaleX(300);
ClientHeight := ScaleY(48);
Caption := CustomMessage('UninstallingAddOnCaption');
Position := poScreenCenter;
BorderIcons := [];
end;
lblMessage := TNewStaticText.Create(frmMessage);
with lblMessage do
begin
Parent := frmMessage;
AutoSize := True;
Caption := pMessage;
Top := (frmMessage.ClientHeight - Height) div 2;
Left := (frmMessage.ClientWidth - Width) div 2;
Visible := True;
end;
frmMessage.Show();
frmMessage.Refresh();
end;
procedure UninstInfRun(const pInf: String);
var Description,Prog,Params: String;
Split, ResultCode, Ctr: Integer;
frmMessage: TForm;
begin
DebugMsg('UninstInfRun',pInf);
Split := Pos('/',pInf);
if Split <> 0 then
begin
Description := Copy(pInf, 1, Split - 1);
Prog := Copy(pInf, Split + 1, Length(pInf));
end else
begin
Prog := pInf;
Description := '';
end;
Split := Pos('/',Prog);
if Split <> 0 then
begin
Params := Copy(Prog, Split + 1, Length(Prog));
Prog := Copy(Prog, 1, Split - 1);
end else
begin
Params := '';
end;
if not UninstallSilent then //can't manipulate uninstaller messages, so create a form instead
CreateMessageForm(frmMessage,Description);
DebugMsg('UninstInfRun','Running: ' + Prog + '; Params: ' + Params);
if Exec(Prog,Params,'',SW_SHOW,ewWaitUntilTerminated,ResultCode) then
begin
DebugMsg('UninstInfRun','Exec result: ' + IntToStr(ResultCode));
Ctr := 0;
while FileExists(Prog) do //wait a few seconds for the uninstaller to be deleted - since this is done by a program
begin //running from a temporary directory, the uninstaller we ran above will exit some time before
Sleep(UNINSTALL_CHECK_TIME); //it's removed from disk
Inc(Ctr);
if Ctr = (UNINSTALL_MAX_WAIT_TIME/UNINSTALL_CHECK_TIME) then //don't wait more than 5 seconds
break;
end;
end else
DebugMsg('UninstInfRun','Exec failed: ' + IntToStr(ResultCode) + ' (' + SysErrorMessage(ResultCode) + ')');
if not UninstallSilent then
frmMessage.Free();
end;
(*
uninst.inf documentation:
- Delete Registry keys (with all subkeys):
RegKey:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete (warning: this will delete all keys under subkey, so be very careful with it)
- Delete empty registry keys:
RegKeyEmpty:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete if empty
- Delete values from registry:
RegVal:<RootKey>/<SubKey>/Value
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete Value from
Value = value to delete; \ and % must be escaped as %5c and %25
- Delete files:
File:<Path>
Path = full path to file
- Delete empty directories:
Dir:<Path>
- Run program with parameters:
Run:<description>/<path>/<params>
Directives are parsed from the end of the file backwards as the first step of uninstall.
IMPORTANT: From GIMP 2.10.12 onwards (Inno Setup 6 with support for per-user install), Registry keys referring to HKCR will be
processed by the installer as the first step of install (and the entries will be removed from uninst.inf), since file associations
code was rewritten.
*)
procedure ParseUninstInf();
var i,d: Integer;
sWhat: String;
begin
for i := GetArrayLength(asUninstInf) - 1 downto 0 do
begin
DebugMsg('ParseUninstInf',asUninstInf[i]);
if (Length(asUninstInf[i]) = 0) or (asUninstInf[i][1] = '#') then //skip comments and empty lines
continue;
d := Pos(':',asUninstInf[i]);
if d = 0 then
begin
DebugMsg('ParseUninstInf','Malformed line: ' + asUninstInf[i]);
continue;
end;
sWhat := Copy(asUninstInf[i],d+1,Length(asUninstInf[i]));
case Copy(asUninstInf[i],1,d) of
'RegKey:': UninstInfRegKey(sWhat,False);
'RegKeyEmpty:': UninstInfRegKey(sWhat,True);
'RegVal:': UninstInfRegVal(sWhat);
'File:': UninstInfFile(sWhat);
'Dir:': UninstInfDir(sWhat);
'Run:': UninstInfRun(sWhat);
end;
end;
end;
procedure CurUninstallStepChanged(CurStep: TUninstallStep);
begin
DebugMsg('CurUninstallStepChanged','');
case CurStep of
usUninstall:
begin
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asUninstInf);
ParseUninstInf();
end;
//usPostUninstall:
end;
end;
procedure AssociationsCleanUp();
var i, d, countNew,countUI: Integer;
asTemp, asNew: TArrayOfString;
sKey,sVal: String;
iRootKey: Integer;
begin
if FileExists(ExpandConstant('{app}\uninst\uninst.inf')) then
begin
DebugMsg('AssociationsCleanUp','Parsing old uninst.inf');
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asTemp);
countNew := 0;
countUI := 0;
SetArrayLength(asNew, GetArrayLength(asTemp));
SetArrayLength(asUninstInf, GetArrayLength(asTemp));
for i := 0 to GetArrayLength(asTemp) - 1 do //extract associations-related entries from uninst.inf
begin
if (Length(asTemp[i]) = 0) or (asTemp[i][1] = '#') then //comment/empty line
begin
asNew[countNew] := asTemp[i];
Inc(countNew);
continue;
end;
d := Pos(':',asTemp[i]);
if d = 0 then //something wrong, ignore
continue;
if Copy(asTemp[i],1,3) = 'Reg' then
begin
sVal := 'nil';
if not SplitRegParams(Copy(asTemp[i], d + 1, Length(asTemp[i])),iRootKey,sKey,sVal) then
continue; //malformed line, ignore
if iRootKey = HKCR then //old association, prepare for cleanup
begin
DebugMsg('AssociationsCleanUp','Preparing for cleanup: '+asTemp[i]);
asUninstInf[countUI] := asTemp[i];
Inc(countUI);
continue;
end;
end;
//something else, keep for new uninst.inf
asNew[countNew] := asTemp[i];
Inc(countNew);
end;
SetArrayLength(asNew, countNew);
SetArrayLength(asUninstInf, countUI);
SaveStringsToUTF8File(ExpandConstant('{app}\uninst\uninst.inf'), asNew, False); //replace uninst.inf with a cleaned one
ParseUninstInf(); //remove old associations
end;
end;