天天看點

Inno_setup制作更新包必須面臨的幾個問題

        這兩天的時間一直在制作應用程式的更新包,期間碰到一些問題這裡一并記錄下來,相信這是制作更新包必須面臨和解決的問題:

1. 更新包安裝程式如何不再産生新的安裝、解除安裝程式

    Inno_setup中AppId是用來辨別某個應用程式的唯一辨別,是以更新包中的AppId字段應該和原始安裝程式的AppId相同。

    CreateUninstallRegKey字段,改值設定為no則安裝程式将不會在控制台的“添加/删除程式”中再建立一個。當這個關鍵字設定為 no時,UpdateUninstallAppName通常也設定為 no。

    UpdateUninstallAppName如果為 yes, 當添加到一個已存在的解除安裝記錄時,安裝程式将以目前的安裝程式的 AppName 替換在解除安裝記錄中的 AppName。解除安裝記錄中的 AppName決定了解除安裝程式顯示的标題。如果你的安裝程式隻是一個更新或附加到一個已存在的程式,并且你不想改變解除安裝程式的标題,那麼你可以設定該值為no。

2. 如何檢測以前的應用程式正在運作

    判斷某個應用程式是否正在運作,這裡可以采用兩種方式:一種是應用程式的程序是否正在運作;一種是通過視窗名稱來檢測。采用第一種方式時要引入ISTask.dll檔案(它通常可以在Inno_setup安裝包裡面找到),執行個體代碼如下:

    1) 通過程序檢測是否正在運作

         首先確定ISTask.dll檔案和腳本檔案位于同一目錄:

Inno_setup制作更新包必須面臨的幾個問題

        其次確定[Files]段中添加:

Inno_setup制作更新包必須面臨的幾個問題

        最後[Code]段中加入一下函數調用:

Inno_setup制作更新包必須面臨的幾個問題

    2) 通過視窗檢測是否正在運作,主要是通過FindWindowByWindowName()函數,下面以檢測有道詞典是否正在運作為例:

Inno_setup制作更新包必須面臨的幾個問題

    以上兩種情況可以依據自己的實際情況來選擇,如果你的應用程式視窗固定那麼采用第二種檢測方式會友善一些;但是如果你無法确定視窗名稱或你的視窗名稱是會變化的,則采用第一種方式會更好。

3. 如何修改控制台裡原有程式的版本資訊

    制作更新包不得不面對的問題是版本更新,那麼像下面所示如何修改控制台中存在的版本資訊是我們不得不面對的問題:

Inno_setup制作更新包必須面臨的幾個問題

    如何修改呢?看看我們的系統資料庫就知道了:

Inno_setup制作更新包必須面臨的幾個問題

    圖中辨別的就是控制台中可以看到的所有資訊,那麼解決方案就是修改系統資料庫中的資訊,具體代碼如下:

Inno_setup制作更新包必須面臨的幾個問題

   具體涉及的兩個操作就是:RegQueryStringValue()查詢系統資料庫和RegWriteStringValue()修改系統資料庫,具體使用一看便知。

4. 如何修改控制台裡原有程式的顯示圖示

    有了上面的如何修改控制台裡的版本資訊,相信你已經猜到了,修改控制台裡應用程式的顯示圖示也是通過修改系統資料庫來實作的,這裡要提到的是:DisplayIcon字段,用來定義控制台中應用程式圖示的顯示路徑,代碼如下:

Inno_setup制作更新包必須面臨的幾個問題

    更新包程式運作之後,控制台中的資訊為:

Inno_setup制作更新包必須面臨的幾個問題

    可以看到應用程式的顯示圖示和版本資訊都已經修改了,再看下系統資料庫裡面,添加了DisplayIcon字段,其它資訊也已經修改:

Inno_setup制作更新包必須面臨的幾個問題

5. 如何檢測浏覽器正在運作

     适用于目前主流浏覽器,代碼如下:

Inno_setup制作更新包必須面臨的幾個問題

6. 如何進行檔案查找及拷貝

    不管是在安裝包制作或更新包制作過程中,通常面臨着檔案的拷貝,除了[Files]段中的檔案拷貝,請看如下的查找及拷貝操作:

Inno_setup制作更新包必須面臨的幾個問題

   FileSearch('rdp.tmp' , ExpandConstant('{app}'))表示查找應用程式安裝目錄下是否存在rdp.tmp檔案,如果存在則傳回該檔案的絕對路徑,如果不存在則傳回' '

   FileCopy(ExpandConstant('{tmp}\rdp.tmp') , ExpandConstant('{app}\rdp.tmp') , false)是将臨時目錄下的rdp.tmp檔案拷貝到應用程式安裝目錄下,這裡要注意兩點:

   1> 第二個參數目标檔案,一定要帶着最終的檔案名,如果隻是一個目錄的路徑,則拷貝操作會出錯。

   2> 第三個參數為true代表如果最終檔案存在則拷貝操作失敗,如果為false則拷貝操作會覆寫原有檔案。

總結:以上就是2天的收獲,更新包制作完成。Inno_setup是個比較強大的工具,裡面還可以運作cmd指令。

相關代碼:

// 解除安裝時判斷浏覽器是否正在運作
function InitializeUninstall(): Boolean;
var
    iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer;
begin
    result:=true;
    iehWnd := FindWindowByClassName('IEFrame');
    ffhWnd := FindWindowByClassName('MozillaWindowClass');
    b360hWnd := FindWindowByClassName('360se6_Frame');
    chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
    safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');
    i := 0;
    
    while (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) do
    begin
      if i > 0 then
      begin
         Msgbox('請確定所有浏覽器都已關閉!', mbInformation, MB_OK);
      end;
      
      if Msgbox('插件更新程式檢測到浏覽器正在運作。'  #13#13 '請您先關閉所有浏覽器,單擊“是”繼續更新,否則按“否”退出安裝', mbConfirmation, MB_YESNO) = idNO then
      begin
           Result:=false;
           iehWnd :=0;
           ffhWnd :=0;
           b360hWnd :=0;
           chrhWnd :=0;
           safhWnd :=0;
      end else begin
        Result :=true;  //解除安裝程式繼續
        iehWnd := FindWindowByClassName('IEFrame');
        ffhWnd := FindWindowByClassName('MozillaWindowClass');
        b360hWnd := FindWindowByClassName('360se6_Frame');
        chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
        safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');
      end;
      i := i+1;
    end;
end;


// 檢測應用服務是否正在使用  added by houqd 2013/12/17
// 該函數利用FindWindowByWindowName(),隻能通過視窗的名字來判斷
// 不适合現在的情況,采用另一種方式判斷背景程序是否正在進行
function ifRunningDesktop():Boolean;
var
   isRunning:Integer;
   cycleCount:Integer;
begin
    Result:=true;
    cycleCount:=0;
    isRunning:=FindWindowByWindowName('有道詞典');
    while isRunning <> 0 do
    begin
        if cycleCount > 0 then
        begin
           Msgbox('請確定用戶端已關閉!', mbInformation, MB_OK);
        end;
        if MsgBox('更新程式檢測到用戶端正在運作。' #13#13 '您必須先關閉用戶端然後單擊“是”繼續安裝,或按“否”退出安裝!',mbConfirmation, MB_YESNO) = idNO then
        begin
           Result:=false;
           isRunning:=0;
        end else begin
           Result:=true;
           isRunning:=FindWindowByWindowName('VSODesktop');
        end;
        cycleCount:=cycleCount +1 ;
    end;
end;

// 判斷某個程序是否正在運作,利用安裝包裡面自帶的ISTask.dll插件
function RunTask(FileName: string; bFullpath: Boolean): Boolean;
external '[email protected]:ISTask.dll stdcall delayload';

function ifBrowserIsRunning():Boolean;
var
   iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer;
begin
    iehWnd := FindWindowByClassName('IEFrame');
    ffhWnd := FindWindowByClassName('MozillaWindowClass');
    b360hWnd := FindWindowByClassName('360se6_Frame');
    chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
    safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');

    if (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) then
    begin
       Result:=true;
    end else begin
       Result:=false;
    end;
end;


// 檢測vsodesktop程序是否正在運作,即正在打開這vso應用軟體
// added by houqd 2013/12/18
function ifVsoIsRunning():Boolean;
var
    pstate:Boolean;
begin
    Result:= RunTask('VSODesktop.exe', false);
end;


// 更新包通過修改系統資料庫,更改控制台中已安裝軟體的版本資訊
// added by houqd 2013/12/18
function updateVersion():Boolean;
var
   ResultStr:String;
   nDisplayName:String;
   nVersion:String;
begin

   Result:=true;
   nDisplayName:='{#PreDisplayName}'+'{#MyAppVersion}';
   nVersion:='{#MyAppVersion}';

   // 修改版本資訊
   if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayName',ResultStr) then
   begin
      if nDisplayName <> ResultStr then
      begin
          RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayName', nDisplayName);
      end;
   end;
   
   if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayVersion',ResultStr) then
   begin
      if nVersion <> ResultStr then
      begin
          RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayVersion', nVersion)
      end;
   end;
end;

// 更新包通過修改系統資料庫,更改控制台中已安裝軟體的顯示圖示
// added by houqd 2013/12/18
function updateDisplayIcon():Boolean;
var
  ResultStr:String;
  nDisplayIcon:String;
  installLocation:String;
begin
  Result:=true;
  
  RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','InstallLocation',installLocation);
  nDisplayIcon:=installLocation+'VSODesktop.exe';
  
  // 如果DisplayIcon該鍵值存在則說明它原本就有圖示,現在要對比更新
  if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayIcon',ResultStr) then
  begin
     if nDisplayIcon <> ResultStr then
     begin
        RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon)
     end;
  end else begin
        RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon)
  end;
end;

rdpFileExsits:=FileSearch('rdp.tmp',ExpandConstant('{app}'));    // 如果檔案存在則傳回絕對路徑,如果不存在則傳回空
      if rdpFileExsits = '' then
      begin
         Exec(ExpandConstant('{cmd}'), '/c wmic qfe get hotfixid | find "KB2592687" > '+ExpandConstant('{tmp}\rdp.tmp'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
         FileCopy(ExpandConstant('{tmp}\rdp.tmp'),ExpandConstant('{app}\rdp.tmp'),false);
      end;
           

         加油,堅持每天的學習,少年!

繼續閱讀