2012-05-21 25 views
9

如何告诉InnoSetup不要卸载(文本)由用户更改的文件(==与InnoSetup安装的文件不同)?或者更难:当在现有的版本上安装新版本时,InnoSetup应该询问用户是否覆盖已更改的文件,但是在纯卸载时,它应该在不询问的情况下卸载它。InnoSetup:不要卸载已更改的文件

+0

也许你可以使用'UninsNeverUninstall'标志,然后为'CurUninstallStepChanged'' usPostUninstall'添加一个'[CODE]'部分,其中所有的TXT文件将检查CRC,然后删除,如果CRC相等或者CRC不等于用户将被通知有关更改的文件+询问文件是否应该删除。 – RobeN

+1

这些文件是什么?如果是配置文件,最好使用不同的名称安装默认文件,然后将其复制到主配置文件中不存在的位置。如果它们是用户文件,则安装程序根本不应触摸它们。 – Deanna

回答

6

我最近有一个类似的问题。这是我的解决方案,用于检测文本文件(配置文件)是否已从上次安装运行期间安装的文本文件(配置文件)更改为:

使用ISPP(Inno Setup Pre-Processor)创建文本文件及其哈希列表编译时间:

[Files] 
; ... 
#define FindHandle 
#define FindResult 
#define Mask "Profiles\*.ini" 
#sub ProcessFoundFile 
    #define FileName "Profiles\" + FindGetFileName(FindHandle) 
    #define FileMd5 GetMd5OfFile(FileName) 
    Source: {#FileName}; DestDir: {app}\Profiles; Components: profiles; \ 
     Check: ProfileCheck('{#FileMd5}'); AfterInstall: ProfileAfterInstall('{#FileMd5}'); 
#endsub 
#for {FindHandle = FindResult = FindFirst(Mask, 0); FindResult; FindResult = FindNext(FindHandle)} ProcessFoundFile 

在“代码”部分顶部我定义了一些有用的东西:

[Code] 
var 
    PreviousDataCache : tStringList; 

function InitializeSetup() : boolean; 
begin 
    // Initialize global variable 
    PreviousDataCache := tStringList.Create(); 
    result := TRUE; 
end; 

function BoolToStr(Value : boolean) : string; 
begin 
    if (not Value) then 
     result := 'false' 
    else 
     result := 'true'; 
end; 

在“检查”事件处理程序我比较以前的散列安装和当前文件:

function ProfileCheck(FileMd5 : string) : boolean; 
var 
    TargetFileName, TargetFileMd5, PreviousFileMd5 : string; 
    r : integer; 
begin 
    result := FALSE; 
    TargetFileName := ExpandConstant(CurrentFileName()); 
    Log('Running check procedure for file: ' + TargetFileName); 

    if not FileExists(TargetFileName) then 
    begin 
     Log('Check result: Target file does not exist yet.'); 
     result := TRUE; 
     exit; 
    end; 

    try 
     TargetFileMd5 := GetMd5OfFile(TargetFileName); 
    except 
     TargetFileMd5 := '(error)'; 
    end; 
    if (CompareText(TargetFileMd5, FileMd5) = 0) then 
    begin 
     Log('Check result: Target matches file from setup.'); 
     result := TRUE; 
     exit; 
    end; 

    PreviousFileMd5 := GetPreviousData(ExtractFileName(TargetFileName), ''); 
    if (PreviousFileMd5 = '') then 
    begin 
     r := MsgBox(TargetFileName + #10#10 + 
     'The existing file is different from the one Setup is trying to install. ' + 
     'It is recommended that you keep the existing file.' + #10#10 + 
     'Do you want to keep the existing file?', mbConfirmation, MB_YESNO); 
     result := (r = idNo); 
     Log('Check result: ' + BoolToStr(result)); 
    end 
    else if (CompareText(PreviousFileMd5, TargetFileMd5) <> 0) then 
    begin 
     r := MsgBox(TargetFileName + #10#10 + 
     'The existing file has been modified since the last run of Setup. ' + 
     'It is recommended that you keep the existing file.' + #10#10 + 
     'Do you want to keep the existing file?', mbConfirmation, MB_YESNO); 
     result := (r = idNo); 
     Log('Check result: ' + BoolToStr(result)); 
    end 
    else 
    begin 
     Log('Check result: Existing target has no local modifications.'); 
     result := TRUE; 
    end; 
end; 

在“AfterInstall”事件处理程序中,我将文件哈希标记为稍后存储在 注册表中。因为在我的测试中,如果文件移动失败的事件被触发甚至(目标文件是只读的),我又比较散,以找出是否将文件移动成功:

procedure ProfileAfterInstall(FileMd5 : string); 
var 
    TargetFileName, TargetFileMd5 : string; 
begin 
    TargetFileName := ExpandConstant(CurrentFileName()); 
    try 
     TargetFileMd5 := GetMd5OfFile(TargetFileName); 
    except 
     TargetFileMd5 := '(error)'; 
    end; 
    if (CompareText(TargetFileMd5, FileMd5) = 0) then 
    begin 
     Log('Storing hash of installed file: ' + TargetFileName); 
     PreviousDataCache.Add(ExtractFileName(TargetFileName) + '=' + FileMd5); 
    end; 
end; 

procedure RegisterPreviousData(PreviousDataKey : integer); 
var 
    Name, Value : string; 
    i, n : integer; 
begin 
    for i := 0 to PreviousDataCache.Count-1 do 
    begin 
     Value := PreviousDataCache.Strings[i]; 
     n := Pos('=', Value); 
     if (n > 0) then 
     begin 
     Name := Copy(Value, 1, n-1); 
     Value := Copy(Value, n+1, MaxInt); 
     SetPreviousData(PreviousDataKey, Name, Value); 
     end; 
    end; 
end; 
+0

我可以问你什么时候调用RegisterPreviousData()? –

+2

@JulienM:如果存在具有该名称的函数,则“RegisterPreviousData”是由Inno Setup自动调用的事件函数。有关更多信息,请参阅Inno Setup帮助。 – blerontin

+0

良好的工作;如果一个相当于这个的标志可以被添加到InnoSetup中会更好! –

1

Inno无法在本地执行此检查。

要在安装过程中不替换已更改的文件,您需要使用自定义[Code]来执行校验和,并与预先计算或从以前的安装中保存的已知良好值进行比较。

为避免在卸载过程中将其删除,您需要先禁用Inno自己的卸载,然后在删除它们之前检查相同的校验和,再次在[Code]

请注意,最好保留用户可以在设置之外编辑的任何文件,以更好地处理这种情况并正确遵守应用程序指南。