C# Process.Start() - target app can't find file - c#

I'm trying to start application "GA.exe", but on start it's taking data from file "acc.txt".
If I start it normallly (via double click :-)) it works, but if I use code below it say "Can't find acc.txt".
My first idea:
Process.Start(pathToGA.exe);
Second idea:
ProcessStartInfo pinfo = new ProcessStartInfo()
{
Arguments = FolderWithGA.exePath,
FileName = pathToGA.exe,
};
And both don't work.

You should set ProcessStartInfo.WorkingDirectory to the directory that holds acc.txt and GA.exe:
ProcessStartInfo pinfo = new ProcessStartInfo()
{
Arguments = FolderWithGA.exePath,
FileName = pathToGA.exe,
WorkingDirectory = FolderWithGA
};

Related

C# Create Detached Process on Linux

I am writing a software update process on Linux. Application is .NET 5 RC1 (Sept 15 2020 release). When a certain packet is received by my application, it downloads the software update to a sub-folder then spawns off the executable to perform the software update.
Unfortunately, using Process.Start and ProcessStartInfo seems to create a process that is attached to the main process. Since the software update must stop the process in order to update it, it also gets stopped because it is a child of the process, having been spawned via Process.Start.
How do I create a detached process on Linux? On Windows I am using PInvoke and the CreateProcess API with the DETACHED_PROCESS flag, see the following:
var processInformation = new ProcessUtility.PROCESS_INFORMATION();
var startupInfo = new ProcessUtility.STARTUPINFO();
var sa = new ProcessUtility.SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
CreateProcess(null, "\"" + fileName + "\" " + arguments, ref sa, ref sa, false, DETACHED_PROCESS, IntPtr.Zero, Path.GetDirectoryName(fileName), ref startupInfo, out processInformation);
Here is my code for Linux. I had read that appending & to a process on Linux creates it detached, but that does not appear to be the case.
ProcessStartInfo info = new ProcessStartInfo
{
// Linux uses " &" to detach the process
Arguments = arguments + " &",
CreateNoWindow = true,
FileName = fileName,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = Path.GetDirectoryName(fileName)
};
Process.Start(info);
I was unable to get nohup or disown to work from C#. Killing the parent process always resulted in the child process being terminated as well.
I ended up using at, which can be installed via sudo apt install at. The atd service is installed and will stay running even when rebooted.
Here is the C# code that I used:
// the following assumes `sudo apt install at` has been run.
string fileName = "[your process to execute]";
string arguments = "[your command line arguments for fileName]";
string argumentsEscaped = arguments.Replace("\"", "\\\"");
string fullArgs = $"-c \"echo sudo \\\"{fileName}\\\" {argumentsEscaped} | at now\"";
ProcessStartInfo info = new()
{
Arguments = fullArgs,
CreateNoWindow = true,
FileName = "/bin/bash",
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = Path.GetDirectoryName(fileName)
};
using var process = Process.Start(info);
process.WaitForExit();
// make sure to check process.ExitCode == 0
For me, setsid in combination with & makes a spawned child process out-living its parent process when invoked via sh -c.
Example:
var command = $"dotnet \"PathToDll\" param1 param2";
process.StartInfo = new ProcessStartInfo
{
Arguments = $"-c \"setsid {command.Replace("\"", "\\\"")} &\"",
CreateNoWindow = true,
FileName = "/bin/sh",
};
process.Start();
This was tested on Debian and Ubuntu.
Slightly refactored version of #jjxtra solution, so it's easier to understand what's going on in the arguments.
Btw, the echo is not an example, but the way of executing at command.
string command = $"actual command to run";
string atdCommand = $#"echo \""{command}\"" | at now";
string bashCommand = $#"-c ""{atdCommand}"" ";
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = bashCommand,
...
};

Keeping the subprocess environment for the caller process in C#

I'd like to set up a Visual C++ toolchain to be used inside my C# application. For the toolchain it's recommended to call vcvarsall (or some subvariant). My problem is that the calling process - my application - will not get to keep the environment set up by vcvarsall. Can this somehow be achieved?
// First set up the toolchain with vcvarsall
var vcvarsallProc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = vcvarsallPath,
Arguments = "x86",
UseShellExecute = false,
}
};
vcvarsallProc.Start();
vcvarsallProc.WaitForExit();
// Invoke the linker for example
var linkerProc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "LINK.exe",
Arguments = " foo.obj /OUT:a.exe",
UseShellExecute = false,
}
};
linkerProc.Start();
linkerProc.WaitForExit();
// ERROR: 'LINK' is not recognized as an internal or external command
Turns out, this is pretty much impossible without a hassle.
The best one can do is chain multiple commands, which will run in the same environment. It can be done like so:
var linkerProc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/C ({vcvarsallPath} {vcvarsallArgs}) && (LINK.exe {linkArgs})",
UseShellExecute = false,
}
};
Hiding this behind a function like InvokeWithEnvironment, and it's pretty painless to use.

c# ProcessStartInfo

Why is this
ProcessStartInfo myProcess = new ProcessStartInfo(path);
myProcess.UserName = username;
myProcess.Password = MakeSecureString(password);
myProcess.UseShellExecute = false;
Process.Start(myProcess);
working, but
ProcessStartInfo myProcess = new ProcessStartInfo();
myProcess.FileName = Path.GetFileName(path);
myProcess.WorkingDirectory = Path.GetDirectoryName(path);
myProcess.UserName = username;
myProcess.Password = MakeSecureString(password);
myProcess.UseShellExecute = false;
Process.Start(myProcess);
is not.
I wanted to use the second one because of this question: https://stackoverflow.com/a/2621943/1306186
I am constantly getting a file not found exception... Any ideas?
Edit:
Path is for example #"C:\Users\User\Desktop\ConsoleApplication2.exe"
This bit is wrong
myProcess.FileName = Path.GetFileName(path);
this should be
myProcess.FileName = path;
Pass in C:\SomeDir\SomeApp.exe and the code you have will set the filename to SomeApp.exe, which it can't find. Count yourself lucky, there are circumstances where it could have (e.g. your app and the app you want to run being in the same folder), and then you would have possibly got a funny when deploying.
I would try using Path.GetFullPath() instead of simply Path.GetFileName() since the constructor initializes the FileName with the full path when you use it with the string parameter.

locate to a folder and execute an application C#

In my application, the user can select a program:
D:/application/app.exe
I would like to execute it such that the same situation that I have to do on CMD, it will show:
C:/
then I have to do: D:
then:
D:/application/app.exe
The application can be only run on its folder for connecting with other libraries.
How can I make it possible to execute it from C# in such a way that it locate to the D:/application first and then execute: app.exe?
Thanks in advance.
See the WorkingDirectory property of ProcessStartInfo. E.g.
Process.Start(new ProcessStartInfo {
WorkingDirectory = #"D:\application",
FileName = "app.exe"
}
You can set the working directory when you start a new process:
Process.Start(new ProcessStartInfo()
{
FileName = #"D:\application\app.exe",
WorkingDirectory = #"D:\application",
//...
});
The Path class can help you parse and manipulate your input path.
Path.GetPathRoot("D:\MyApp\App.exe") --> D:\
Path.GetDirectoryName("D:\MyApp\App.exe") --> D:\MyApp
ProcessStartInfo psi = new ProcessStartInfo(#"D:\application\app.exe") { WorkingDirectory = #"C:\" };
Process.Start(psi);

Is there anyway to specify a PrintTo printer when spawning a process?

What I Have
I am currently writing a program which takes a specified file and the performs some action with it. Currently it opens it, and/or attaches it to an email and mails it to specified addresses.
The file can either be of the formats: Excel, Excel Report, Word, or PDF.
What I am currently doing is spawning a process with the path of the file and then starting the process; however I also am trying to fix a bug feature that I added which adds the verb 'PrintTo' to the startup information, depending on a specified setting.
What I Need
The task I am trying to accomplish is that I would like to have the document open and then print itself to a specified printer named within the program itself. Following that up, the file should then close itself automatically.
If there is no way to do this generically, we might be able to come up with a way to do it for each separate file type.
What you Need
Here is the code I'm using:
ProcessStartInfo pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = FilePath;
// Determine wether to just open or print
if (Print)
{
if (PrinterName != null)
{
// TODO: Add default printer.
}
pStartInfo.Verb = "PrintTo";
}
// Open the report file unless only set to be emailed.
if ((!Email && !Print) || Print)
{
Process p = Process.Start(pStartInfo);
}
How I'm doing...
Still stumped... might call it like Microsoft does,'That was by design'.
The following works for me (tested with *.doc and *.docx files)
the windows printto dialog appears by using the "System.Windows.Forms.PrintDialog" and for the "System.Diagnostics.ProcessStartInfo" I just take the selected printer :)
just replace the FILENAME with the FullName (Path+Name) of your Office file. I think this will also work with other files...
// Send it to the selected printer
using (PrintDialog printDialog1 = new PrintDialog())
{
if (printDialog1.ShowDialog() == DialogResult.OK)
{
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(**FILENAME**);
info.Arguments = "\"" + printDialog1.PrinterSettings.PrinterName + "\"";
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.UseShellExecute = true;
info.Verb = "PrintTo";
System.Diagnostics.Process.Start(info);
}
}
Theoretically, according to an article on MSDN you should be able to change it to be along the lines of (untested):
// Determine wether to just open or print
if (Print)
{
if (PrinterName != null)
{
pStartInfo.Arguments = "\"" + PrinterName + "\"";
}
pStartInfo.CreateNoWindow = true;
pStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pStartInfo.UseShellExecute = true;
pStartInfo.WorkingDirectory = sDocPath;
pStartInfo.Verb = "PrintTo";
}
get from Rowland Shaw:
ProcessStartInfo startInfo = new ProcessStartInfo(Url)
{
Verb = "PrintTo",
FileName = FilePath,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
Arguments = "\"" + PrinterName+ "\"",
};
Process.Start(startInfo);
FilePath look like 'D:\EECSystem\AttachedFilesUS\53976793.pdf'
PrinterName is your printer name
copy the code,it will work.

Categories