C# Starting a program from another program - c#

I have this method
private void StartSDCBackupSet() {
using (Process p = new Process()) {
p.StartInfo.FileName = "SDCBackup";
try {
p.Start();
BackIcon.ShowBalloonTip(5000, "Backup", "Editor for settings startet", ToolTipIcon.Info);
} catch (Exception) {
MessageBox.Show("Program til settings blev ikke fundet");
}
}
}
According to the documentation I can find - and quite a lot of answers here -, it should start another program - SDCBackup.exe.
It doesn't. And I HAVE tried adding the .exe to the filename, but it does not make a difference. I get the messagebox with the message...
I have checked p and StartInfo and everything looks right. StartInfo.UseShellExecute is true.
Debugging reveals, that it is the line p.Start(); that produces the exception. And the Exception is a System.ComponentModel.Win32Exception with message:
File not found
Documentation says, that the code above does the excat same thing as Run in Windows menu, but it obviously does not.
If I write SDCBackup in the RUN section of Windows menu, SDCBackup.exe is started as it should.
(And SDCBackup.exe is a ClickOnce installation, that nobody really knows where to find - other than Windows itself...)
So why does my code not do the trick?

Use
p.StartInfo.FileName = "SDCBackup.exe";
Windows tests out known file types, and if it's an .exe (or any other known type, such as .bat, msc, scr, etc.) it runs it. As far as I know .NET does not do that.
You could try using Path.GetFullPath (https://msdn.microsoft.com/de-de/library/system.io.path.getfullpath(v=vs.110).aspx) but I think it should work with relative paths as well.
Also make sure the file is inside your debug/release folder (whatever folder your .exe that is starting SDCBackup is in), since Windows looks in known directories that are contained in the PATH variable (such as C:\windows\System32, etc), and .NET does not. If it is not in that folder, provide a fully qualified path and it should work.

It seems no one knows how to reference a ClickOnce installed application in another application. (Asked the question at Microsoft, and got no useful response there either.)
It seems ClickOnce apps are installed somewhere in the current users area, e.g.:
C:\Users\[user]\AppData\Local\Apps\2.0
and from there 3 randomly named folders down - and not the same folder names for different users; so there seem to be no way to solve this.
But I did get a way to create a regular installer from Microsoft, for Visual Studio C# solutions.
I used it to set the install path of my apps, so they can find it each other - and it functions.
Install projecttype Installer
and follow the explanation
It involves adding a Installer project to the solution.
I found, that in addition to the explanation,
you have to go to Options for the installer-project,
select **"Configuration Manager",
and set it to be included when building
I also found, that version control is not automatic. You must manually set version number - and for the sake of simplicity, this is a different format than the one Visual Studio uses. If you do set the version, it will automatically uninstall previous versions of the same app.

Related

Microsoft Visual Studio Installer Projects - how to provide restart prompt to MSI executed with Process.Start(), but without Repair option

The problem is following: I have my custom uninstaller called before MSI uninstall. After shutting down my application properly it calls msiexec to use Windows Installer to uninstall MSI.
It's done by executing something like "msiexec /x{PRODUCT_CODE} /promptrestart".
And here is important thing - if the system is not restarted after uninstallation, and then the user installs the app again, some of its files will be deleted after next restart, so it's not acceptable. The restart is required, however, I need prompt, automatic and unconditional restart is evil and should never ever be used.
So, the invocation above displays STUPID "uninstall / repair" dialog. I do not want it. When I use "msiexec /x{PRODUCT_CODE} /qr /promptrestart" - then it uninstalls nicely, however it refuses propt for restart afterwards.
I have read about setting ARPNOREPAIR property.
But the idiots who gave that answer wouldn't care to say WHERE and HOW that property could be set. Even... Where the property belongs, it's the property of what? MSI file?
Then, maybe is it another way to achieve this, like invoke the prompt for restart from my code, but... how? The uninstaller should remove all my files until that moment. Maybe it's possible to execute a kind of script after the uninstallation process is complete?
(One more problem, the Windows Installer doesn't delete ALL files and directories created by my app. It would be nice if I could execute some code to clean up better.)
UPDATE
I see 2 paths ahead: make a script to be run once the uninstallation ends (like using Registry or Task Scheduler or IDK), use Win32 API to modify MSI file, because AFAIK it's possible to change its properties that way.
Questions: Some questions first.
Restart Manager: Are you familiar with the Restart Manager feature of MSI? Intended to help shut down and restart
applications without the need for reboots. I would give it a quick
skim? I think this is your real solution?
Alternative MSI Tools: There are many tools available for creating MSI setups. This link also contains further links to a summary of the shortcomings of Visual Studio Installer Projects.
Using the free, open-source WiX toolset - for example - you can change MSI dialogs. Github sample. SO question 1. SO question 2. And here is the official WiX toolset site.
Adding my own answer from SO: Changing text color to Wix dialogs (please do skim)
I am not familiar with how to change dialogs in Visual Studio Installer Projects. Commercial products Advanced Installer and Installshield can certainly change dialogs.
Services: What is the nature of the product you are installing? Does it has a lot of services for example? Services can be shut down and restarted via MSI tables if you use a proper tool to build the MSI.
REINSTALLMODE: Do you use a custom REINSTALLMODE for your setup? (some settings can cause more reboot prompts).
Custom Uninstaller: How do you invoke that custom uninstaller of yours? Manually or do you register an uninstall command line with Add / Remove Programs? (this latter approach is not recommended).
ARP Applet vs MSI Dialogs: The ARPNOREPAIR property is set in the MSI itself - in the property table. It affects only what is seen in Windows' Add / Remove Programs applet (ARP = Add / Remove Programs), and not what you see when your MSI is invoked via command line. Then you see the dialogs defined in that MSI itself (which can be changed - not entirely trivial to do).
ARP / Add Remove Programs Applet: A quick review of this applet below:
Hold Windows Key and Tap R. Type: appwiz.cpl and press Enter. This opens the Add /Remove Programs Applet.
Select the different package entries in the list to see different settings for ARPNOREPAIR, ARPNOMODIFY, etc...
If ARPNOREPAIR is set in the MSI's property table then the Repair entry is missing.
If ARPNOMODIFY is set in the MSI's property table then the Change entry is missing.
If ARPNOREMOVE is set in the MSI's property table then the Remove entry is missing.
If the special ARPSYSTEMCOMPONENT property is set, then the MSI will be missing from ARP altogether.
Links:
In-use files not updated by MSI-installer (Visual Studio Installer project)
So, there is an "ugly hack" which solves the exact problem:
First - we need an executable, that isn't affected by the installer. This one is easy, we just copy that one installed exe to a TEMP directory and run it from there.
The next step is to that file must wait unit the uninstall phase is done. There are a couple of ways of doing so. You can observe the installer process, you can observe the file system if main program file is deleted. Considering the pace of common installer operations, polling once a second is a good enough option.
The next step is optional - you remove remaining files created by application, empty directories and such.
The next step is reboot itself, MessageBox.Show() from PresentationFramework is fine to ask user, when user answer OK or YES, then reboot itself can be performed in many ways, I use ExitWindowsEx() from user32.dll since it's probably what msiexec calls internally.
Here's example code:
if (MessageBox.Show(RestartPromptMsg, "", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation) == MessageBoxResult.OK) {
NativeMethods.ExitWindowsEx(
NativeMethods.Flags.Reboot,
NativeMethods.Reason.MajorApplication | NativeMethods.Reason.MinorInstallation | NativeMethods.Reason.FlagPlanned
);
}
Of course some parameters could be passed to our special clean up executable, so it could do some extra things, like skip the restart prompt if it's not really required.
The last step is to delete our executable itself. It's easy, but it's tricky. Again I hope my example code would help:
var cleanUpTempPath = Path.Combine(Path.GetTempPath(), CleanUpExe);
File.Copy(CleanUpPath, cleanUpTempPath, overwrite: true);
Process.Start(new ProcessStartInfo {
FileName = "cmd",
Arguments = $"/c (\"{cleanUpTempPath}\" -purge \"{InstallerDir}\") & (del \"{cleanUpTempPath}\")",
UseShellExecute = false,
CreateNoWindow = true
});
We use cmd.exe special feature, the power of & and (). Commands separated with & gets executed when previous command exits. So when our clen up exe completes, it's gets deleted by the same cmd instance which called it. Remember to quote all paths, they can contain spaces. Remember to enclose a command with arguments in parentheses, because otherwise the & operator would be seen as a parameter to the previous command, not the cmd.exe.
I tested it in my big production application and it works as charm. The code examples don't work when just pasted, if you're looking for complete code, just google for it, there are plenty of working examples on pinvoke.net and StackOverflow.

Run program with build errors

This question might be a little bit weird, but I'd like my program to run with build errors. I am using windows forms (c#), and before initializing the main form, the program checks if I have Adobe Reader installed. This is necessary, because certain forms are designed to use Adobe's COM extension.
So I'd like my program to check at startup if Adobe Reader is installed, and if it is, continue, and if it is not, execute the supplied Adobe installer. My problem is that if Adobe Reader is not installed, the program won't even execute, so it can't even check for the installation, because it won't recognize certain parts of the code.
Do I have to use another program, which then executes the main one if Adobe is installed, or is there a workaround, so that I can use only the main application?
You should consider using some kind of Launcher or Installer that checks for all the requested prerequesites before it starts your program.
I suggest you just add another application that checks for adobe installation and after the validation/installation is finished to start your own application.
There are two parts to this "solution":
The way I've worked around this problem (so that it will at least build) is to include the referenced DLL/COM object's (on the reference, choose to "Copy to Local" and set it to true). Extract them to a folder and it should allow for you to at least build when the application has errors, since the references are available. I've seen this used extremely successfully against COM object.
Say you have a "Common Libraries" folder in your solution's base directory, you'll navigate to the bin directory after you build the application on a machine with a good copy of everything that's needed (the COM object for Adobe). You'll then copy the appropriate Adobe DLL's from that folder into the Common Libraries, remove the reference to the Adobe COM and then re-add pointing to the DLL's in the "Common Libraries" folder. You may have to choose NOT to embed the types in the application (also part of the Reference properties).
The second part is to check for the application and determine its state. I imagine even attempting to use the COM object without the application present should throw some kind of error -- and I've seen folks use try-catch blocks around to "fix" this. That's not a great programming practice, so anything you can do to scan for it otherwise is better, but for quick and simple, try-catch generally will work.

Visual Studio Setup, Custom Action to copy the setup file

I am developing a visual studio setup project. So far all has been good except uninstalling. The program did not create its own uninstaller, but instead the uninstall feature is inside of the setup.msi. So what I need to do is during the install, I need to copy the running setup.msi to the [TARGETDIR]. The easiest way I can think of is to use custom actions. I'm pretty lost on custom actions though, I don't understand where they go and every time I try to code one, its full of errors. Looking at other questions and answers, I have come up with the following:
[RunInstaller(true)]
public partial class CustomInstaller : System.Configuration.Install.Installer
{
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string path = this.Context.Parameters["targetdir"];
// Do something with path.
}
}
But I don't understand it. I see how it gets targetdir as that gets passed via the customactiondata. But, RunInstaller isn't known, nor is System.COnfiguration.Install.Installer. Where am I supposed to put this .cs file to make it work? Very confused.
This class should be placed in your application project. I believe it can be included in any project whose DLL is packaged by the setup project, but it usually makes the most sense to put it in the application project.
Make sure your application project references System.Configuration.Install.dll. That will resolve the reference to Installer.
RunInstaller is in the System.ComponentModel namespace (System.dll), so make sure you have a using System.ComponentModel statement at the top of the class file.
This question may help you understand custom actions more:
Why won't my Setup Project Perform my Custom Registration Process
This might help you get started, although it doesn't cover installer classes.
https://www.simple-talk.com/dotnet/visual-studio/getting-started-with-setup-projects/
Error 2835 is a bogus error related to trying to show a dialog, probably the error dialog, so it's masking whatever went wrong, most likely your code.
Make a log using msiexec /I /l*v and look for your error before the 2835.
You pass that targetdir value to your custom action like an argument list, so you'd say /targetdir="[TARGETDIR]\" and that's case-sensitive and including the brackets. It's picky because it gets merged with other arguments.
Beware that your code is not running in an application context. It's a call from the msiexec process running with the system account and a working directory of sysetm32. That means full paths need to be specified and any use of a profile-specific item (like Desktop, user profile location) will fail.

Deployed application can't find its resources c# Visual Studio 2010

I have an big issue when publishing my application on another machine. The apps resources as pictures and sounds can't be found anywhere thou they actually are installed somewhere I really don't know where.. I'm talking about oneClick Deployment! I have put the files in separate folders in the Resource folder in the Solution explorer and the path is a string path inside Settings like this ....\Resources\Images\Cards\ and ....\Resources\Sounds\ Whatever I do the program can't find its resources so what is the basic issue here? I believe it's something wrong with the path because I see when the program gets installed it installs everything (same amount of MB). Any suggestions anybody?
C# Visual Studio 2010 Black Jack Game
I had the same problem, You can do the following:
Open the .resx file
Just above the file, there is a access modifier listbox. if it is set to "No code generated" , Select public from the list
Build,
Hopefully, problem solved.
Well I found the answer to this issue after a while of struggling..
You have to erase the "..\..\" before the Resource folder in the "settings" while you are about to publish otherwise the deployed application can not find its resources thus they will not be at the same folder as described. But remember if you want to continue working on your project you must put back "..\..\" for debugging the program otherwise debugging will not work!!! I was not allowed to publish the image to show you here because of I don't have earned "10" reputations yet.. :)
In Visual Studio 2010 professional open your project
open the project properties
select Web
Under Servers set the Virtual Path as your deployed website virtual path.
If you set the virtual path to /BookStore
You need to update all the resources references
Look like the following from
src="../../img/picture.png"
to
src="/BookStore/./img/picture.png"
I had the same issue, I assume it is suppose to be that way with two different paths.
This is what I did so I no longer had to edit the file paths when going from debugging to production.
Public RP As String = IO.Path.GetFullPath(My.Resources.ResourceManager.BaseName)
Public filePath As String = RunOrInstall(RP)
'Checks to see if debugging or installed and returns correct path
Private Function RunOrInstall(RP)
Dim pathing As String
If RP.ToString().IndexOf("bin") = -1 Then
pathing = RP.Substring(0, RP.LastIndexOf("\")) & "\Resources\"
Else
pathing = RP.Substring(0, RP.LastIndexOf("bin")) & "Resources\"
End If
Return pathing
End Function
If I understand the problem correctly, I believe I had a similar issue...
I was creating an installer for one of my c# apps, and whenever I installed the program it couldn't find any of the resources it needed to run.
The problem ended up being that the files that the installer was putting on the desktop and in the programs menu weren't set to "shortcut". Try setting "Type" to "Shortcut" (I'm using microsoft visual studio 2008, and it requires a right-click -> create new shortcut -> select file to create a shortcut to... it may be different for whatever IDE you're using)
edit - I just noticed you put vs 2010 in your tag, so the process should be very similar

TFSBuild 2010: File.Copy c# snippets throw me exception after compilation

With TFS Build 2010, I have build process running devenv.com for several projects. After that, I want all the binaries to be copied from the output folders with C# Custom Build Activities with "File.Copy". However, it threw me this exception with the first copy of the file:
The process cannot access the file 'C:\Test\BuildServer\Sources\Library\LibraryInstall\LibraryInstall\Release\LibraryInstall.msm' because it is being used by another process.
It seems the file is still been using by the devenv.com. Any idea how? Other than File.Copy, is there any better way to copy it regardless the file status?
======
I found an ugly way:
Process proc = new Process();
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = #"C:\WINDOWS\system32\xcopy.exe";
proc.StartInfo.Arguments = "/Y " + Path.Combine(sourcesDirectory, fileName) + " " + binariesDirectory;
proc.Start();
Devenv is an agressive file locker. If you can build your projects by creating an MSBuild file and bypassing devenv you'll be better off. Some project types can only be built with devenv though, you've not specified what project types you are using so this may not be an option.
MSBuild has a feature called "node reuse" whereby it creates processes that can hang around for up to 15 minutes as an optimization for subsequent builds. It may be that the node reuse combined with devenv's file locking behavior is giving you trouble.
You've not made it clear just exactly how you are executing your build, but if MSBuild is involved, you could try to specify the /nodereuse:false option to disable this feature.
I've also seen rogue MSBuild and devenv process hang onto files, they can get hung up and stay around forever until you kill them if there are obscure exceptions in your build.
I have few amateur things. Don't put a minus on my answer =)
First, take a look at this answer to change your algorithm little bit
You can create batch file which includes same ugly method in
it. Then call this batch file from C#
Maybe you can use FileStream.. binary read-write
Maybe you can import vb referance to your project and use ( non-sense
)
Or directly kill the process which accourding with this error.
And here is an another search, please take a look this question too.
This is the last and hard-core long shot.
Best Regards...

Categories

Resources