336 lines
8.0 KiB
Plaintext
336 lines
8.0 KiB
Plaintext
|
#if 0
|
||
|
[Code]
|
||
|
#endif
|
||
|
|
||
|
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 PIKA 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;
|