Running console application from a different project - c#

I have a solution in VS2010. Under the solution, I have my main WPF application, with all the user interface, a couple of libraries, and a console application that I want to run when I click a button in my WPF application. My solution structure is similar to this:
- Solution
- WPF App [this is my startup project]
- Library
- Another library
- Console application
Now I have done some hunting around, and I've found people looking for how to reference code and classes, and also a solution to this being that I find the path of the executable, and run it as a new process. However, this requires knowing an absolute path, or even a relative path, and I was wondering if that's the only way I can start an application, even though it's in the same solution?

Yes,that is true. You must know the path to the executable, either absolute or relative. But that is no breakdown. Why don't you just put your WPF exe and Console exe in the same directory or in a subdirectory like in bin\myconsole.exe? When creating a new Process, just pass the name of the Console exe to Process.Start() and Windows will find your executable.
using System;
using System.Diagnostics;
using System.ComponentModel;
namespace MyProcessSample
{
class MyProcess
{
// Opens the Internet Explorer application.
void OpenApplication(string myFavoritesPath)
{
// Start Internet Explorer. Defaults to the home page.
Process.Start("IExplore.exe");
// Display the contents of the favorites folder in the browser.
Process.Start(myFavoritesPath);
}
// Opens urls and .html documents using Internet Explorer.
void OpenWithArguments()
{
// url's are not considered documents. They can only be opened
// by passing them as arguments.
Process.Start("IExplore.exe", "www.northwindtraders.com");
// Start a Web page using a browser associated with .html and .asp files.
Process.Start("IExplore.exe", "C:\\myPath\\myFile.htm");
Process.Start("IExplore.exe", "C:\\myPath\\myFile.asp");
}
// Uses the ProcessStartInfo class to start new processes,
// both in a minimized mode.
void OpenWithStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
startInfo.Arguments = "www.northwindtraders.com";
Process.Start(startInfo);
}
static void Main()
{
// Get the path that stores favorite links.
string myFavoritesPath =
Environment.GetFolderPath(Environment.SpecialFolder.Favorites);
MyProcess myProcess = new MyProcess();
myProcess.OpenApplication(myFavoritesPath);
myProcess.OpenWithArguments();
myProcess.OpenWithStartInfo();
}
}
}
Look here.

Related

Killing process as admin via another process

I'm trying to kill some processes by their names (specific names that I already know) In C#. I find them and kill them with Process.Kill(), but sometimes on some processes i get 'access denied'. I assume it is because I'm not running them as an admin.
I created a batch that does the same, and if I run it as an admin it kills them all, otherwise not.
I can run the batch as an admin via the c# code, i.e:
var psi = new ProcessStartInfo();
psi.Verb = "runas"; //This suppose to run the command as administrator
//Then run a process with this psi
My question is, is this really a way to solve the access problem? Is there a better way? If I run my C# code as an admin, does Process.Kill() suppose to have the same result as doing it with the batch file?
What you are talking about are Elevated rights.
You need the programm that finds the programms and sends out the kills to always run Elevated. The most reliable way to do that, is to add this requirement to the Programm Manifest. It is something the UAC will read to help you.
The second most reliable way is to check if you got the rights. And if not, have the programm try to (re)start itself elevated. I did write some sample code for this a while back:
using System;
using System.Diagnostics;
using System.IO;
namespace RunAsAdmin
{
class Program
{
static void Main(string[] args)
{
/*Note: Running a batch file (.bat) or similar script file as admin
Requires starting the interpreter as admin and handing it the file as Parameter
See documentation of Interpreting Programm for details */
//Just getting the Absolute Path for Notepad
string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
string FullPath = Path.Combine(windir, #"system32\notepad.exe");
//The real work part
//This is the programm to run
ProcessStartInfo startInfo = new ProcessStartInfo(FullPath);
//This tells it should run Elevated
startInfo.Verb = "runas";
//And that gives the order
//From here on it should be 100% identical to the Run Dialog (Windows+R), except for the part with the Elevation
System.Diagnostics.Process.Start(startInfo);
}
}
}
Note that regardless how you try to elevate, Eleveation can fail in very rare OS settings.

C# Remove Readonly From Main Application Folder

I'm trying to build an application with an auto / self updater. The file will check for updates then immediately download the files and replace the necessary files. I've been trying to put this into an installer package, but am running into a problem with the Application Folder being read only. I've tried removing the readonly parameter using code from multiple SO this one, but after the program is installed, the folder remains read only.
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
string path = this.Context.Parameters["targetdir"];
path = path.Substring(0, path.Length - 1);
DirectoryInfo di = new DirectoryInfo(path);
di.Attributes &= ~FileAttributes.ReadOnly;
di.Refresh();
}
catch (Exception e)
{
}
}
I've tried putting this in the Commit method as well. The path is definitely being pulled (MessageBox.Show showed the correct path).
Do I need to be doing something different to change the application's main folder?
I don't see why the updater process matters in the context of this question, but here is how it is working:
User launches the updater app as a sort of "portal" to the main application.
The updater checks the server for an update specific to that device.
The new files are downloaded and all files are replaced that aren't currently locked.
The exe then calls a helper exe and closes itself. The helper exe updates the remaining files (IE the updater itself)
The helper then launches the main application.
You're not looking to remove the Read-only flag, you're looking for elevated permissions to write in that folder - it's not read only to begin with.
To that end you can run your installer app with "RunAs":
// launcher code
if (CheckIfUpdateAvailable()){
ProcessStartInfo startInfo = new ProcessStartInfo ("MyUpdater.exe");
startInfo.Verb = "runas";
System.Diagnostics.Process.Start (startInfo);
Application.Quit();
}
the process spawned by launcher will have the rights to write in your app folder
and your updater has to be an executable you deploy along with your app - you'll find it hard to overwrite a running executable's file
or you could switch to ClickOnce and this comes for free. Granted - there are some minor limitations on what you can do with a ClickOnce installer.
http://support.microsoft.com/kb/981778
I ended up doing a self-elevation (restart run-as) for the updater. This will only ask for permission if there is an update available.
// During update process:
if (!IsAdministrator())
{
// Launch itself as administrator
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
try
{
Process.Start(proc);
}
catch
{
// The user refused to allow privileges elevation.
// Do nothing and return directly ...
return false;
}
Application.Exit();
}
public static bool IsAdministrator()
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
Another solution that is working, although not entirely how I would like it, is to go through each project's properties -> Security -> Enable ClickOnce security settings and then building the installer. This is annoying because it asks for permission every time the file runs on a UAC account. However, it is working and doesn't require some looping exe launching.

How to start a Process from a Win 8 App?

I can’t find System.Diagnostics.Process to start a new process. I guess this is on purpose. But is there a other way? Is this even possible?
You can use this reference on Windows 8 Metro application : How to Start a external Program from Metro App.
All the Metro-style applications work in the highly sand boxed environment and there is no way to directly start an external application.
You can try using Launcher class
Launcher.LaunchFileAsync
// Path to the file in the app package to launch
string exeFile = #"C:\Program Files (x86)\App.exe";
var file = await Windows.ApplicationModel.Package.Current.InstalledLocation
.GetFileAsync(exeFile);
if (file != null)
{
// Set the option to show the picker
var options = new Windows.System.LauncherOptions();
options.DisplayApplicationPicker = true;
// Launch the retrieved file
bool success = await Windows.System.Launcher.LaunchFileAsync(file, options);
if (success)
{
// File launched
}
else
{
// File launching failed
}
}
Launcher.LaunchUriAsync
Reference: Can I use Windows.System.Launcher.LauncherDefaultProgram(Uri) to invoke another metro style app?
Looks like it’s not possible to open any non-metro processes. You can open URLs or Files like *.txt, but not *.cmd or *.exe.
If there is a Custom File Association you could possibly(I haven’t try this) start a process by opening an empty file with your custom filename extension. But you can’t edit the registry to add the association from your app.
So there are no App-Only ways to do this (except not yet discovered hacks ;) ).

Launching a Desktop Application with a Metro-style app

Is there a way to launch a desktop application from a Metro-style app on Windows 8? I'm trying to create some simple shortcuts to desktop applications to replace the desktop icons on the start screen, which look out of place.
I just need something super simple, preferably in C#, to open an application as soon as the app loads. I'm planning on making these shortcuts for some games, photoshop, etc, not anything I've made myself. They're also just for personal use, so I can use direct paths to applications like "C:\Program Files (x86)\Steam\steamapps\common\Skyrim\TESV.exe"
If you simply want to run a desktop application like (notepad, wordpad, internet explorer etc) then go through Process Methods and ProcessStartInfo Class
try
{
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "C:\Path\To\App.exe";
p.Start();
}
// Exp 2
// Uses the ProcessStartInfo class to start new processes,
// both in a minimized mode.
void OpenWithStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
startInfo.Arguments = "www.northwindtraders.com";
Process.Start(startInfo);
}
On Windows 8 Metro application i discovered this: How to Start a
external Program from Metro App.
All the Metro-style applications work in the highly sand boxed
environment and there is no way to directly start an external
application.
You can try to use Launcher class – depends on your need it may
provide you a feasible solution.
Check this:
Can I use Windows.System.Launcher.LauncherDefaultProgram(Uri) to invoke another metro style app?
Ref: How to launch a Desktop app from within a Metro app?
Metro IE is a special app. You cannot invoke an executable from Metro style apps.
Try this - I have not test yet but may be it will help you..
Launcher.LaunchFileAsync
// Path to the file in the app package to launch
string exeFile = #"C:\Program Files (x86)\Steam\steamapps\common\Skyrim\TESV.exe";
var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(exeFile);
if (file != null)
{
// Set the option to show the picker
var options = new Windows.System.LauncherOptions();
options.DisplayApplicationPicker = true;
// Launch the retrieved file
bool success = await Windows.System.Launcher.LaunchFileAsync(file, options);
if (success)
{
// File launched
}
else
{
// File launch failed
}
}
I found a solution which is suitable for me. I just made an empty textfile in my app and called it launcher.yourappyouwanttostart and then executed it with
Windows.System.Launcher.LaunchFileAsync("launcher.yourappyouwanttostart");
On the first startup it asks you for the assocation for this file and then you choose the exe file you want to run and from now on every time you execute this file, your app will be started.
I haven't actually tried if it works and it's not really a beautiful solution, but I guess Metro-style apps can launch a URI.
You could then create a desktop-program that is registered for a custom URI scheme that would then do the actual program launching.
What you can do is host external WCF service on your computer with separate installation and connect to it from metro style application using localhost. Then you can do pretty much anything including Process.Start.
I love simple things, so my solution was to use this:
Process.Start("explorer", "shell:AppsFolder\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe!App")
This will start the "new" Sticky Notes coming with Anniversary Update to Windows 10, but it works with all other "Metro" apps I tested.
To find the name of the metro app, from Windows Explorer you have to find it in shell:appsfolder using the AppUserModelId column.

How do i change the hosts file in a windows program?

How would a program in C++/ C / C# program change the C:\Windows\System32\drivers\etc\hosts file content in windows?
I know this sounds like phishing, honestly not.
Hosts file has a very simple format where each line may contain "ip host" records
All you need is regular file appending :
using (StreamWriter w = File.AppendText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers/etc/hosts")))
{
w.WriteLine("123.123.123.123 FQDN");
}
Beware that by default you'll need elevated privileges to write to the hosts file...
In order to revert back, better take a backup of the file and restore it once you are done.
First, you should request for administrative permission from the user. You can do this through your Program class in your application. The below code will request the user for administrative access, the user then has the option to allow or deny it. If they deny it, this example does not run the application.
Once your application is run in administrative mode, its plain text with simple formatting. You do not even need all the Microsoft comments included in the file, and simple string parsing will do just fine. The comments by MSFT in the HOSTS file are all the documentation you really need as far as the HOSTS file itself goes.
namespace Setup {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Setup.Forms;
using System.Security.Principal;
using System.Diagnostics;
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool administrativeMode = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!administrativeMode) {
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Verb = "runas";
startInfo.FileName = Application.ExecutablePath;
try {
Process.Start(startInfo);
}
catch {
return;
}
return;
}
Application.Run(new ShellForm());
}
}
}
The file is usually located at C:\Windows\System32\drivers\etc\hosts. Rather than hard coding the C:\Windows part though, you should use Environment.GetEnvironmentVariable("SystemRoot") to safely determine the system root directory.
Otherwise you can write to it like any other file, assuming you have the proper permissions.
The hosts file is just plain text. The format is each line contains the IP and the hostname that IP should resolve to, separated by whitespace. # denotes a comment.
Example:
# This is a comment-
127.0.0.1 mysuperhost.com
The file is located here: C:\Windows\system32\drivers\etc\hosts. You will (with good reason), need administrator privileges to write to it.
The most accurate way of finding the HOSTS file location is to read the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DataBasePath registry key, and appending hosts to the end.
This will always point to the correct location for the current machine configuration and works for all Windows NT based platforms since Windows NT 4.0.
As a guy who struggled with this problem, easy way out, copy the hosts file to temp folder, modify it and copy it back with overwrite. Running the application as admin, will be the best.

Categories