Starting an uninstaller from code - c#

I would like to add an "Uninstall" button to my program that will start the uninstaller to remove the program and then immediately quit. What's the best way to a) determine if there is an uninstaller present, and b) find the correct uninstaller and launch it?
Can I use the registry in a reliable manner? I recall using the registry before to fix some broken installations and was thinking I could iterate over the entries and identify the appropriate one, but I worry that using the registry might not be reliable and/or work on all systems?
Another thought is that I could actually store the uninstall information to the registry during the installation itself, and then use that information to somehow find the correct uninstaller. That seems like it would be the most reliable method, but is there such an identifier that I could store that I could then pass back to Windows Installer?

Since you taged this with windows-installer, I will assume that you are distributing your application using an MSI. That said, you can call msiexec /x {ProductCode} from your application to initial the uninstall. You can obtain the product code by having the installer write to a registry key/value that your application can read or you can hard code it or your UpgradeCode in your application. If you hard code the UpgradeCode you'll have to call into the Windows Installer API to find out the installed ProductCode for that UpgradeCode.

Related

How to create file as non-root when program was run with sudo?

The problem is: the same program can be run with and without sudo. With sudo it should store configuration in system directory, without sudo it should store configuration in user's directory. Also, when run with sudo it should write both configurations.
The problem is when I create a file or directory in my program when it's run with sudo - it will create file and directories as root. Those files would not be writeable by the user then.
My program also deletes a file that makes resetting the configuration a second time impossible. So on the first run it needs to create both files, user and system.
I know one way of doing that: create all files and directories as root, then change the owner of user directories and files to UID, since libc getuid() should still return my original user id. But this approach requires to add a specialized package for Linux system call. As I'm doing another package, I'm looking a way to reduce dependencies, so maybe is there a build-in way to just switch context to non-sudo from root?
Another way to do that is to use shell, but I don't want to use shell.
I know there is a built-in principal context switching for Windows.
Is there something similar for Linux or multi-platform, or the only way is to use libc calls?
BTW, one or 2 simple calls is no problem, I just don't want to include all stuff like stat, chown, chmod and friends. But if there's no other way I have it all in my Woof.LinuxAdmin package. I just don't want to add a dependency in a package that is not intended strictly for system administration. My goal is just to use the new DPAPI, and this (at least on LINUX) requires configuring key storage somehow. So this IS a little administrative task.
UPDATE:
Oops, it's a rabbit hole ;) I just tested, that libc getuid() and geteuid() return the same value with sudo. It's getting interesting. So of course I can still get user's id by stating the main executable owner. I know, it's not the equivalent to the current user, but it's most common scenario that files in user's home directory are owned by the user. But that leaves me with my Woof.LinuxAdmin package, since it contains all needed system calls and tools to effortlessly use Linux file system permission features.
Since there's probably no easy way around, so when I make a package that should both work on Linux and Windows, I'll probably go for adding the dependency on that Linux module.
I'll just make another "lite" version for Windows only, without the dependency.

How to detect First run of the application after installation?

I want to catch first run of the application after installation. I know that I can use user settings. for example:
if(Properties.Settings.Default.CheckFirstTime == true)
{
MessageBox.Show("1st run");
Properties.Settings.Default.CheckFirstTime = false;
Properties.Settings.Default.Save();
}
else
{
MessageBox.Show("Later run");
}
But in this case, it is not possible to catch first run when the user uninstalls and reinstalls the application again.
Also, I don't want to use a database, because it may be replaced with a manipulated database.
What's the best way to ensure catching the first run of the application after installation?
Depending on your installation method, it could be worth using the registry for this.
When the program is initially installed, there will be no registry keys to store the properties.
If they are not present, write them into the registry as it's assumed to be the first run.
Using this approach, the keys will not be removed when uninstalling as the program manages them itself rather than allowing the installer to handle it.
The following link describes interacting with the registry in C#.
https://www.codeproject.com/Articles/3389/Read-write-and-delete-from-registry-with-C
If you're using MSI for the installer package, you can configure it to leave behind the registry data when uninstalling, which will work around the issue. This is configured differently depending on the tool you use to create the MSI, but as it's supported by the format, it should be implemented in most installation builders than support generating an MSI.
If using install shield, the following section of the documentation describes how to create and remove registry keys - http://helpnet.flexerasoftware.com/installshield23helplib/helplibrary/IHelpRegistryKeys.htm

Get version information for C# application with InstallSheild LE installer

I have a C# program that I want to deploy with InstallSheild LE. I know how to make a setup.exe file to install the application and I know how to create a new installer that can upgrade a current installation.
Currently, I have my application get its version number from the installation log. It checks its version number (which is initially and empty string). If the version number is a an empty string, the application goes to the %TEMP% directory and reads the newest installation LOG file looking for the line that states the installation was successful and the line with the version information. The version information is saved in the application settings and used to detect if upgrades are available. To detect an update, it compares its version number to the version number of the setup.exe in the update location (on a network drive).
This implementation works, however, there are a few aspects of this that worry me and i would like to know if there is a better way to tell the application what version it is and saving this information (preferably not in a file that can be deleted). Obviously, the information would need to be update-able and preserved between runs. Ideally, I would like to be able to internally set the version number in my C# application without having to make assumptions about files being created, or file locations, etc to get it.
Thoughts??
I appreciate your suggestions!
I found that the easiest way was to hardcode the version number in the application. I then would preform a check, during program execution, for the version of the installer in the update location on the network drive. If the version of the installer in the network drive was greater than the hardcoded version in the application, the program would download the new installer, execute it via another process, and close the application so that the necessary files could be updated.
In order to do this you pretty much have to hardcode something in addition to the update location. The question then becomes what's best to hardcode. Here are some ideas, assuming that your installation's ProductVersion property contains the version you need to compare:
The version in question, per your answer
The ProductCode of your installation
A registry location (specific to major versions)
The UpgradeCode of your installation series
A registry location (independent of major versions)
Those, in order, are each less likely to change than the one before it, and it should be trivial to have the installer write its version into a chosen registry location (put [ProductVersion] in a registry key's value) so that's my recommendation. Then the only required update is to change ProductVersion when you update your installation.
There is one other approach that could work without any special a priori knowledge. I'll sketch it out in Win32 API because I'm not familiar enough with the DTF wrappers:
Use MsiEnumComponents or MsiEnumComponentsEx to look at all the installed components on the machine - this could take a while
Use MsiEnumClients or MsiEnumClientsEx to identify the product (or products) that installed each component
Use MsiGetComponentPath or MsiGetComponentPathEx on each product-component pair to identify whether that pair installed your exe file (the location from which you are currently running)
Use MsiGetProductInfo or MsiGetProductInfoEx to retrieve the ProductVersion; if there was more than one client, you'll have to decide how to handle it - perhaps by using the largest version
(If you hardcode the UpgradeCode you can use MsiEnumRelatedProducts in place of steps 1-3; if you hardocde the ProductCode you can jump directly to step 4. Typically you only need to call the Ex variants if you need to search per-user installations.)

Windows seems to lose track of .NET application

We have a .NET application that we distribute to our users via an MSI installer package. We have C++ applications that run each morning to see if the user's copy of the application is out of date, and if so, we pull down the new MSI and install it. If the application is running, we need to take it down so we can perform the update.
Our problem is that every once in a while it seems like windows "loses" our application. It will not report that the process is running - though it is. It will allow us to overwrite, or even delete, the in-use executable file without taking down the application.
Maybe this is something that is common -- but we can't figure out what is going on! Does anyone have any insight into this situation?
It seems like a temporary copy of our application is getting created, and the program is getting ran from that. But if that is the case, why doesn't it happen all the time?
EDIT:
In our program, We are using the "EnumProcesses" function from the Platform SDK, PSAPI.dll, to enumerate all of the running processes.
Could it be that either the script or the application runs as a 64-bit program, and the other as a 32-bit program? If so, then on 64-bit machines the update check could be looking in the wrong location for an existing application and thus reporting it as missing?
What mechanism are you using to check to see if the process is running or not?
Try using something like process explorer to see what path the executable image is loaded from - it should be listed in the modules section.

Forcing Winforms install to make application to start when windows starts

How do I force a windows application, with a setup project being added to it, to install so that it will start everytime someone logs into windows?
Edit: I'm aware of the registry settings, but specifically, I am looking for a solution which will allow for the installer to set the registry values.
Open your registry and find the key
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run].
For each program you want to start automatically create a new string value using a descriptive name, and set the value of the string to the program executable.
For example, to automatically start Notepad, add a new entry of
"Notepad"="c:\windows\notepad.exe".
Remove a startup application
If you're trying to remove a program and can not find it in the StartUp folder (usually C:\WINDOWS\Start Menu\Programs\StartUp), then it may be launching from one of the registry keys below. To remove it, delete the value associated with the program you want to remove.
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows]
Source: http://www.pctools.com/guides/registry/detail/109/
If you really need your application to start when Windows is started as opposed to when someone logs in you need to create it as service and on install set the service to "Automatic".
There are many places on the web that will give you information about this:
Microsoft Support Knowledge Base
Developer.com
C# Corner
are the first three I found, but do some research and find the resource that works for you.
UPDATE
I see from the updated question that the requirement is for the program to run when someone logs in so this answer is (to a certain degree) redundant. However, I will leave it here in case someone wants to go the service root.
You can add a shortcut to your winforms program in the Startup Folder. The setup project's File System is where you need to look.
Technically you can't make a WinForms app start when "windows is started"; however, you can start it when someone logs into Windows. To perform that you do one of the three:
Place a shortcut in the current user's startup folder.
Place a shortcut in the the "All Users" startup folder.
Write a registry key to HKLM/Software/Microsoft/Windows/CurrentVersion/Run
Update: as Chris points out I missed the HKCU path.
To run everytime Windows starts you should build your program as a Windows Service (or perhaps lauch it from a Service).

Categories

Resources