2012-05-21 30 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]

請注意,最好保留用戶可以在設置之外編輯的任何文件,以更好地處理這種情況並正確遵守應用程序指南。