Redirecting Standard Output from a Process (msxsl.exe) to a string in VB.NET - vb.net

I am writing a command line application in VB.NET. This application is calling another one, msxsl.exe, to run an XSL transform. I am using the Process class to do this:
Dim process = New Process()
process.StartInfo.FileName = "msxsl.exe"
process.StartInfo.Arguments = "base.xml test.xsl -o styled.xml"
process.StartInfo.UseShellExecute = False
process.StartInfo.CreateNoWindow = True
process.StartInfo.RedirectStandardOutput = True
process.Start()
This part works great. What I want it to be able to display the output from this process to the console of my application. I have read several posts explaining this method, but it does not seem to work in this case. The output is an empty string.
Dim output As String = process.StandardOutput.ReadToEnd()
process.WaitForExit()
Console.WriteLine(output)
I have verified that if I run the msxsl executable on its own (i.e. running "msxsl.exe base.xml test.xsl -o styled.xml"), it displays output on the command line. What am I doing wrong?
EDIT: I should note that the msxsl process is currently failing due to a malformed XML file. It is displaying this error message:
Error occurred while executing stylesheet 'test.xsl'.
Code: 0x800c0006
The system cannot locate the object specified.
This is exactly the type of thing I want displayed in the console of my application (or, eventually, a log file.)

This is probably because this isn't standard output it is StandardError you will want to redirect StandardError like so Process.StartInfo.RedirectStandardError = True and then read that into a string.
Dim ErrorString As String = Process.StandardError.ReadToEnd()

Related

Process.Start PDF in a folder

I can't get Process.Start to simply launch a PDF with default PDF viewer.
I tried so many combinations of shell execute, working folder etc etc. Keeps giving me either 'The system cannot find the file specified' or 'the directory name is invalid'
private void button1_Click(object sender, EventArgs e)
{
string filename = #"Milking and cooling software set 2018-39.pdf";
MessageBox.Show(currentpath + #"\Astronaut A5 v1.5(b7)\documentation\" + filename);
fullpath = currentpath + #"\Astronaut A5 v1.5(b7)\documentation";
fullfile = fullpath + filename;
ProcessStartInfo process = new ProcessStartInfo();
process.WorkingDirectory = fullpath;
process.UseShellExecute = false;
process.FileName = fullfile;
process.RedirectStandardOutput = true;
process.Verb = "run as";
Process.Start(process);
}
Why is this so hard, I have tried for hours to simply lauch Acrobat Reader to open a PDF file. I can double click it no problem in it's location but C# can't open it, either I get .NET errors or Adobe opens and says it can't find the file. Tried so many combinations of "\"", full path, hard coded path etc etc...unbelievable that this is so hard to code in this day and age.
You’ve told the system to not use ShellExecute. This means the path you’re giving should be an actual executable program. PDFs are not so if you want to open it with the default reader use ShellExecute.
process.UseShellExecute = true;
Also using “run as” as the verb doesn’t make any sense here, unless there is such a verb defined for PDFs which I’m pretty sure there isn’t. That should be removed.

Executable app(.exe) not running via the ASP.Net Webservice(.asmx)

I want to execute a process from the ASP.Net Webservice(.asmx).
In the Webservice hosted directory, I have a executable app in "importerapp" folder of the webservice directory. My executable app is ( Named as Import.exe) is working good by double clicking.
My webservice is running with no error but the process is not executed.
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string executeProcess(RunMode mode )
{
Process process = new Process();
process.StartInfo.FileName = Server.MapPath("importerapp/Import.exe");
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.Arguments = "mode=" + (int)_runMode ;
process.Start();
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
return("Job Submitted OK with params: "+_runMode + error
+ output +"Exit Code:"+ process.ExitCode );
}
In the browser, The output is as below.
<string xmlns="http://tempuri.org/">Job Submitted OK with
params: Exit Code:0</string>
That means, the "error" and "output" variable is null and exit code is 0 which means success.
But the processing is not doing anything, even not creating logfile( I am using nLog library).
Environment: WIndows7, IIS 7.5, .Net4.0, C#, ASP.Net
Please advise.
Thanks.
Ruhul
Job Submitted OK with params: Exit Code:0
This, according to your code, means that _runMode variable is not initiated. I think you forget to pass the parameter mode to your process

Why won't ArrayList.execute() use given arguments?

I'm trying to run a batch script on windows using groovy. I started with this code:
StringBuilder output = new StringBuilder()
StringBuilder error = new StringBuilder()
dir = new File("$homedir")
Process proc = "pathToScript\script.bat --arg test".execute(null, dir)
proc.consumeProcessOutput(output, error)
proc.waitFor()
print proc.exitValue()
This code works just fine for my scripts, but some commands don't play nice, so I decided to start using an ArrayList to store the arguments. So now my code looks like this:
StringBuilder output = new StringBuilder()
StringBuilder error = new StringBuilder()
dir = new File("$homedir")
ArrayList command = ["pathToScript\script.bat", "--arg test"]
Process proc = command.execute(null, dir)
proc.consumeProcessOutput(output, error)
proc.waitFor()
print proc.exitValue()
Now for some inexplicable reason it runs script.bat without the arguments. I've printed out the list to be sure it contains the arguments properly, which it does, so I'm not sure why the execute method isn't using them.
Try:
ArrayList command = ["pathToScript\script.bat", "--arg", "test"]
When an instance of List is used as source for execute() all arguments should be passed separately.

Getting No application is associated with the specified file for this operation while executing AutoIt scripts from vb.net

I have installed AutoIt on my machine. Its working ok on one machine but same configuration and code is not working on other. Any idea what I am missing?
Following error
Could not start process Z:\test\AutoItScripts\test.au3
No application is associated with the specified file for this operation
Also autoit script successfully executes from command line. Its just getting this error while using the following code to execute
objProcess = New System.Diagnostics.Process()
objProcess.StartInfo.Verb = "runas"
objProcess.StartInfo.Arguments = Argument
objProcess.StartInfo.FileName = ProcessPath
objProcess.Start()
'Wait until it's finished
objProcess.WaitForExit()
'Exitcode as String
Console.WriteLine(objProcess.ExitCode.ToString())
objProcess.Close()
Because AutoIt3 scripts are not themselves executable, you will need to be using shellexecute.
p.UseShellExecute = true;
Process compiler = new Process();
compiler.StartInfo.FileName = sExeName;
compiler.StartInfo.Arguments = sParameters;
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();
Console.WriteLine(compiler.StandardOutput.ReadToEnd());

Filetype check in VB.NET?

I have an image resized program and it works. The problem is when a user selects a non-image file in the file select dialog, it crashes. How can I check for image files?
UPDATE: 2022-04-05
Since it may not be feasible to validate the binary structure of every supported image, the fastest way to check if a file contains an image is to actually load it. If it loads successfully, then it is valid. If it doesn't then it is not.
The code below can be used to check if a file contains a valid image or not. This code is updated to prevent locking the file while the method is called. It also handles resource disposal after the tests (thanks for pointing out this issue user1931470).
Public Function IsValidImage(fileName As String) As Boolean
Dim img As Drawing.Image = Nothing
Dim isValid = False
Try
' Image.FromFile locks the file until the image is disposed.
' This might not be the wanted behaviour so it is preferable to
' open the file stream and read the image from it.
Using stream = New System.IO.FileStream(fileName, IO.FileMode.Open)
img = Drawing.Image.FromStream(stream)
isValid = True
End Using
Catch oome As OutOfMemoryException
' Image.FromStream throws an OutOfMemoryException
' if the file does not have a valid image format.
isValid = False
Finally
' clean up resources
If img IsNot Nothing Then img.Dispose()
End Try
Return isValid
End Function
ORIGINAL ANSWER
⚠️⚠️ WARNING ⚠️⚠️
This code has a bug that causes a high memory consumption when called several times in a program's lifetime.
DO NOT USE THIS CODE!!
Here's the VB.NET equivalent of 0xA3's answer since the OP insisted on a VB version.
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
Catch generatedExceptionName As OutOfMemoryException
' Image.FromFile throws an OutOfMemoryException
' if the file does not have a valid image format or
' GDI+ does not support the pixel format of the file.
'
Return False
End Try
Return True
End Function
You use it as follows:
If IsValidImage("c:\path\to\your\file.ext") Then
'do something
'
Else
'do something else
'
End If
Edit:
I don't recommend you check file extensions. Anyone can save a different file (text document for instance) with a .jpg extension and trick you app into beleiving it is an image.
The best way is to load the image using the function above or to open the first few bytes and check for the JPEG signature.
You can find more information about JPEG files and their headers here:
http://www.fastgraph.com/help/jpeg_header_format.html
http://en.wikipedia.org/wiki/JPEG
A very primitive check is to simply try to load the image. If it is not valid an OutOfMemoryException will be thrown:
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
return true;
}
If I understood your question correctly your application it going to load the image anyway. Therefore simply wrapping the load operation in a try/catch block does not mean any additional overhead. For the VB.NET solution of this approach check the answer by #Alex Essilfie.
The ones wondering why Image.FromFile is throwing an OOM on invalid files should read the answer of Hans Passant to the following question:
Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?
Your first line of defense, of course, would be simply to check the file's extension:
Function IsImageFile(ByVal filename As String) As Boolean
Dim ext As String = Path.GetExtension(filename).ToLowerInvariant()
' This supposes your program can deal only with JPG files; '
' you could add other extensions here as necessary. '
Return ext = ".jpg" OrElse ext = ".jpeg"
End Function
Better yet, as SLC suggests in a comment, set your dialog's Filter property:
dialog.Filter = "Image files|*.jpg;*.jpeg"
This isn't a guarantee -- ideally you'd want to check the file itself to verify it's an image, and theoretically you should also be able to load files with anomalous extensions if they are in fact image files (maybe just ask for the user's acknowledgement first) -- but it's an easy start.
The VB and C# answers are great but also contain a "gotcha" if you plan to alter or move the file: the created 'img' object will lock the image file unless the dispose() method is invoked to release it. See below:
VB
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
img.dispose() ' Removes file-lock of IIS
Catch generatedExceptionName As OutOfMemoryException
' Image.FromFile throws an OutOfMemoryException
' if the file does not have a valid image format or
' GDI+ does not support the pixel format of the file.
'
Return False
End Try
Return True
End Function
C#
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
img.dispose(); // Removes file-lock of IIS
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
return true;
}
The most robust way would be to understand the signatures of the files you need to load.
JPEG has a particular header format, for example.
This way your code won't be as easily fooled if you just look at the extension.
163's answer should get you most of the way along these lines.