i want to use CMD.exe in my C# Program.
The Problem is iam using normally The CMD to open Two Programs to convert Fotos from .png to .svg (ImageMagick.exe & Potrace.exe).
That happend via CMD.exe with Tow Command-lines
the firsstepe: magick convert image.png image.pnm the secondstep: potrace image.pnm image.svg
How to call the CMD.exe to do this two commandslin in my C# Program ?
i try this commands Lines but he call just the CMD.exe and do not anything.
If you use the C# Process class as shown in the code below, with process.WaitForExit() called after each process is started, then you can run the two commands separately as shown. I think the correct calls are in fact magick convert image.png image.pnm and then potrace image.pnm -b svg. This works for me and is what the code is doing.
The biggest problem here was getting C# to find the files it needs. To get this to work I put potrace in a subfolder of the project and copied it to the output directory, so you don't need to install it. I couldn't get this to work for ImageMagick. It appears to need to be installed to work, so in the end I just installed it. The files to be converted are similarly in a Files subfolder of the project with 'Copy to Output Directory' set on their project properties.
As some of the commenters have suggested it may be better to try one of the libraries that can be called directly from C# rather than starting separate processes, which are clearly more inefficient. However, my experience is that often this sort of wrapper project is not well-maintained versus the main project, so if the solution below works it may be fine.
I can upload the full project to GitHub if that would be helpful.
using System.Diagnostics;
using System.Reflection;
#nullable disable
namespace ImageMagicPotrace
{
internal class Program
{
static void Main(string[] args)
{
string path = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).Location);
string filesPath = Path.Combine(path, "Files");
string fileName = "image";
string imageMagick = "magick.exe";
string arg = $"convert \"{Path.Combine(filesPath, fileName + ".png")}\" \"{Path.Combine(filesPath, fileName + ".pnm")}\"";
RunProcess(imageMagick, arg);
string potrace = Path.Combine(path, #"potrace\potrace.exe");
string arg2 = $"\"{Path.Combine(filesPath, fileName + ".pnm")}\" -b svg";
RunProcess(potrace, arg2);
Console.WriteLine("Done");
}
private static void RunProcess(string executable, string arg)
{
Console.WriteLine(executable);
Console.WriteLine(arg);
ProcessStartInfo start = new ProcessStartInfo(executable)
{
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = arg,
UseShellExecute = false,
CreateNoWindow = true
};
Process process = Process.Start(start);
process.WaitForExit();
}
}
}
Related
I would like to embed all files/resources into a single exe (2 exe's and a ps1)
Is it possible ? and how would one go about doing it, currently I have managed to publish the project but there are additional files ( Application Files, Application Manifest and setup exe) in the output - this I would like to embed into single exe.
Been doing some readings, seems I may need to embed the resources and perhaps create pointers? or embedding image resources in the project, not sure if I am on right track and/or how to start the code..
What I have so far
private Boolean Install_certificate()
{
try
{
var newProcessInfo = new System.Diagnostics.ProcessStartInfo()
{
FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe",
Verb = "runas",
Arguments = (#"–ExecutionPolicy Bypass ""script.ps1""")
};
System.Diagnostics.Process.Start(newProcessInfo);
// Install the cert & change proxy settings
//System.Diagnostics.Process.Start(#"script.ps1" );
return true;
}
catch
{
return false;
}
}
private Boolean Install_exe1()
{
try
{
// Install exe1
System.Diagnostics.Process.Start(#"setup1.exe");
return true;
}
catch
{
return false;
}
}
private Boolean Install_exe2()
{
try
{
// Install exe2
System.Diagnostics.Process.Start(#"setup2.exe");
return true;
}
catch
{
return false;
}
}
Appreciate the help!
Thanks
You can use System.Diagnostics.Process to start .exe files.
You can use System.Management.Automation to run power shell scripts.
If your exes work with their dependencies from a command prompt you shouldn't have a problem in C#
If you want to embed these files into your c# project you can add them as resources and when your program runs you can save their binary content to an exe file and then execute them:
In a nutshell, right click on your project, choose properties and then click on resources. Click the link to add a default resource file to your project,
Then in the resource designer select the files, then add resource and add the files you wish to embed. This will create a Resources file that will have your files embedded in them that you can access as a byte[] from in your application.
Then when you application starts save them to disk and run them:
using System;
using System.IO;
using System.Diagnostics;
namespace myNs
{
class Program
{
static void unpack()
{
if (!File.Exists("exe1.exe"))
File.WriteAllBytes("exe1.exe", myNs.Properties.Resources.exe1);
if (!File.Exists("exe2.exe"))
File.WriteAllBytes("exe2.exe", myNs.Properties.Resources.exe2);
if (!File.Exists("ps1.ps")) if (!File.Exists("ps1.ps"))
File.WriteAllBytes("ps1.ps", myNs.Properties.Resources.ps1);
}
static void Main(string[] args)
{
unpack();
Process process = new Process();
process.StartInfo.FileName = "exe1.exe";
process.Start();
process.WaitForExit();
process = new Process();
process.StartInfo.FileName = "exe2.exe";
process.Start();
process.WaitForExit();
process = new Process();
process.StartInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
process.StartInfo.Arguments = "ps1.ps1";
process.Start();
process.WaitForExit();
}
}
}
my question is regarding compiling the exe's + powershell into a single exe without the additional files
You can add the ps1 script as a resource like Alexander Higgins illustrates.
You can merge 2 assemblies together using the tool ILMerge from Microsoft. Here we merge Primary.dll Secondary.dll (and etc) into Merged.dll with a log.txt out of the merger.
ilmerge /log:log.txt /out:Merged.dll Primary.dll Secondary.dll
Because EXEs have an entry point you cant megre 2 EXEs, to workaround this simply change one of the EXEs to be a DLL (class library).
I am trying to run ".sh" file from c# core application.But it doesn't seem to be running properly.Here is my scenario.
I am working on .Net core project which is hosted on Linux environment.We are trying to create "PDF" in our project for which we have used "Apache FOP".
Here i have created one "shell script" file "transform.sh" which internally calls "fop" with required parameters.Since developement is being done on windows machine we tested the same usinf "batch" file i.e. "transform.bat",but since we cannot use the "batch" file on linux enviornment we have created shell script file "transform.sh"
Following is the code from"transform.sh"
./fop -xml $1 -xsl $2 -pdf $3
Following is C# code from which i am calling the "shell script file
var process = new Process
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = string.Format("{0} {1} {2}", XML_filename, XSL_filename, output)
}
};
process.StartInfo.FileName = "Path to shell script file";
process.Start();
process.WaitForExit();
Above code doesnot give any error but it also does not create the pdf file.If i directly run the shell script file from "Terminal" it works fine and create pdf file.
./transform.sh "/home/ubuntu/psa//PdfGeneration/ApacheFolder/XMLFolder/test.xml" "/home/ubuntu/psa/PdfGeneration/ApacheFolder/XSLTFolder/Certificate.xsl" "/home/ubuntu/psa/PdfGeneration/ApacheFolder/PDFFolder/t444t.pdf"
Please let me know if there is something wrong i am doing?How can i make the sheel script run on linux through C# core application.
Thanks.
I was able to solve the issue,just thought that i should put my solution here so that it may help others in future...
As mentioned in Question i was not able to generate the PDF file through shell script on linux machine.After debugging as suggested by "#JNevill" I came to understand that the shell script file was not getting called from .net process itself.
So my first task was to make the shell script file called through .Net Process.
After lots of searching through Net and trying out different solutions i got solution at How to perform command in terminal using C#(Mono).
So changed my code of calling the process as follow,
var command = "sh";
var myBatchFile = //Path to shell script file
var argss = $"{myBatchFile} {xmlPath} {xsltPath} {pdfPath}"; //this would become "/home/ubuntu/psa/PdfGeneration/ApacheFolder/ApacheFOP/transform.sh /home/ubuntu/psa/PdfGeneration/ApacheFolder/XMLFolder/test.xml /home/ubuntu/psa/PdfGeneration/ApacheFolder/XSLTFolder/Certificate.xsl /home/ubuntu/psa/PdfGeneration/ApacheFolder/PDFFolder/test.pdf"
var processInfo = new ProcessStartInfo();
processInfo.UseShellExecute = false;
processInfo.FileName = command; // 'sh' for bash
processInfo.Arguments = argss; // The Script name
process = Process.Start(processInfo); // Start that process.
var outPut = process.StandardOutput.ReadToEnd();
process.WaitForExit();
After changing the code ,the ".sh" file got executed and i was able to generate the PDF file.
Also script of the ".sh" file i.e. (transform.sh) which was calling Apache FOP file i.e. "FOP.sh" also needed to be changed.
Initially code was
./fop -xml $1 -xsl $2 -pdf $3
Which i changed as follow,(Change was to give full path of the FOP file)
/home/ubuntu/psa/PdfGeneration/ApacheFolder/ApacheFOP/fop -xml $1 -xsl $2 -pdf $3
Late answer, but for me, it worked just by setting the RedirectStandardOutput to true and changing the FileName property like this:
processInfo.FileName = #"C:\Program Files\Git\git-bash.exe";
processInfo.RedirectStandardOutput = true;
I have a scenario where i would like to compress my folder due to presence of large number of files present in them using SSIS 2008. Consider it like i have one Source Folder and one Target Folder and while moving files from "SRC" to "TGT" the folder must be compressed in destination.Now feasible option for doing this i think is SSIS Script task ,since I cannot use Execute Process task due to restriction of using any third party software like 7z/Winrar etc.But i am not able to implement this even after using SSIS Script Component.Tried many online solutions but it did not work.How can i implement such thing using SSIS 2008?
You can use the ZipPackage class if you are targeting .Net 3 and above. Complete example here:
https://msdn.microsoft.com/en-us/library/system.io.packaging.zippackage.aspx
There is also a ZipArchive class, example here:
https://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive(v=vs.110).aspx
I did this exercise , I created a Script Task to perform compression of a folder by using the compression provided by Windows;
the folder name can dynamically change.
In this way it is not necessary to use third party software like 7z/Winrar etc..
You need to provide to the Script Task the folder to be zipped and the name of the compressed folder as ReadOnlyVariables (to be added in the tab ReadOnlyVariables)
These two variables must be defined in the Variables tab (String type) of the package and can be changed dynamically through a cycle (eg. for each)
I use these two variables:
sFolderCompressed - the folder '.zip' that you want to obtain eg. \\XX.XX.XX.XX\C$\.....\folderCompressed
sFolderSource - the source folder containing the files affected eg. \\XX.XX.XX.XX\C$\.....\folderSource
(*)
The script is made using c#, choose Script Language: Microsoft Visual C# 2008
This is the code to be added in the Main method:
public void Main()
{
// TODO: Add your code here
try
{
// variables used in process
string l_sFolderCompressed = (string)Dts.Variables["User::sFolderCompressed"].Value;
string l_sFolderSource = (string)Dts.Variables["User::sFolderSource"].Value;
string l_sCommand = "zip -j " + l_sFolderCompressed + " " + l_sFolderSource + "/*";
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/C " as the parameters.
// Incidentally, /C tells cmd that we want it to execute the command that follows,
// and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/C " + l_sCommand);
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Possibly display the command output.
}
catch (Exception objException)
{
Dts.TaskResult = (int)ScriptResults.Failure;
// Log the exception
}
Dts.TaskResult = (int)ScriptResults.Success;
}
You can also manage a single file
"cmd", "/C zip -j c:\\...\file.zip c:\\..\file.txt");
I hope can help
I'm trying to run the Windows System Assessment Tool (winsat.exe) using the following code:
System.Diagnostics.Process WinSPro =
new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo WinSSInfo =
new System.Diagnostics.ProcessStartInfo();
WinSSInfo.FileName = "cmd.exe";
WinSSInfo.Arguments = "/k winsat.exe";
WinSPro.StartInfo = WinSSInfo;
WinSPro.Start();
This code works if I only call cmd.exe, and even if I call regedit.exe it still works.
However, when I try to call winsat.exe as a argument of cmd.exe, it fails.
The command prompt shows this:
'winsat.exe' is not recognized as an internal or external command,
operable program or batch file.
I tried several ways to call winsat.exe:
Call it directly by assigning "winsat.exe" to ProcessStartInfo.FileName. It fails with a Win32Exception: The system cannot find the file specified
As above, using the full path - #"c:\windows\system32\winsat.exe". It fails with the same error.
Run the code as the System Administrator. It still fails.
Call winsat.exe as in the coded example. It failed as I explained earlier.
It's interesting that the command prompt launched from the code can only see .dll files in c:\windows\system32.
Does anyone have any idea why winsat.exe cannot be launched through System.Diagnostics.Process? Are there any limitations which I've misunderstood?
Thanks,
Rex
winsat.exe is redirected using Windows-on Windows 64-bit redirection. What's happening is that your launch request (from a 32-bit process) is being redirected to %windir%\SysWOW64\winsat.exe. Since there's no 32-bit version of this particular executable on 64-bit installs, the launch fails. To bypass this process and allow your 32-bit process to access the native (64-bit) path, you can reference %windir%\sysnative instead:
Process WinSPro = new Process();
ProcessStartInfo WinSSInfo = new ProcessStartInfo();
WinSSInfo.FileName = #"c:\windows\sysnative\winsat.exe";
WinSPro.StartInfo = WinSSInfo;
WinSPro.Start();
Alternatively, if you build your program as x64, you can leave the path as c:\windows\system32.
Note that it's best to use Environment.GetFolderPath to get the path to the windows directory, just in case the OS is installed in a non-standard location:
WinSSInfo.FileName = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
#"sysnative\winsat.exe");
Based on Simon MᶜKenzie's answer, and the link he provided (thanks to soyuz for his comment) I wrote method that should work in either cases (to just copy/paste the code):
public static string GetSystem32DirectoryPath()
{
string winDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
string system32Directory = Path.Combine(winDir, "system32");
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
// For 32-bit processes on 64-bit systems, %windir%\system32 folder
// can only be accessed by specifying %windir%\sysnative folder.
system32Directory = Path.Combine(winDir, "sysnative");
}
return system32Directory;
}
and code to launch the process:
var pi = new ProcessStartInfo
{
FileName = Path.Combine(GetSystem32DirectoryPath(), "winsat.exe"),
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(pi);
On a Windows machine, is there a way to programmatically find out which application is responsible for opening files with a particular extension? Suppose I want to find out programmatically which application is responsible for opening .PDF files. (don't care if you have C# or VB.NET code)
Well, you will start out by looking in the registry in the following position:
HKEY_Current_User\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts.pdf\OpenWithList
There will be one or more keys from a and onwards, which point to the program used for opening a file of that type:
using Microsoft.Win32;
var key = Registry.CurrentUser
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("Explorer")
.OpenSubKey("FileExts")
.OpenSubKey(".doc")
.OpenSubKey("OpenWithList");
var firstProgram = key.GetValue("a"); // E.g. Winword.exe
You might want to split the assignment to key into several statements with null checks ;-)
Hope this helps!
The command-line command ASSOC finds file associations, and the command FTYPE finds actions assigned to them:
C:\> assoc .docx
.docx=Word.Document.12
C:\> ftype Word.Document.12
Word.Document.12="C:\Program Files (x86)\Microsoft Office\Office12\WINWORD.EXE" /n /dde
You can probably invoke them programmatically from any script.
From C#, you'd want to do something like this:
private string ShellCommand(string command)
{
var psi = new ProcessStartInfo("cmd", "/c " + command) {
RedirectStandardOutput = true,
CreateNoWindow = true
};
var p = Process.Start(psi);
return p.StandardOutput.ReadToEnd();
}
private string FindDefaultProgram(string extension)
{
assoc = ShellCommand("assoc " + extension).Split('=')[1];
program = ShellCommand("ftype " + assoc).Split('=')[1];
return program;
}
Haven't tested any of this, so take it with a grain of salt, but this should get you on the right track.
I won’t give you code but rather tell you where this information is stored – I’m sure you can figure out the rest on your own :)
So, all that data is stored inside the registry, in HKEY_CLASSES_ROOT. Taking .pdf as an example, there is a key .pdf which contains AcroExch.Document as it’s default value (on my setup at least).
Again in HKEY_CLASSES_ROOT there is a key AcroExch.Document\Shell\Open\Command and that one contains "C:\Program Files (x86)\Adobe\Acrobat 8.0\Acrobat\Acrobat.exe" "%1" as its value. And that’s what is being used on my computer to open a PDF file.