Using ProcessStartInfo with ImageMagick's Mogrify - c#

Tearing my hair out over something that should be ridiculously simple! I have cd'd to C:\Program Files\ImageMagick-6.9.0-Q16 on my shell and used the following the command string which works on my machine; it creates the expected output image, no problem:
convert "C:\Users\someguy\Debug\test_in.jpg" -resize 75x75 -colorspace
RGB "C:\Users\someguy\Debug\test_out.jpg"
I am trying to automate this with a simple test application in C#:
var proc = new Process
{
StartInfo = new ProcessStartInfo()
{
//WorkingDirectory = #"C:\Program Files\ImageMagick-6.9.0-Q16\",
Arguments = //_arguments,
"convert \"" + InputPath + "\" -resize 75x75 \"" + OutputPath + "\""
,
UseShellExecute = _useShellExecute,
RedirectStandardError = _redirectStandardError,
//RedirectStandardOutput = _redirectStandardOutput,
//CreateNoWindow = _createNoWindow,
//Verb = _verb,
FileName = #"C:\Program Files\ImageMagick-6.9.0-Q16\" + "convert.exe"
}
};
var test = proc.StartInfo.Arguments.ToString();
proc.Start();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
I have tried several permutations of this, using convert.exe, mogrify.exe, with verb as "runas", with the working directory set on, or off... (see commented out stuff - I've tried setting it) I have referred to how to use imageMagick with C# but I continue to get the same error:
mogrify.exe: unable to open image convert': No such file or directory
# error/blob.c/OpenBlob/2709. mogrify.exe: no decode delegate for this
image format' # error/constitute.c/ReadImage/501. mogrify.exe:
unable to open image `C:\Users\someguy\Debug\test_out.jpg': No such
file or directory # error/blob.c/OpenBlob/2709.
I feel like I'm just missing something really basic here, but I don't have a clue at this point. Could someone please offer a suggestion?

var proc = new Process
{
StartInfo = new ProcessStartInfo(_imageMagickFile)
{
//WorkingDirectory = #"C:\Program Files\ImageMagick-6.9.0-Q16\",
Arguments = //_arguments,
"" + InputPath + " -resize 75x75 " + OutputPath + ""
,
UseShellExecute = _useShellExecute,
RedirectStandardError = _redirectStandardError,
RedirectStandardOutput = _redirectStandardOutput,
CreateNoWindow = _createNoWindow,
Verb = _verb,
FileName = _imageMagickFile
}
};
var test = proc.StartInfo.Arguments.ToString();
proc.Start();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
I'm not actually sure why this works instead of the original question, but it does. Using convert.exe is indeed correct, not mogrify.exe. As an FYI, the other parameters are ShellExecute = false, Redirect std err/out are set to true, verb is runas.

Related

Starting node process once and reusing it for execution of javascript file in c#

I am trying to run node and executing my javascript file using below code from c#. my c# application is running as windows service in windows server 2019 standard
string appjsloc = AppDomain.CurrentDomain.BaseDirectory + "\\appjs.js";
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
{
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
CreateNoWindow = true,
FileName = "cmd.exe",
Arguments = "/C node \"" + appjsloc + "\" \"" + inputfile + "\" \"" + outputfile + "\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
my input and output is changing and thus i am passing these two arguments dynamically whenever required . appjsloc is fixed.
using this code , node is started every time and then closed after executing my appjs file. this is time consuming and giving performance slowness, because in every execution , it start the node process first(which takes some time) and then execute my appjs file. Is there any way I can avoid starting node every time and reusing them for all my future execution of appjs.

Trying to transpile a js file in wpf c# project

I'm attempting to call Process.Start to invoke Babel and transpile a js file in my c# project.
I've installed babel into a directory "ES6" using the command:
npm install babel-preset-es2015 --save-dev
the directory C:\ES6\node_modules.bin now has a babel and babel.cmd file
Now I'm attempting to transpile a js file using Process.Start and redirecting the std out to capture the results I can use:
string babelFileName = #"C:\ES6\node_modules\.bin\babel";
var startInfo = new ProcessStartInfo {
FileName = babelFileName,
Arguments = " --presets es2015 " + ViewModel.EditorViewModel.JSFullFilePath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
string js = ViewModel.EditorViewModel.Javascript;
using (var process = Process.Start(startInfo)) {
var standardOutput = new StringBuilder();
// read chunk-wise while process is running.
while (!process.HasExited) {
standardOutput.Append(process.StandardOutput.ReadToEnd());
}
int exitCode = process.ExitCode;
// make sure not to miss out on any remaindings.
standardOutput.Append(process.StandardOutput.ReadToEnd());
string stdout = standardOutput.ToString();
js = string.IsNullOrEmpty(stdout) ? js : stdout;
}
I've tried to invoke bable using "bable." to get around the missing ".exe" extension but no luck. I get the following exception:
The specified executable is not a valid application for this OS platform.
Hoping someone can point out how I can properly invoke babel to do this.
**UPDATE
I took a look at babel.cmd since this command line does transpile correctly:
C:\ES6\node_modules.bin>babel someES5.js --presets es2015
babel.cmd:
#IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\babel-cli\bin\babel.js" %*
) ELSE (
#SETLOCAL
#SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\babel-cli\bin\babel.js" %*
)
And modified my C#:
string babeljs = #"C:\ES6\node_modules\babel-cli\bin\babel.js";
var startInfo = new ProcessStartInfo {
FileName = "node.exe",
Arguments = babeljs + " " + ViewModel.EditorViewModel.JSFullFilePath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
This does essentially echo the un-transpiled js code verbatim. If I now add " --presets es2015 " to the arguments, the process completes successfully but with empty output.
What do I need to add here to get transpiled js from this node.exe process?

c# System.Diagnostics.Process Does Not Do Anything or Throw Error

I wonder if someone can please help me understand why my Process is not working, nor generating an error.
The code below should loop through a directory, find all files with an sqb extension and for each file run a Process as a user account which has elevated privileges on the server.
The process should run an executable sqb2mtf.exe from the same folder as the files are located with an argument such as sqb2mtf.exe file.sqb file.bak for example purposes.
If I use Visual Studio 2013 and step through the code I can see each file being looped through and the Process appears to fire, but no files are converted, nor any errors presented to the variable readToEndError.
var directory = new DirectoryInfo(#"D:\inetpub\Import\");
foreach (var file in directory .EnumerateFiles("*.sqb"))
{
var convert = Path.GetFileNameWithoutExtension(file.ToString());
var process = new Process
{
StartInfo =
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true,
FileName = #"D:\inetpub\Import\sqb2mtf.exe",
UserName = "myUserName",
Domain = "myDomain",
Password = GetSecureString("myPassword"),
Arguments = #"D:\inetpub\Import\" + file + " " + #"D:\inetpub\Import\" + convert + ".bak"
}
};
process.Start();
string readToEndOutput = process.StandardOutput.ReadToEnd();
string readToEndError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
I am going out of my mind, any advice to resolve this would be much appreciated :-)
Update
var directoryInfo = new DirectoryInfo(BackupDirectory);
foreach (var file in directoryInfo.EnumerateFiles("*.sqb"))
{
var convert = Path.GetFileNameWithoutExtension(file.ToString());
var fileName = BackupDirectory + "sqb2mtf.exe";
var arguments = "\"" + BackupDirectory + file + "\" \"" + BackupDirectory + convert + ".bak\"";
var process = new Process
{
StartInfo =
{
CreateNoWindow = true,
UseShellExecute = true,
RedirectStandardOutput = false,
RedirectStandardInput = false,
RedirectStandardError = false,
FileName = fileName,
Arguments = arguments
}
};
process.Start();
process.WaitForExit();
file.Delete();
}
One thing drawing on from the comments by InBetween is the need for quotes, in this case the quotes needed to surround the two separate files.
I can confirm this code does work on IISExpress, impersonating the different user, unfortunately just not IIS 7.5.
A workround was to move this code into a Console Application and install on the server in question, then use a Windows Schedule Task to run as a specific account.
With some legacy apps, I've discovered that I need to pass the arguments as quoted text, otherwise they simply wouldn't work.
Not sure if this is the issue but it's worth the try:
Arguments = "\"D:\\inetpub\\Import\\" + file + " D:\\inetpub\\Import\\" + convert + ".bak\"";
Still it seems strange that the process would simply die silently. I'd double check Domain, UserName and Password.

Generate CSS from LESS on windows azure worker role

I would like to allow my user to change some less variables so they can customize the styles.
When done I would like to generate the css file.
I m working in .net and have an azure worker role that can probably handle the task.
if it's not possible in .net may be with node.js?
Can someone suggest me a way to do it?
Thank you
I'm currently building my LESS files using lessc.wsf which you can download here: https://github.com/duncansmart/less.js-windows/tree/windows-script-host
Then in your Worker Role you can do something like this:
// File path.
var lessCompilerPath = "...\\lessc.wsf";
var lessPath = "site.less");
var cssPath = "site.css");
// Compile.
var process = new Process
{
StartInfo = new ProcessStartInfo("cscript")
{
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
Arguments = "//nologo \"" + lessCompilerPath + "\" \"" + lessPath + "\" \"" + cssPath + "\" -filenames",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true
}
};
process.Start();
process.WaitForExit();
// Error.
if (process.ExitCode != 0)
{
throw new InvalidOperationException(process.StandardError.ReadToEnd());
}
You'll need to match the path to your files depending on where they are located in your solution.

Run Command Prompt Commands

Is there any way to run command prompt commands from within a C# application? If so how would I do the following:
copy /b Image1.jpg + Archive.rar Image2.jpg
This basically embeds an RAR file within JPG image. I was just wondering if there was a way to do this automatically in C#.
this is all you have to do run shell commands from C#
string strCmdText;
strCmdText= "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);
EDIT:
This is to hide the cmd window.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.StartInfo = startInfo;
process.Start();
EDIT 2:
It is important that the argument begins with /C, otherwise it won't work. As #scott-ferguson said: /C carries out the command specified by the string and then terminates.
Tried RameshVel's solution but I could not pass arguments in my console application. If anyone experiences the same problem here is a solution:
using System.Diagnostics;
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine("echo Oscar");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
var proc1 = new ProcessStartInfo();
string anyCommand;
proc1.UseShellExecute = true;
proc1.WorkingDirectory = #"C:\Windows\System32";
proc1.FileName = #"C:\Windows\System32\cmd.exe";
proc1.Verb = "runas";
proc1.Arguments = "/c "+anyCommand;
proc1.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(proc1);
None of the above answers helped for some reason, it seems like they sweep errors under the rug and make troubleshooting one's command difficult. So I ended up going with something like this, maybe it will help someone else:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\Program Files\Microsoft Visual Studio 14.0\Common7\IDE\tf.exe",
Arguments = "checkout AndroidManifest.xml",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
WorkingDirectory = #"C:\MyAndroidApp\"
}
};
proc.Start();
Though technically this doesn't directly answer question posed, it does answer the question of how to do what the original poster wanted to do: combine files. If anything, this is a post to help newbies understand what Instance Hunter and Konstantin are talking about.
This is the method I use to combine files (in this case a jpg and a zip). Note that I create a buffer that gets filled with the content of the zip file (in small chunks rather than in one big read operation), and then the buffer gets written to the back of the jpg file until the end of the zip file is reached:
private void CombineFiles(string jpgFileName, string zipFileName)
{
using (Stream original = new FileStream(jpgFileName, FileMode.Append))
{
using (Stream extra = new FileStream(zipFileName, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[32 * 1024];
int blockSize;
while ((blockSize = extra.Read(buffer, 0, buffer.Length)) > 0)
{
original.Write(buffer, 0, blockSize);
}
}
}
}
if you want to run the command in async mode - and print the results. you can you this class:
public static class ExecuteCmd
{
/// <summary>
/// Executes a shell command synchronously.
/// </summary>
/// <param name="command">string command</param>
/// <returns>string, as output of the command.</returns>
public static void ExecuteCommandSync(object command)
{
try
{
// 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 " + command);
// 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();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
Console.WriteLine("ExecuteCommandSync failed" + objException.Message);
}
}
/// <summary>
/// Execute the command Asynchronously.
/// </summary>
/// <param name="command">string command.</param>
public static void ExecuteCommandAsync(string command)
{
try
{
//Asynchronously start the Thread to process the Execute command request.
Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
//Make the thread as background thread.
objThread.IsBackground = true;
//Set the Priority of the thread.
objThread.Priority = ThreadPriority.AboveNormal;
//Start the thread.
objThread.Start(command);
}
catch (ThreadStartException )
{
// Log the exception
}
catch (ThreadAbortException )
{
// Log the exception
}
catch (Exception )
{
// Log the exception
}
}
}
if you want to keep the cmd window open or want to use it in winform/wpf then use it like this
string strCmdText;
//For Testing
strCmdText= "/K ipconfig";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);
/K
Will keep the cmd window open
Yes, there is (see link in Matt Hamilton's comment), but it would be easier and better to use .NET's IO classes. You can use File.ReadAllBytes to read the files and then File.WriteAllBytes to write the "embedded" version.
with a reference to Microsoft.VisualBasic
Interaction.Shell("copy /b Image1.jpg + Archive.rar Image2.jpg", AppWinStyle.Hide);
This can also be done by P/Invoking the C standard library's system function.
using System.Runtime.InteropServices;
[DllImport("msvcrt.dll")]
public static extern int system(string format);
system("copy Test.txt Test2.txt");
Output:
1 file(s) copied.
Here is little simple and less code version. It will hide the console window too-
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.Start();
I have the following method, which I use to run the command prompt commands from C#
In first parameter pass the command you want to run
public static string RunCommand(string arguments, bool readOutput)
{
var output = string.Empty;
try
{
var startInfo = new ProcessStartInfo
{
Verb = "runas",
FileName = "cmd.exe",
Arguments = "/C "+arguments,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = false
};
var proc = Process.Start(startInfo);
if (readOutput)
{
output = proc.StandardOutput.ReadToEnd();
}
proc.WaitForExit(60000);
return output;
}
catch (Exception)
{
return output;
}
}
You can achieve this by using the following method (as mentioned in other answers):
strCmdText = "'/C some command";
Process.Start("CMD.exe", strCmdText);
When I tried the methods listed above I found that my custom command did not work using the syntax of some of the answers above.
I found out more complex commands need to be encapsulated in quotes to work:
string strCmdText;
strCmdText = "'/C cd " + path + " && composer update && composer install -o'";
Process.Start("CMD.exe", strCmdText);
you can use simply write the code in a .bat format extension ,the code of the batch file :
c:/ copy /b Image1.jpg + Archive.rar Image2.jpg
use this c# code :
Process.Start("file_name.bat")
You can use RunProcessAsTask pacakge and run your process async and easily like this:
var processResults = await ProcessEx.RunAsync("git.exe", "pull");
//get process result
foreach (var output in processResults.StandardOutput)
{
Console.WriteLine("Output line: " + output);
}
This may be a bit of a read so im sorry in advance. And this is my tried and tested way of doing this, there may be a simpler way but this is from me throwing code at a wall and seeing what stuck
If it can be done with a batch file then the maybe over complicated work around is have c# write a .bat file and run it. If you want user input you could place the input into a variable and have c# write it into the file. it will take trial and error with this way because its like controlling a puppet with another puppet.
here is an example, In this case the function is for a push button in windows forum app that clears the print queue.
using System.IO;
using System;
public static void ClearPrintQueue()
{
//this is the path the document or in our case batch file will be placed
string docPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//this is the path process.start usues
string path1 = docPath + "\\Test.bat";
// these are the batch commands
// remember its "", the comma separates the lines
string[] lines =
{
"#echo off",
"net stop spooler",
"del %systemroot%\\System32\\spool\\Printers\\* /Q",
"net start spooler",
//this deletes the file
"del \"%~f0\"" //do not put a comma on the last line
};
//this writes the string to the file
using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
{
//This writes the file line by line
foreach (string line in lines)
outputFile.WriteLine(line);
}
System.Diagnostics.Process.Start(path1);
}
IF you want user input then you could try something like this.
This is for setting the computer IP as static but asking the user what the IP, gateway, and dns server is.
you will need this for it to work
public static void SetIPStatic()
{
//These open pop up boxes which ask for user input
string STATIC = Microsoft.VisualBasic.Interaction.InputBox("Whats the static IP?", "", "", 100, 100);
string SUBNET = Microsoft.VisualBasic.Interaction.InputBox("Whats the Subnet?(Press enter for default)", "255.255.255.0", "", 100, 100);
string DEFAULTGATEWAY = Microsoft.VisualBasic.Interaction.InputBox("Whats the Default gateway?", "", "", 100, 100);
string DNS = Microsoft.VisualBasic.Interaction.InputBox("Whats the DNS server IP?(Input required, 8.8.4.4 has already been set as secondary)", "", "", 100, 100);
//this is the path the document or in our case batch file will be placed
string docPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//this is the path process.start usues
string path1 = docPath + "\\Test.bat";
// these are the batch commands
// remember its "", the comma separates the lines
string[] lines =
{
"SETLOCAL EnableDelayedExpansion",
"SET adapterName=",
"FOR /F \"tokens=* delims=:\" %%a IN ('IPCONFIG ^| FIND /I \"ETHERNET ADAPTER\"') DO (",
"SET adapterName=%%a",
"REM Removes \"Ethernet adapter\" from the front of the adapter name",
"SET adapterName=!adapterName:~17!",
"REM Removes the colon from the end of the adapter name",
"SET adapterName=!adapterName:~0,-1!",
//the variables that were set before are used here
"netsh interface ipv4 set address name=\"!adapterName!\" static " + STATIC + " " + STATIC + " " + DEFAULTGATEWAY,
"netsh interface ipv4 set dns name=\"!adapterName!\" static " + DNS + " primary",
"netsh interface ipv4 add dns name=\"!adapterName!\" 8.8.4.4 index=2",
")",
"ipconfig /flushdns",
"ipconfig /registerdns",
":EOF",
"DEL \"%~f0\"",
""
};
//this writes the string to the file
using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
{
//This writes the file line by line
foreach (string line in lines)
outputFile.WriteLine(line);
}
System.Diagnostics.Process.Start(path1);
}
Like I said. It may be a little overcomplicated but it never fails unless I write the batch commands wrong.

Categories

Resources