下面的代码进行了改进,增加了计数功能,也能正确处理别人已经添加了的同样项目。
#define AppID "FDBDCE28-5522-494B-B75A-E515082A312D"
#ifdef UNICODE
#define A "W"
#else
#define A "A"
#endif
[Setup]
AppId={#AppID}
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
[Tasks]
Name: noad; Description: "通过 hosts 屏蔽广告(&D)"
[code]
const
myMark = 'XYZ123'; // 你的标识,用于标识你修改的内容
var
AddHostsItemList, AddHostsCommentList, RemoveHostsList: TStringList;
function GetFileAttributes(lpFileName: String): Cardinal;
external 'GetFileAttributes{#A}@kernel32.dll stdcall';
function SetFileAttributes(lpFileName: String; dwFileAttributes: Cardinal): Boolean;
external 'SetFileAttributes{#A}@kernel32.dll stdcall';
function IsLineInFile(sItem: string; sl: TStringList; var LineNo, Cnt: LongInt): Boolean;
var
s: String;
n: Integer;
begin
Result := false;
LineNo := 0; // 行号
Cnt := 0; // 计数器
for n:= 0 to sl.Count-1 do
if Pos(sItem, Trim(sl.Strings[n])) = 1 then
begin
Result := true;
LineNo := n + 1;
s := Trim(sl.Strings[n]);
if Pos('##', s) > 0 then
begin
Delete(s, 1, Pos('##', s)+1);
if Pos(' ', s) > 0 then
s := Copy(s, 1, Pos(' ', s)-1);
Cnt := StrToIntDef(s, 0);
end;
exit;
end;
end;
procedure StartAddHosts();
begin
AddHostsItemList := TStringList.Create;
AddHostsCommentList := TStringList.Create;
end;
procedure AddHosts(newItem, comments: string);
begin
AddHostsItemList.Add(newItem);
AddHostsCommentList.Add(comments);
end;
procedure EndAddHosts();
var
stl: TStringList;
fs: TFileStream;
OldFileAttribute: Cardinal;
hfPath, newItem, comments, s: string;
LineNo, Cnt, n: LongInt;
begin
hfPath := ExpandConstant('{sys}\drivers\etc\hosts');
OldFileAttribute := GetFileAttributes(hfPath);
SetFileAttributes(hfPath, FILE_ATTRIBUTE_NORMAL);
stl := TStringList.Create;
stl.LoadFromFile(hfPath);
try
for n:= 0 to AddHostsItemList.Count-1 do
begin
newItem := AddHostsItemList.Strings[n];
comments := AddHostsCommentList.Strings[n];
if IsLineInFile(newItem, stl, LineNo, Cnt) then // 检查 Hosts 中是否有该项
begin
s := stl.Strings[LineNo-1];
if Cnt = 0 then
StringChangeEx(s, newItem, newItem + ' ##2', true) // 如果有项目,但是没有计数,说明是别人已经添加的项目,计数从 2 开始
else
StringChangeEx(s, newItem + ' ##' + IntToStr(Cnt), newItem + ' ##' + IntToStr(Cnt+1), true); // 计数加 1
stl.Strings[LineNo-1] := s;
end
else
begin // Hosts 中还没有该项
s := newItem + ' ##1 ID' + myMark; // 计数从 1 开始,ID标识 计数形式: ##x
if Trim(comments) > '' then // 检查注释是否为空白
s := s + ' / ' + Trim(comments);
stl.Add(s);
end;
end;
finally
AddHostsItemList.Free;
AddHostsCommentList.Free;
end;
fs := TFileStream.Create(hfPath, fmCreate);
try
stl.SaveToStream(fs);
fs.Size := fs.Size - Length(#13#10); // 删除最后的换行符
finally
stl.Free;
fs.Free;
end;
SetFileAttributes(hfPath, OldFileAttribute);
end;
procedure StartRemoveHosts();
begin
RemoveHostsList := TStringList.Create;
end;
procedure RemoveHosts(sItem: string);
begin
RemoveHostsList.Add(sItem);
end;
procedure EndRemoveHosts();
var
OldFileAttribute: Cardinal;
hfPath, sItem, s: string;
stl: TStringList;
fs: TFileStream;
LineNo, Cnt, n: LongInt;
begin
hfPath := ExpandConstant('{sys}\drivers\etc\hosts');
OldFileAttribute := GetFileAttributes(hfPath);
SetFileAttributes(hfPath, FILE_ATTRIBUTE_NORMAL);
stl := TStringList.Create;
stl.LoadFromFile(hfPath);
try
for n:= 0 to RemoveHostsList.Count-1 do
begin
sItem := RemoveHostsList.Strings[n];
if IsLineInFile(sItem, stl, LineNo, Cnt) then // 检查 Hosts 中是否有该项
if Cnt > 0 then
begin
if Cnt = 1 then
stl.Delete(LineNo-1) // 计数是 1 的项将被删除
else
begin
s := stl.Strings[LineNo-1];
if (Cnt = 2) and (Pos('ID'+myMark, s) = 0) then // 如果计数是 2,但是没有标识,说明是别人添加的项,将恢复原状
StringChangeEx(s, sItem + ' ##2', sItem, true)
else
StringChangeEx(s, sItem + ' ##' + IntToStr(Cnt), sItem + ' ##' + IntToStr(Cnt-1), true); // 计数减 1
stl.Strings[LineNo-1] := s;
end;
end;
end;
finally
RemoveHostsList.Free;
end;
fs := TFileStream.Create(hfPath, fmCreate);
try
stl.SaveToStream(fs);
fs.Size := fs.Size - Length(#13#10); // 删除最后的换行符
finally
stl.Free;
fs.Free;
end;
SetFileAttributes(hfPath, OldFileAttribute);
end;
function GetHKLM: Integer;
begin
if IsWin64 then
Result := HKLM32
else
Result := HKLM;
end;
function WasTaskSelected(aTask, AppID: String): boolean;
var
sSelectedTasks, sTask: String;
begin
Result := false;
sSelectedTasks := '';
if RegQueryStringValue(getHKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\'+AppID+'_is1',
'Inno Setup: Selected Tasks', sSelectedTasks) then
begin
sSelectedTasks := Uppercase(sSelectedTasks);
sTask := Uppercase(aTask);
if Pos(',', sSelectedTasks) = 0 then
Result := sSelectedTasks = sTask
else
begin
if Pos(sTask+',', sSelectedTasks) = 1 then
Result := true;
if Pos(','+sTask+',', sSelectedTasks) > 0 then
Result := true;
if Pos(','+sTask, sSelectedTasks) = Length(sSelectedTasks) - Length(sTask) then
Result := true;
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep );
begin
if CurStep = ssPostInstall then // 安装文件前检查
if IsTaskSelected('noad') then // 是否选择了相应的任务
begin
WizardForm.StatusLabel.Caption := '正在添加 Hosts ...';
StartAddHosts; // 开始添加项目(必需)
AddHosts('127.0.0.1
www.abcd.com', '你的注释'); // 添加要增加的项目,带注释
AddHosts('127.0.0.1
www.abcd.net', ''); // 添加要增加的项目,不带注释
EndAddHosts; // 结束添加项目(必需)
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep );
begin
if CurUninstallStep = usUninstall then // 卸载文件前检查
if WasTaskSelected('noad', '{#AppID}') then // 安装时是否选择了相应的任务
begin
StartRemoveHosts; // 开始删除项目(必需)
RemoveHosts('127.0.0.1
www.abcd.com'); // 添加要删除的项目
RemoveHosts('127.0.0.1
www.abcd.net'); // 添加要删除的项目
EndRemoveHosts; // 结束删除项目(必需)
end;
end;