W Visual Studio Express Edition nie ma możliwości tworzenia plików instalacyjnych dla naszych projektów. Przynajmniej takiej funkcji nie znalazłem. Pomoże nam w tym program Inno Setup Compiler. Przede wszystkim jest to darmowe narzędzie do tworzenia instalatorów.
UWAGA! Ten post został zamieszczony na mojej starej stronie, która dawno temu padła. Inno Setup używałem bardzo dawno temu, ale archiwizuje stare artykuły, może kiedyś się przydadzą. Także, proszę z rezerwą podchodzić do treści tu zwartych.
Jeżeli nie ma potrzeby tworzenia rozbudowanego instalatora – to kreator w Inno Setup pomoże zrobić nam plik wykonywalny w minutę. Jednakże, jeżeli ktoś oczekuje dodatkowych funkcji, wtedy trzeba użyć języka Pascal, aby zbudować instalator.
Projekt, który stworzyłem w Visual Studio Express Edition w języku Visual Basic wymagał 3 rzeczy:
1. sprawdzenia czy na komputerze zainstalowany jest Net.Framework >= 3.5,
2. sprawdzenia czy na komputerze zainstalowany jest SQL SERVER CE 4.0,
3. możliwości usunięcia poprzedniej wersji w przypadku instalacji nowej.
Także mój instalator sprawdza, czy Net.Framework i SQL SERVER są zainstalowane. Co więcej instalator, daje możliwość pobrania plików bezpośrednio ze stron Microsoftu. Gdy instalator sprawdzi, czy w/w dwie aplikacje są zainstalowane, sprawdza czy czy mój program nie jest na komputerze zainstalowany. Jeżeli tak, user ma możliwość odinstalowania starej wersji. Inno Setup (przynajmniej tak czytałem?) nie rozróżnia numeracji naszego programu, po prostu widzi, że nasz program jest zainstalowany.
Zwracam uwagę na AppId. Jeżeli stworzymy nową wersję naszego programu, AppId musi być zbieżny z poprzednią wersją:
AppId={{809B9E8D-0216-4263-83D9-B2A87E4AB658}
W kodzie mojego instalatora AppId występuje w dwóch miejscach, tam gdzie instalator sprawdza czy starsza wersja jest zainstalowana:
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{809B9E8D-0216-4263-83D9-B2A87E4AB658}_is1'); //Your App GUID/ID
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{809B9E8D-0216-4263-83D9-B2A87E4AB658}_is1', 'UninstallString') then //Your App GUID/ID
Dodatkowo ważnym fragmentem instalatora jest sekcja [Dirs]. Pozwala nam ona instalować program na koncie ograniczonym w Windows. Dzięki [Dirs] Windows zapyta się o hasło admina z prośbą o instalację programu.
[Dirs] Name: "{app}\"; Permissions: everyone-modify
Niestety, nie pamiętam skąd pobrałem kod (nie znam Pascala) do sprawdzania czy Net.Framework i SQL SERVER CE są zainstalowane. Usuwanie poprzedniej wersji wziąłem z tej strony:
http://stackoverflow.com/questions/11739317/how-to-detect-old-installation-and-offer-removal
W stosunku do oryginalnego kodu, odhaczyłem jako tekst następujący fragment kodu:
//sUnInstallString := GetUninstallString();
Usunięcie tego fragmentu było podyktowane tym, że gdy instalator wykrywał poprzednią wersję, to zadawał pytanie czy na pewno chce odinstalować program. Było to bez sensu bo wcześniej pada pytanie o odinstalowanie poprzedniej wersji.
Oczywiście podstawowy kod został stworzony przez kreatora w Inno Setup, by później odpowiednio go zmodyfikować. Poniżej cały kod w Inno Setup do stworzenie mojego instalatora:
; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "Nazwa mojej aplikacji" #define MyAppVersion "1.1.0.0" #define MyAppPublisher "Pawel Bartkowiak" #define MyAppURL "http://localhost/pawelbartkowiak/_public_html/wordpress/" #define MyAppExeName "NazwaInstalatora.exe" [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{809B9E8D-0216-4263-83D9-B2A87E4AB658} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={pf}\{#MyAppName} DefaultGroupName={#MyAppName} AllowNoIcons=yes OutputBaseFilename=GeneratorSetupRozszerzony_wer1100Final Compression=lzma SolidCompression=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\Pawel\Documents\Visual Studio 2012\Projects\Nazwa Projektu\bin\Debug\Instalator.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "C:\Users\Pawel\Documents\Visual Studio 2012\Projects\Nazwa Projektu\bin\Debug\BazaGrzejniki.sdf"; DestDir: "{app}"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Dirs] Name: "{app}\"; Permissions: everyone-modify [CustomMessages] dotnetmissing1=Minimum Microsoft .NET Framework 3.5 jest wymagany. Czy chcesz go teraz pobrac? dotnetmissing2=SQL SERVER CE 4.0 jest wymagany. Czy chcesz go teraz pobrac? [code] function CheckDotNetFx(): Boolean; begin Result:= RegKeyExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5'); end; function CheckSSCE(): Boolean; begin Result:= RegKeyExists(HKLM, 'SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v4.0'); end; function CheckIsReady(): Boolean; begin Result:= CheckDotNetFx() and CheckSSCE(); end; function GetUninstallString: string; var sUnInstPath: string; sUnInstallString: String; begin Result := ''; sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{809B9E8D-0216-4263-83D9-B2A87E4AB658}_is1'); //Your App GUID/ID 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 InitializeSetup(): Boolean; var Path:string; //ResultCode: Integer; ErrorCode: Integer; V: Integer; iResultCode: Integer; sUnInstallString: string; begin // Sprawdzanie czy >= net.framework 3.5 jest zainstalowany if not CheckDotNetFx() then begin if (MsgBox(ExpandConstant('{cm:dotnetmissing1}'), mbConfirmation, MB_YESNO) = idYes)then begin ShellExec('open', 'http://www.microsoft.com/pl-pl/download/details.aspx?id=22', '','',SW_SHOWNORMAL,ewNoWait,ErrorCode); end; result := false; end; // Sprawdzanie czy SQL SERVER CE 4.0 jest zainstalowany if not CheckSSCE() then begin if (MsgBox(ExpandConstant('{cm:dotnetmissing2}'), mbConfirmation, MB_YESNO) = idYes)then begin ShellExec('open', 'http://www.microsoft.com/pl-pl/download/details.aspx?id=17876', '','',SW_SHOWNORMAL,ewNoWait,ErrorCode); end; result := false; end; Result := CheckIsReady(); // http://stackoverflow.com/questions/11739317/how-to-detect-old-installation-and-offer-removal begin Result := True; // in case when no previous version is found if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{809B9E8D-0216-4263-83D9-B2A87E4AB658}_is1', 'UninstallString') then //Your App GUID/ID begin V := MsgBox(ExpandConstant('Wykryto stara wersje programu, ktora powinna zostac usunieta. Czy chcesz ja teraz odinstalowac?'), mbInformation, MB_YESNO); //Custom Message if App installed if V = IDYES then begin //sUnInstallString := GetUninstallString(); sUnInstallString := RemoveQuotes(sUnInstallString); Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode); Result := True; //if you want to proceed after uninstall //Exit; //if you want to quit after uninstall end else Result := False; //when older version present and not uninstalled end; end; end; [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent