For the project I am working on, I am not allowed to use ClickOnce. My boss wants the program to look "real" (with an installer, etc).
I have installed Visual Studio 2012 Professional, and have been playing around with the InstallShield installer, and it definitely makes nice installers, but I can't figure out how to enable the application to "auto-update" (that is, when it starts up, checks to make sure that it is using the latest version).
I have been asked to make a tiny change to the code - switching an addition to a subtraction, and I don't really want people to have to uninstall the old version, and then have to reinstall the new version every time I make a small change like this.
How can I make the application check for updates, and install them? Or is this not possible (or not easy)?
There are a lot of questions already about this, so I will refer you to those.
One thing you want to make sure to prevent the need for uninstallation, is that you use the same upgrade code on every release, but change the product code. These values are located in the Installshield project properties.
Some references:
Auto update .NET applications
Auto-update library for .NET?
Auto update for WinForms application
Suggest a method for auto-updating my C# program
Automatic update a Windows application
I think you should check the following project at codeplex.com
http://autoupdater.codeplex.com/
This sample application is developed in C# as a library with the project name “AutoUpdater”. The DLL “AutoUpdater” can be used in a C# Windows application(WinForm and WPF).
There are certain features about the AutoUpdater:
Easy to implement and use.
Application automatic re-run after checking update.
Update process transparent to the user.
To avoid blocking the main thread using multi-threaded download.
Ability to upgrade the system and also the auto update program.
A code that doesn't need change when used by different systems and
could be compiled in a library.
Easy for user to download the update files.
How to use?
In the program that you want to be auto updateable, you just need to call the AutoUpdate function in the Main procedure. The AutoUpdate function will check the version with the one read from a file located in a Web Site/FTP. If the program version is lower than the one read the program downloads the auto update program and launches it and the function returns True, which means that an auto update will run and the current program should be closed. The auto update program receives several parameters from the program to be updated and performs the auto update necessary and after that launches the updated system.
#region check and download new version program
bool bSuccess = false;
IAutoUpdater autoUpdater = new AutoUpdater();
try
{
autoUpdater.Update();
bSuccess = true;
}
catch (WebException exp)
{
MessageBox.Show("Can not find the specified resource");
}
catch (XmlException exp)
{
MessageBox.Show("Download the upgrade file error");
}
catch (NotSupportedException exp)
{
MessageBox.Show("Upgrade address configuration error");
}
catch (ArgumentException exp)
{
MessageBox.Show("Download the upgrade file error");
}
catch (Exception exp)
{
MessageBox.Show("An error occurred during the upgrade process");
}
finally
{
if (bSuccess == false)
{
try
{
autoUpdater.RollBack();
}
catch (Exception)
{
//Log the message to your file or database
}
}
}
#endregion
The most common way would be to put a simple text file (XML/JSON would be better) on your webserver with the last build version. The application will then download this file, check the version and start the updater. A typical file would look like this:
Application Update File (A unique string that will let your application recognize the file type)
version: 1.0.0 (Latest Assembly Version)
download: http://yourserver.com/... (A link to the download version)
redirect: http://yournewserver.com/... (I used this field in case of a change in the server address.)
This would let the client know that they need to be looking at a new address.
You can also add other important details.
A Lay men's way is
on Main() rename the executing assembly file .exe to some thing else
check date and time of created.
and the updated file date time and copy to the application folder.
//Rename he executing file
System.IO.FileInfo file = new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
System.IO.File.Move(file.FullName, file.DirectoryName + "\\" + file.Name.Replace(file.Extension,"") + "-1" + file.Extension);
then do the logic check and copy the new file to executing folder
This is the code to update the file but not to install
This program is made through dos for copying files to the latest date and run your program automatically. may help you
open notepad and save file below with ext .bat
xcopy \\IP address\folder_share_name\*.* /s /y /d /q
start "label" /b "youraplicationname.exe"
These days you could use included in Windows 10 mechanism for app delivery called AppInstaller by packaging your app in MSIX bundle or package.
With it, you don't have to think about an installer (if your app doesn't use a lot of dependencies), background updating, and all of that. It's much better than ClickOnce, command-line usage works like a charm thanks to aliases, updates are non-obtrusive and could be used for background apps too.
The installation experience is much better too: a user just needs to click a button on HTML and Windows will install the app automatically.
It's not super-simple, I'd say more complicated than ClickOnce, but not as hard as Wix.
Official guide doesn't work with .NET Core or .NET 5 apps, so you can refer to this article, or to this great video, for example. This site also contains a lot of useful information.
To make my console application launch after install I have added an installer class to my project.
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(this.Context.Parameters["AssemblyPath"]) + #"\MyAppName.exe");
}
I have added custom actions to my SetupProject (shortcut to Primary output MyApp.exe under Install and Commit) to execute launch after install and it does launch the app.
However when the app launches after install, and Main() runs UserPrincipal.Current.EmailAddress; I get this error:
Unable to cast object of type
'System.DirectoryServices.AccountManagement.GroupPrincipal'
to type 'System.DirectoryServices.AccountManagement.UserPrincipal'.
(This is on my workplace network by the way).
Now if I go to the application folder and run the .exe.... it works.
So my question is: what is it about the "run after install" method that's making this happen and how can I fix it?
I've tried almost every corner of the internet but cant get my head around this and many other solutions haven't worked.
I've tried solutions from this SO post with no luck.
I've tried getting the email address from outlook instead but I get a different error (which doesnt happen during debug or from clicking the .exe).
I have done a test Win service to make sure I have the Installer project (which is the part of that project and is set to InstallShield Limited by default) works fine.
I've searched for the correct manual and did the same as it was suggested:
Pls, see the WinService Installation class definition:
Then I tried both ways
1)
2)
Then I successfully build the Installation project and get the setup package..
As you can see everything is set to be installed under the Local user..
But each time I run the installation pask it asks for credentials..
My question is: how to avoid that dialog during installation?
Actually, I found the solution by myself.
The start point should be: To make yourself sure that the service is installable manually using InstallUtil.
In my case I mistakenly named ServiceName in AfterInstall event, when engaged Service Controller.. missed letter "1"
private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
using (ServiceController sc = new ServiceController(serviceInstaller1.ServiceName))
{
sc.Start();
}
}
After that I changed the settings in InstallShield Project..
1) I dropped the added service at screen Way#1
2) Add InstallClass as it shown on Way#2
The request of the credential was because inside the service itself, I missed setting LocalSystem for Property Account of Service Process Installer in the Design Mode.
So, now it works..
I have found that on un-installing myproject setup installer is removing all files but not one conn.cnf file .I want it to be removed too . so I used custom Actions installer class.but it is not removing that file .
this is my code
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Uninstall(IDictionary savedState)
{try
{
base.Uninstall(savedState);
if (System.IO.File.Exists(Application.StartupPath + "\\Conn.cnf"))
System.IO.File.Delete(Application.StartupPath + "\\Conn.cnf");
}
catch (Exception es) { MessageBox.Show(es.Message); }
}
i have tested if cursor is going in this block or not, by putting a messageBox. which is being execute on un-installation .I have also checked file name ,am i trying to delete file in a wrong way ? Help me. thanks
This is quite difficult to find out the application path. Actually its not an application path its installation directory. When you try to find Application path using Application.StartupPath. You may get C:\System or something like that directory. Because your application is using Windows Installer to uninstall and install the application from the computer and the Windows Installer is installed in System folder. You should try to find Target Directory instead of Application or Executable path.
You can get the Target Directory from the Context Parameter like this.
string targetFolder = Context.Parameters["TARGETDIR"];
I have a solution with 3 modules. Windows, Web, and Windows Service. I want to create one parent setup that runs three child setup packages regarding to the user choose.
I created a setup project as the following:
I created a library that contains InstallerHelper which is inherited from Installer class
I added the following code:
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
FileInfo fileInfo = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
string sProgram = Path.Combine(fileInfo.DirectoryName, "Setup1.msi");
Process p = Process.Start(sProgram);
p.WaitForExit();
}
catch (Exception exc)
{
Context.LogMessage(exc.ToString());
throw;
}
}
The problem is that the windows installer refuses to run multiple instances of windows installer and throws the following error:
Another installation is in progress. You must complete that
installation before continuing this one.
Is my approach correct? Is ther another way to run another setup and the parent setup should wait all of them with one Finish click?.
You can use Wix Burn to create a setup package contained multiple application installers (msi/exe):
Wix Toolset: Building Installation Package Bundles
Neil Sleightholm's Blog: WiX Burn – tips/tricks