Pengaturan Inno: Bagaimana cara menghapus instalasi versi sebelumnya secara otomatis?

90

Saya menggunakan Pengaturan Inno untuk membuat penginstal.

Saya ingin penginstal mencopot pemasangan versi sebelumnya secara otomatis, alih-alih menimpanya. Bagaimana saya bisa melakukan itu?

Quan Mai
sumber
2
Perhatikan bahwa seperti yang dikatakan mlaan biasanya tidak perlu melakukan ini dengan penyiapan berbasis Inno kecuali Anda meningkatkan dari versi non Inno.
Deanna
7
Deanna: tergantung kasusnya. Untuk beberapa program dengan sistem plugin otomatis, yang membaca apa pun di dalam folder, penghapusan file lama adalah hal yang mutlak ketika menginstal versi baru, dan menjalankan uninstall biasanya merupakan cara terbersih untuk melakukan ini.
Nyerguds
1
@Nyerguds Tetapi InnoSetup melayani itu dengan memiliki opsi untuk menghapus file / folder tertentu sebelum instalasi dimulai (tanda "InstallDelete") sehingga Anda masih tidak perlu menghapus versi lama terlebih dahulu.
NickG
3
@NickG: Sekali lagi, tergantung kasusnya. Itu akan menjadi situasi yang ideal, ya, dan sejauh ini yang disukai, tetapi dalam kenyataannya, ada cukup banyak situasi yang tidak ideal. Salah satu contohnya adalah file dll terdaftar, pada banyak versi target yang mungkin.
Nyerguds

Jawaban:

28

Anda harus bisa membaca uninstall string dari registri, mengingat AppId (yaitu nilai yang Anda digunakan untuk AppIDdi [Setup]-bagian). Ini dapat ditemukan di bawah Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\(bisa jadi salah satu HKLMatau HKCU, jadi sebaiknya periksa keduanya) di mana {AppId}harus diganti dengan nilai sebenarnya yang Anda gunakan. Cari UninstallStringatau QuietUninstallStringnilai dan gunakan Execfungsi untuk menjalankannya dari InitializeSetup()fungsi acara Anda .

Pembaruan: hapus solusi alternatif yang tidak berfungsi menggunakan [Run]entri -bagian dengan {uninstallexe}- terima kasih kepada semua pemberi komentar yang menunjukkan hal ini!

Oliver Giesen
sumber
+1, tetapi pasti menggunakan skrip untuk membaca nama uninstaller lama, karena jika tidak, itu tidak akan berfungsi jika jalur yang berbeda telah dimasukkan oleh pengguna.
mghie
3
Saya tidak berpikir [Run]solusi bagian akan berfungsi, karena terlambat dalam proses instalasi. Dari panduan Inno Setup: Bagian [Run] adalah opsional, dan menentukan sejumlah program yang akan dijalankan setelah program berhasil diinstal, tetapi sebelum program Setup menampilkan dialog terakhir.
Craig McQueen
Harap edit posting ini dan hapus bagian [Jalankan], itu tidak berfungsi. Bagian kedua berhasil. Terima kasih :-)
Saulius Žemaitaitis
11
Satu peringatan: untuk aplikasi 32 bit pada Windows 64 bit, jalurnya mungkin `Software \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall \ {AppId}`
Adrian Cox
4
@ Adrian: Meskipun itu mungkin benar pada lapisan fisik, saya pikir panggilan WinAPI yang digunakan oleh Inno sudah akan mengurusnya - setidaknya jika setup.exe itu sendiri adalah proses 32bit.
Oliver Giesen
114

Saya telah menggunakan yang berikut ini. Saya tidak yakin ini cara termudah untuk melakukannya tetapi berhasil.

Penggunaan ini {#emit SetupSetting("AppId")}bergantung pada Inno Setup Preprocessor. Jika Anda tidak menggunakannya, potong dan tempel ID Aplikasi Anda secara langsung.

[Code]

{ ///////////////////////////////////////////////////////////////////// }
function GetUninstallString(): String;
var
  sUnInstPath: String;
  sUnInstallString: String;
begin
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
  sUnInstallString := '';
  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
  Result := sUnInstallString;
end;


{ ///////////////////////////////////////////////////////////////////// }
function IsUpgrade(): Boolean;
begin
  Result := (GetUninstallString() <> '');
end;


{ ///////////////////////////////////////////////////////////////////// }
function UnInstallOldVersion(): Integer;
var
  sUnInstallString: String;
  iResultCode: Integer;
begin
{ Return Values: }
{ 1 - uninstall string is empty }
{ 2 - error executing the UnInstallString }
{ 3 - successfully executed the UnInstallString }

  { default return value }
  Result := 0;

  { get the uninstall string of the old app }
  sUnInstallString := GetUninstallString();
  if sUnInstallString <> '' then begin
    sUnInstallString := RemoveQuotes(sUnInstallString);
    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

{ ///////////////////////////////////////////////////////////////////// }
procedure CurStepChanged(CurStep: TSetupStep);
begin
  if (CurStep=ssInstall) then
  begin
    if (IsUpgrade()) then
    begin
      UnInstallOldVersion();
    end;
  end;
end;

Alternatif

Lihat juga entri blog ini "Contoh Skrip Pengaturan Inno untuk Perbandingan Versi" yang melangkah lebih jauh, dan membaca nomor versi dari versi yang diinstal sebelumnya, dan membandingkan nomor versi itu dengan nomor versi paket penginstalan saat ini.

Craig McQueen
sumber
3
terima kasih telah merujuk ke posting blog saya. Contoh lengkap untuk posting itu tersedia di sini, code.google.com/p/lextudio/source/browse/trunk/trunk/setup/…
Lex Li
Satu-satunya hal yang hilang di sini adalah dukungan untuk entri Uninstall di bawah HKCU, bukan HKLM.
Oliver Giesen
1
Bolehkah saya menyarankan menambahkan kemampuan untuk mencopot pemasangan jika ada pengguna yang memasang aplikasi, terutama jika pengguna saat ini adalah Administrator? ... UserSIDs: TArrayOfString; I: Integer; ... if not RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString) then if isAdminLoggedOn() and RegGetSubkeyNames( HKEY_USERS, '', UserSIDs ) then for I := 0 to GetArrayLength( UserSIDs ) - 1 do begin if RegQueryStringValue( HKEY_USERS, UserSIDs[I] + '\' + sUnInstPath, 'UninstallString', sUnInstallString ) then break; end;
Terrance
2
Solusi hebat, berfungsi dengan baik. Namun itu membuka jendela selama instalasi yang menunjukkan "Menghapus instalasi [nama perangkat lunak]". Apakah mungkin mencegah jendela ini muncul? Karena penginstalan perangkat lunak saya sangat cepat sehingga jendela penginstalan ditutup sebelum jendela penginstalan dan terlihat aneh ...
André Santaló
4
@ AndréSantaló Gunakan / VERYSILENT sebagai pengganti / SILENT
Gautam Jain
7

Jika Anda "hanya ingin menghapus ikon lama" (karena milik Anda telah diubah / diperbarui) Anda dapat menggunakan ini:

; attempt to remove previous versions' icons
[InstallDelete]
Type: filesandordirs; Name: {group}\*;

Ini dijalankan "pada awal penginstalan" jadi pada dasarnya menghapus ikon lama, dan yang baru akan tetap dipasang di sana setelah ini selesai.

Saya hanya melakukan ini dengan setiap penginstalan ikon "jika ada yang berubah" (semuanya tetap diinstal ulang).

rogerdpack
sumber
Jika Anda memiliki pembaruan untuk ikon Anda, biarkan mereka menimpa. Tidak perlu menghapusnya. Nah, jika Anda ingin menghapusnya, Anda bisa menggunakan opsi ini. Itu cara yang benar. Bagaimanapun, pria yang Anda ajak bicara (mlaan, Martijn Laan) adalah penulis Inno Setup dan saya pikir dia tahu apa yang dia bicarakan :-)
TLama
1
Ya, saat Anda ingin mengganti nama atau memindahkan ikon yang Anda butuhkan ini. Misalnya jika v5 memiliki satu bernama "run" dan v6 telah mengganti namanya menjadi "run basic" jika pengguna menginstal v5 lalu v6, mereka akan mendapatkan 2 ikon, padahal Anda benar-benar menginginkan 1 ("run basic"). Jadi trik ini akhirnya diperlukan (@mlaan +1 untuk mengubah perilaku default innosetup menjadi menghapus ikon lama dan tidak membutuhkan ini ...)
rogerdpack
6

Saat menggunakan Inno Setup, tidak ada alasan untuk menghapus versi sebelumnya kecuali versi tersebut diinstal oleh program penginstal yang berbeda. Jika tidak, peningkatan akan ditangani secara otomatis.

mlaan
sumber
7
Program kami mengalami perubahan struktur, jadi versi lama perlu dicopot pemasangannya.
Quan Mai
11
Tidak, Anda dapat menambahkan entri ke skrip Anda untuk menangani perubahan struktur selama pembaruan.
mlaan
@mlaan Dan apa entri itu?
Mythofechelon
1
Anda cukup menggunakan [InstallDelete]bagian untuk menghapus file / direktori lama. File baru kemudian akan ditempatkan di lokasi yang benar selama instalasi.
daiscog
2
Jika Anda memutakhirkan pustaka pihak ketiga seperti DevExpress, yang memiliki nomor versi dalam nama DLL (seperti 15.1 diinstal sebelumnya dan 15.2 sekarang) maka Anda ingin menghapus versi lama. IMHO itu alasan yang bagus.
Thomas Weller
2

Jawaban yang diberikan oleh Craig McQueen benar-benar layak. Meskipun, saya akan menambahkan komentar itu:

  • The {#emit SetupSetting("AppId")}kode tidak bekerja untuk saya, jadi saya hanya menambahkan saya App ID.
  • Saya tidak ingin menjalankan program penghapusan saya, karena saya memiliki file konfigurasi INI yang disimpan di folder AppData / yang dihapus oleh uninstaller, dan saya tidak ingin menghapusnya saat menginstal versi baru. Jadi, saya memodifikasi sedikit kode yang disediakan oleh Craig McQueen untuk menghapus direktori tempat menginstal program, setelah mengambil jalurnya.

Jadi, terkait kode Craig McQueen, perubahannya adalah:

  • Ambil InstallLocationkunci, bukan UninstallStringkunci.
  • Gunakan DelTreefungsi alih-alihExec(sUnInstallString, ...)

sumber
1

Bagi siapa pun yang menggunakan yang GetUninstallString()disarankan di atas untuk memaksa uninstall di dalam CurStepChanged()dan memiliki masalah cache disk, lihat di bawah untuk solusi terkait yang benar-benar menunggu beberapa saat setelah unistallation untuk uninstaller exe untuk dihapus!

Masalah cache disk dengan inno-setup?

fubar
sumber
0

Anda dapat menjalankan uninstaller di bagian [code]. Anda harus mencari cara untuk mendapatkan path ke uninstaller yang ada. Untuk mempermudah ketika saya menginstal aplikasi saya, saya menambahkan nilai string registri yang mengarah ke folder yang berisi uninstaller, dan hanya menjalankan uninstaller di callback InitializeWizard.

Perlu diingat bahwa nama uninstaller penyiapan Inno semuanya dalam bentuk uninsnnn.exe, Anda harus memperhitungkannya dalam kode Anda.

Jim In Texas
sumber
0

Saya mendapat kode @Crain Mc-Queen diedit, saya pikir kode ini lebih baik karena tidak perlu dimodifikasi di proyek yang berbeda:

[Code]
function GetNumber(var temp: String): Integer;
var
  part: String;
  pos1: Integer;
begin
  if Length(temp) = 0 then
  begin
    Result := -1;
    Exit;
  end;
    pos1 := Pos('.', temp);
    if (pos1 = 0) then
    begin
      Result := StrToInt(temp);
    temp := '';
    end
    else
    begin
    part := Copy(temp, 1, pos1 - 1);
      temp := Copy(temp, pos1 + 1, Length(temp));
      Result := StrToInt(part);
    end;
end;

function CompareInner(var temp1, temp2: String): Integer;
var
  num1, num2: Integer;
begin
    num1 := GetNumber(temp1);
  num2 := GetNumber(temp2);
  if (num1 = -1) or (num2 = -1) then
  begin
    Result := 0;
    Exit;
  end;
      if (num1 > num2) then
      begin
        Result := 1;
      end
      else if (num1 < num2) then
      begin
        Result := -1;
      end
      else
      begin
        Result := CompareInner(temp1, temp2);
      end;
end;

function CompareVersion(str1, str2: String): Integer;
var
  temp1, temp2: String;
begin
    temp1 := str1;
    temp2 := str2;
    Result := CompareInner(temp1, temp2);
end;

function InitializeSetup(): Boolean;
var
  oldVersion: String;
  uninstaller: String;
  ErrorCode: Integer;
  vCurID      :String;
  vCurAppName :String;
begin
  vCurID:= '{#SetupSetting("AppId")}';
  vCurAppName:= '{#SetupSetting("AppName")}';
  //remove first "{" of ID
  vCurID:= Copy(vCurID, 2, Length(vCurID) - 1);
  //
  if RegKeyExists(HKEY_LOCAL_MACHINE,
    'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1') then
  begin
    RegQueryStringValue(HKEY_LOCAL_MACHINE,
      'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1',
      'DisplayVersion', oldVersion);
    if (CompareVersion(oldVersion, '{#SetupSetting("AppVersion")}') < 0) then      
    begin
      if MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. Continue to use this old version?',
        mbConfirmation, MB_YESNO) = IDYES then
      begin
        Result := False;
      end
      else
      begin
          RegQueryStringValue(HKEY_LOCAL_MACHINE,
            'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1',
            'UninstallString', uninstaller);
          ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
          Result := True;
      end;
    end
    else
    begin
      MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. This installer will exit.',
        mbInformation, MB_OK);
      Result := False;
    end;
  end
  else
  begin
    Result := True;
  end;
end;
MohsenB
sumber
-1

Saya pasti melewatkan sesuatu. File baru disalin ke direktori target sebelum penghapusan instalasi lama terjadi. Kemudian datang uninstaller menghapusnya dan menghapus direktori.

Shaul
sumber
2
Saya tidak yakin apa yang Anda coba katakan, tetapi perhatikan bahwa ini tidak selalu hanya tentang menyalin file. Bayangkan Anda telah menginstal produk Anda, yang dengan rilis berikutnya hadir dengan struktur file yang benar-benar berubah, di mana banyak dari file asli telah dihapus dan file baru memiliki nama yang berbeda dan disimpan di direktori yang berbeda. Apa cara termudah untuk meningkatkan? Bukankah itu akan menghapus versi sebelumnya?
TLama
Saya menggunakan INNO untuk menginstal driver dan aplikasi yang menyertainya. Secara alami, Instalasi / Penghapusan driver yang sebenarnya tidak dilakukan secara langsung oleh INNO. Sebaliknya, INNO menyalin aplikasi penginstal / penghapus driver lalu menjalankannya. Penghapusan instalasi dilakukan dengan cara yang sama: INNO menjalankan driver remover, lalu menghapus file.
Shaul
-8

Jangan gunakan bagian [Run], tetapi [UninstallRun]. Sebenarnya, program di bawah [Run] dijalankan setelah penginstalan, menyebabkan penginstalan program Anda segera setelah penginstalan: - | Sebaliknya, bagian [UninstallRun] dievaluasi sebelum instalasi.

Andrea Ferroni alias bubbakk
sumber
3
[UninstallRun]bukanlah solusi untuk pertanyaan tersebut.
Craig McQueen
-8

Ikuti tautan ini: http://news.jrsoftware.org/news/innosetup/msg55323.html

Dalam fungsi InitializeSetup (), Anda dapat memanggil "MSIEXEC / x {ID program Anda}" setelah pengguna meminta untuk menghapus versi lama

Tonny Nguyen
sumber
5
MSIEXEC hanya berfungsi untuk paket MSI. Itu tidak berlaku untuk Inno Setup.
Lex Li