Creating an auto updating Windows service [duplicate] - c#

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.

Related

Restore Previous State of app on database migration failure (ClickOnce)

I want to restore previous version of C# application published using ClickOnce, if database migration fails because database wont be latest and it will not support latest version of application.
Details
I am developing an app which will be used locally in remote areas where internet is not available. A person will update his/her app every once in a while by getting internet somehow and then will deploy the app on local network. From there every one will be able to get the updated version of app. What I want now is to use database migration using this app and if the app fails It should restore to previous version. I have already used FluentMigrator for database migration and have used ClickOnce to deploy the app. I have also gone through almost every link over here to see how can I do it. I now know that its not possible using ClickOnce. Can anybody tell me some other way or may be some kind of hack?. I am using ClickOnce because of its auto update feature so don't really want to lose that functionality now. Any help will be appreciated.
FluentMigrator keeps track of current version in the database. It also keeps track of latest version in the current app version. Run Migrator function and check if the latest version of Migration files in the current version is equal to the latest version stored in a database. If both are equal then Migration was successful. If they are not equal then you can run the cmd command to directly open (remove or backup) window of the control panel and go to the previous version. This is the best you can do to revert to the previous version using ClickOnce.
try {
new MigrationsWrapper(AppManager.ConnectionString).MigrateToLatestVersion();
}
catch (Exception ex)
{
}
LatestVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).LatestVersionNumber;
CurrentVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).CurrentVersionNumber;
if (LatestVersionNumber > CurrentVersionNumber) {
string applicationName = ConfigurationManager.AppSettings["ApplicationName"].ToString();
string uninstallString = GetUninstallRegistryKeyByProductName(applicationName);
if (uninstallString != string.Empty) {
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c " + uninstallString;
process.StartInfo = startInfo;
process.Start();
}
} else {
// Successfull
}
So, you want to run previous version of the app if some problem happen during execution.
I don`t know solution for ClickOnce, but there is analogue for it - Squirrel.
Bad news that Squirrel has no straight solution too, but it phisically stores previous version of app and you can run it and it works (I just checked it on my app).
So, there is a strategy:
Migrate to the squirrel (they have a tool for it)
in case of emergency - calc path to the stored previous version and run it. Relative path should be like "../app-1.1.1/myApp.exe"
But there is one thing to keep in mind. Squirrel stores previous version only if it upgraded app from it. There is no prev version after first install.
Good luck.
From the description the different versions of the application are sharing a single database. As a new version of the application goes live on the machine it needs to patch/migrate a shared database. If that fails the application doesn't install. Let's hope it fails without corrupting the database also.
There are clickonce events that can be hoocked into. Create a Custom Installer maybe.
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment_events.aspx
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.aspx
Publishing ClickOnce Applications
https://msdn.microsoft.com/en-us/library/748fh114.aspx
Walkthrough: Creating a Custom Installer for a ClickOnce Application
https://msdn.microsoft.com/en-us/library/dd997001.aspx
Hope that's helpful.

How can I conditionally run my program in 64 bit or 32 bit mode based on external resources?

There are a few questions (and unwanted answers) all over the forums about Microsoft.ACE.OLEDB.12.0 provider not being registered on the local machine, like this one. The gist of the problem, how I understand it, is that the application will look for the provider on the same platform as what the application is running on. So if your computer is 64 bit and the provider 32 bit, then there will be a mismatch if you don't compile the application to run in 32 bit mode.
Most answers effectively deal with this by installing the appropriate data components for the current platform. Other suggestions are to compile for whichever platform the data components are available.
I am developing an app using PCs running Windows 7, 8 and 10, all 64 bit, depending on where I am, but some have older versions of Office and others newer versions. This causes me to have to change the platform for which I compile depending on the PC I currently work on. While this is no problem for me, personally, I foresee this causing headaches for the end users not being able to run the program.
Trying to avoid asking users to install other components on their computers; is there a way I can tell the program to check the platform availability of the database provider and then run in that mode? Might it be possible to create 32 bit and 64 bit extensions of the database module and load the appropriate one regardless of the mode the main program is running in?
EDIT:
I just tried to compile my database extensions on different platforms Whichever one that is not the same platform as the application causes an exception when being loaded saying that I am attempting to load an assembly from a different platform. So I guess I'm out of luck with my option 2...
You can use CorFlags utility to modify your executable on target machine, after you will detect which mode it needs to run.
First ensure that your main exe is compiled under any cpu with Prefer 32 bit flag not set. Now when application is started you need to check if we are in 64-bit process or not, and also check your dependencies (this I won't cover - I don't work with OLEDB). If you found mismatch (say you are running in 64-bit process but your dependencies are 32-bit) - you need to run external process to modify your main executable and then restart it. Easiest way to do it is via simple cmd script, like this (in this example my main exe is called ConsoleApplication3.exe):
:start
start /wait "" "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\CorFlags.exe" ConsoleApplication3.exe /32BIT+
if errorlevel 1 (
goto start
)
start "" ConsoleApplication3.exe
Note that this is just example and if something goes wrong it will fall into endless loop, adjust to your requirements. What this script does is just updates your exe using CorFlags tool to run in 32-bit mode, then starts your main exe.
Right after starting your application, you might do the following check:
static void Main() {
if (Environment.Is64BitProcess) {
// here you also check if you have dependency mismatch, and then:
Console.WriteLine("Running in 64-bit mode. Press any key to fix");
Console.ReadKey();
// run script (here we assume script is in the same directory as main executable, and is called fix-mode.cmd
var process = new Process() {
StartInfo = new ProcessStartInfo("cmd.exe", "/c call fix-mode.cmd")
};
process.Start();
// here you should exit your application immediatly, so that CorFlags can update it (since it cannot do that while it is running)
}
else {
// after restart by our script - we will get here
Console.WriteLine("Running in 32bit mode");
}
}
Note that this tool (CorFlags) is available only with Visual Studio so you may want to pack it together with your application (might be not available on remote machine).

.net application won't run on developer machine but works on visual studio

First of all I want to apologise if this question was answered before, I've searched but I didn't find anything [maybe didn't searched correctly]
I've developed a very simple console application, which doesn't do anything else but display a random number from 2 integers.
Code:
int miNumber;
int mNumber;
bool ok = false;
try
{
miNumber = Convert.ToInt32(minNumber);
mNumber = Convert.ToInt32(maxNumber);
ok = true;
}
catch (Exception)
{
Console.WriteLine("Only digits allowed!");
Console.ReadKey();
ok = false;
}
if(ok)
{
// Generate
var x = new Random();
Console.WriteLine(string.Format("Generated number from {0} and {1} is {2}", miNumber, mNumber, x.Next(miNumber, mNumber)));
}
However, this application works on:
Developer machine if runned with visual studio [debug]
Another PC with .NET 4.0 installed.
My laptop
This application does not work on:
My own computer. If I copy test.exe in another location, it won't run.
I'm sure that I got .NET 4.0 since I run on Windows 8.1, I even tried to install it again but it says I already have it. [Anyways the Visual Studio could'nt make application in .net 4.0 if there wasn't the framework installed]
I've checked Event Viewer and I ain't see anything displayed such as error or something inputted by the system at the moment the application was run.
I tried:
Running the application from CMD [Stucks] [Screenshot added] Screenshot
Running the application from explorer.exe [Stucks and displays the loading cursor like forever]
If I close the console application displayed, the executable is still running. I tried to kill it from CMD using 'taskkill /f /im test.exe' with highest privilege available Killing however, I'm receiving an error at my second try.
The executable is still there, I can't delete or move the exe until I restart the machine.
Thanks for any help provided because I really don't get it what's the issue here.
Thanks to #HansPassant https://stackoverflow.com/users/17034/hans-passant
The problem is from Avast Antivirus.
I've disabled Avast shields and the application is working properly.
I really don't get why avast doesn't like .NET Frameworks so much but, at least is a temporary fix.
Thanks.
I'm pretty sure it could be some kind of anti virus application that's blocking your application.
Update Too late :D

How to get the installed application location in c#?

I have created a WPF application in my application i'm specifying the default path for the installation location suppose, XYZ is my application, "C:\MyApplication\XYZ\" this is my specified default location where my application gets installed, my application creates a folder dynamically which will be created during the installation of the application in the installed directory, i want when user uninstalls the application then my entire folder(XYZ) has to be deleted i tried many ways but i'm not getting it Please any one give suggestion it will helps me a lot.
Here is what i have tried :-
string filepath = String.Format(#"data\local", Environment.CurrentDirectory);
public override void Uninstall(IDictionary savedState)
{
try
{
base.Uninstall(savedState);
// If i Hard code this i.e if i give direct path(C:\MyApplication\XYZ\)
// then it's getting deleted but if user installs application in other
// location it gets fail.
Microsoft.VisualBasic.FileIO.FileSystem.DeleteDirectory(
filepath,
Microsoft.VisualBasic.FileIO.DeleteDirectoryOption.DeleteAllContents);
}
catch(Exception e)
{
MessageBox.Show(e);
}
}
Application installation is not something that we need to manage manually in the .NET Framework. It provides multiple installation options, so you do not have to manually install or uninstall your applications. The two main installation options the Framework are:
ClickOnce Deployment
Setup Projects
As there is far to much to discuss here, please follow the links to find out more.

Picking up the default Program Files destination of a computer

I'm creating an installer through Microsoft Visual Studio and my program needs a WAMP server to be running in the background to function properly.
Within the installer it installs WAMP to the folder of where the program has been installed and is running from, but how can I find where this actually is using c# code? Is there a way?
I tried this, but no luck;
try
{
Process.Start(#"[ProgramFilesFolder]Hex Technologies\32bit\wampmanager.exe");
checkStatus();
}
catch (Win32Exception exception)
{
MessageBox.Show(exception.Data.ToString());
}
You can try someting like
String EnviromentPath = System.Environment.GetEnvironmentVariable("ProgramFiles", EnvironmentVariableTarget.Machine);
but you may need to take care for x64 vs x32

Categories