1

ok, please do no laugh at this :x
i'm trying to create a simple software testing tool in VB.NET
i created a simple C program PROG.EXE which scans a number and prints the OUTPUT, and started building my tester, it should execute PROG.EXE output.txt, so PROG.EXE takes input from input.txt and prints the output to output.txt
but i failed, at first i tried Process.start then shell but nothing worked !
so i did this trick, the VB.NET codes generate a batch file with this codes PROG.EXE output.txt, but again i failed, though the VB.NET created the batch file and executes too, but nothing happened ! but when i manually run the batch file i got success !
i tried executing the batchfile then sendkey the VBCR/LF/CRLF still nothing happens !
whats wrong ?


My VB.NET Code, i am using Visual Studio 2010 Professional

Option Explicit On  
Option Strict On  
Public Class Form1  
 Dim strFileName As String

 Private Sub btnRun_Click() Handles btnRun.Click  
  Dim strOutput As String  
  Using P As New Process()  
   P.StartInfo.FileName = strFileName  
   P.StartInfo.Arguments = txtInput.Text  
   P.StartInfo.RedirectStandardOutput = True  
   P.StartInfo.UseShellExecute = False  
  P.StartInfo.WindowStyle = ProcessWindowStyle.Hidden  ' will this hide the console ?
   P.Start()  
   Using SR = P.StandardOutput  
    strOutput = SR.ReadToEnd()  
   End Using  
  End Using  
  txtOutput.Text = strOutput  
 End Sub

 Private Sub btnTarget_Click() Handles btnTarget.Click  
  dlgFile.ShowDialog()  
  strFileName = dlgFile.FileName  
  lblFileName.Text = strFileName  
 End Sub  
End Class  

And this is my C code

#include<stdio.h>  
#include<conio.h>

void main()
{
 int x;
 scanf("%d",&x);
 printf("%d",(x*x));
}

my program runs perfectly when i run prog.exe <input.txt> output.txt in console

casperOne
  • 73,706
  • 19
  • 184
  • 253
Sourav
  • 17,065
  • 35
  • 101
  • 159
  • I'm using Windows XP, Visual Studio 2010 Professional, and the PROG.EXE is written and compiled in Borland Turbo C – Sourav Apr 18 '11 at 02:52

2 Answers2

6

Below is a fully working example. You want to use the Process class as you tried but you need to RedirectStandardOutput on the process's StartInfo. Then you can just read the process's StandardOutput. The sample below is written using VB 2010 but works pretty much the same for older versions.

Option Explicit On
Option Strict On

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ''//This will hold the entire output of the command that we are running
        Dim T As String

        ''//Create our process object
        Using P As New Process()
            ''//Pass it the EXE that we want to execute
            ''//NOTE: you might have to use an absolute path here
            P.StartInfo.FileName = "ping.exe"

            ''//Pass it any arguments needed
            ''//NOTE: if you pass a file name as an argument you might have to use an absolute path
            P.StartInfo.Arguments = "127.0.0.1"

            ''//Tell the process that we want to handle the commands output stream
            ''//NOTE: Some programs also write to StandardError so you might want to watch that, too
            P.StartInfo.RedirectStandardOutput = True

            ''//This is needed for the previous line to work
            P.StartInfo.UseShellExecute = False

            ''//Start the process
            P.Start()

            ''//Wrap a StreamReader around the standard output
            Using SR = P.StandardOutput
                ''//Read everything from the stream
                T = SR.ReadToEnd()
            End Using
        End Using

        ''//At this point T will hold whatever the process with the given arguments kicked out
        ''//Here we are just dumping it to the screen
        MessageBox.Show(T)
    End Sub
End Class

EDIT

Here is an updated version that reads from both StandardOutput and StandardError. This time it reads asynchronously. The code calls the CHOICE exe and passes an invalid command line switch which will trigger writing to StandardError instead of StandardOutput. For your program you should probably monitor both. Also, if you're passing a file into the program make sure that you are specifying the absolute path to the file and make sure that if you have spaces in the file path that you are wrapping the path in quotes.

Option Explicit On
Option Strict On

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ''//This will hold the entire output of the command that we are running
        Dim T As String

        ''//Create our process object
        Using P As New Process()
            ''//Pass it the EXE that we want to execute
            ''//NOTE: you might have to use an absolute path here
            P.StartInfo.FileName = "choice"

            ''//Pass it any arguments needed
            ''//NOTE: if you pass a file name as an argument you might have to use an absolute path
            ''//NOTE: I am passing an invalid parameter to show off standard error
            P.StartInfo.Arguments = "/G"

            ''//Tell the process that we want to handle the command output AND error streams
            P.StartInfo.RedirectStandardOutput = True
            P.StartInfo.RedirectStandardError = True

            ''//This is needed for the previous line to work
            P.StartInfo.UseShellExecute = False

            ''//Add handlers for both of the data received events
            AddHandler P.ErrorDataReceived, AddressOf ErrorDataReceived
            AddHandler P.OutputDataReceived, AddressOf OutputDataReceived

            ''//Start the process
            P.Start()

            ''//Start reading from both error and output
            P.BeginErrorReadLine()
            P.BeginOutputReadLine()

            ''//Signal that we want to pause until the program is done running
            P.WaitForExit()


            Me.Close()
        End Using
    End Sub

    Private Sub ErrorDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        Trace.WriteLine(String.Format("From Error  : {0}", e.Data))
    End Sub
    Private Sub OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        Trace.WriteLine(String.Format("From Output : {0}", e.Data))
    End Sub
End Class

Its important that you put your entire file path in quotes if it has spaces in it (in fact, you should always enclose it in quotes just in case.) For instance, this won't work:

P.StartInfo.FileName = "attrib"
P.StartInfo.Arguments = "C:\Program Files\Windows NT\Accessories\wordpad.exe"

But this will:

P.StartInfo.FileName = "attrib"
P.StartInfo.Arguments = """C:\Program Files\Windows NT\Accessories\wordpad.exe"""

EDIT 2

Okay, I'm an idiot. I thought you were just wrapping a filename in angled brackets like <input.txt> or [input.txt], I didn't realize that you were using actual stream redirectors! (A space before and after input.txt would have helped.) Sorry for the confusion.

There are two ways to handle stream redirection with the Process object. The first is to manually read input.txt and write it to StandardInput and then read StandardOutput and write that to output.txt but you don't want to do that. The second way is to use the Windows command interpreter, cmd.exe which has a special argument /C. When passed it executes any string after it for you. All stream redirections work as if you typed them at the command line. Its important that whatever command you pass gets wrapped in quotes so along with the file paths you'll see some double-quoting. So here's a version that does all that:

Option Explicit On
Option Strict On

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ''//Full path to our various files
        Dim FullExePath As String = "C:\PROG.exe"
        Dim FullInputPath As String = "C:\input.txt"
        Dim FullOutputPath As String = "C:\output.txt"

        ''//This creates our command using quote-escaped paths, all completely wrapped in an extra set of quotes
        ''//""C:\PROG.exe" < "C:\input.txt" > "C:\output.txt""
        Dim FullCommand = String.Format("""""{0}"" < ""{1}"" > ""{2}""""", FullExePath, FullInputPath, FullOutputPath)
        ''//Create our process object
        Using P As New Process()
            ''//We are going to use the command shell and tell it to process our command for us
            P.StartInfo.FileName = "cmd"

            ''//The /C (capitalized) means "execute whatever else is passed"
            P.StartInfo.Arguments = "/C " & FullCommand

            ''//Start the process
            P.Start()

            ''//Signal to wait until the process is done running
            P.WaitForExit()
        End Using

        Me.Close()
    End Sub
End Class

EDIT 3

The entire command argument that you pass to cmd /C needs to be wrapped in a set of quotes. So if you concat it it would be:

Dim FullCommand as String = """""" & FullExePath & """" & " <""" & FullInputPath & """> " & """" & FullOutputPath & """"""

Here's what the actual command that you pass should look like:

cmd /C ""C:\PROG.exe" < "C:\INPUT.txt" > "C:\output.txt""

Here's a full code block. I've added back the error and output readers just in case you're getting a permission error or something. So look at the Immediate Window to see if any errors are kicked out. If this doesn't work I don't know what to tell you.

Option Explicit On
Option Strict On

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ''//Full path to our various files
        Dim FullExePath As String = "C:\PROG.exe"
        Dim FullInputPath As String = "C:\INPUT.txt"
        Dim FullOutputPath As String = "C:\output.txt"

        ''//This creates our command using quote-escaped paths, all completely wrapped in an extra set of quotes
        Dim FullCommand As String = """""" & FullExePath & """" & " <""" & FullInputPath & """> " & """" & FullOutputPath & """"""
        Trace.WriteLine("cmd /C " & FullCommand)


        ''//Create our process object
        Using P As New Process()
            ''//We are going to use the command shell and tell it to process our command for us
            P.StartInfo.FileName = "cmd"

            ''//Tell the process that we want to handle the command output AND error streams
            P.StartInfo.RedirectStandardError = True
            P.StartInfo.RedirectStandardOutput = True

            ''//This is needed for the previous line to work
            P.StartInfo.UseShellExecute = False

            ''//Add handlers for both of the data received events
            AddHandler P.ErrorDataReceived, AddressOf ErrorDataReceived
            AddHandler P.OutputDataReceived, AddressOf OutputDataReceived

            ''//The /C (capitalized) means "execute whatever else is passed"
            P.StartInfo.Arguments = "/C " & FullCommand

            ''//Start the process
            P.Start()


            ''//Start reading from both error and output
            P.BeginErrorReadLine()
            P.BeginOutputReadLine()


            ''//Signal to wait until the process is done running
            P.WaitForExit()
        End Using

        Me.Close()
    End Sub
    Private Sub ErrorDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        Trace.WriteLine(String.Format("From Error  : {0}", e.Data))
    End Sub
    Private Sub OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        Trace.WriteLine(String.Format("From Output : {0}", e.Data))
    End Sub
End Class
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • @Chris Haas Your code worked perfectly for the ping but not for the program i have written in C, so please see my post ! – Sourav Apr 13 '11 at 02:49
  • @Chris Haas - thanks for trying again ! but it did not worked for a program which i made with BORLAND TURBO C 2.0 :( – Sourav Apr 13 '11 at 14:13
  • @Sourav, see my **EDIT 2** above. I wasn't understanding that you were using stream redirection. – Chris Haas Apr 14 '11 at 13:33
  • @Chris Haas Your code creates an EMPTY OUTPUT.TXT file when executing from VB.NET ! but if i execute the same command from CMD i get OUTPUT.TXT with results in it ! :( – Sourav Apr 16 '11 at 03:34
  • see my edits too -> Dim FullCommand = """" & FullExePath & """" & " <""" & FullInputPath & """> " & """" & FullOutputPath & """" – Sourav Apr 16 '11 at 03:37
  • @Chris Haas see my edits too -> Dim FullCommand = """" & FullExePath & """" & " <""" & FullInputPath & """> " & """" & FullOutputPath & """" [I'm using XP, and the programme i am trying to test is compiled with Borland Turbo C] – Sourav Apr 17 '11 at 03:46
  • @Sourav, I added a third and last edit that hopefully will help you. You need to wrap the entire command that you pass to `CMD /C` in an additional set of quotes. – Chris Haas Apr 18 '11 at 13:30
  • @Chris Haas, you got 50 :) but need one more thing to know ! I want to write the output to output.txt and also show it in a textbox, so i did this "Using SR = P.StandardOutput OutPut = SR.ReadToEnd():msgbox(OutPut) End Using" -> copy paste from your code, but it shows a blank msgbox, can you help me on that ? – Sourav Apr 18 '11 at 13:47
  • @Sourav, unfortunately you're trying to mix two things that don't mix. The stream redirectors `>` and `<` are taking precedence over your code. You can use .Net's stream redirection (`StandardInput`, `StandardOutput`) or the command line's but not both. The only way to read the contents of the file would be to do it manually. `Dim S = My.Computer.FileSystem.ReadAllText(FullOutputPath)`. I would do that outside of the `Using` statement because the .Net code might finish before the disk is completely done be written to. – Chris Haas Apr 18 '11 at 15:10
  • @Sourav, I'm glad everything worked out. Next to my answer there should be a bounty icon that you can click to close out the bounty. – Chris Haas Apr 19 '11 at 12:47
  • I've clicked on it multiple times, but nothing happens :( – Sourav Apr 19 '11 at 13:37
1
Public Class attributeclass
  Public index(7) As ctrarray
End Class

Public Class ctrarray
  Public nameclass As String
  Public ctrlindex(10) As ctrlindexclass
End Class

Public Class ctrlindexclass
  Public number As Integer
  Public names(10) As String
  Public status(10) As Boolean

  Sub New()
    number = 0
    For i As Integer = 0 To 10
        names(i) = "N/A"
        status(i) = False
    Next
  End Sub
End Class

Public attr As New attributeclass

Sub Main()
  attr.index(1).nameclass = "adfdsfds"
  System.Console.Write(attr.index(1).nameclass)
  System.Console.Read()
End Sub
LarsTech
  • 80,625
  • 14
  • 153
  • 225
grishmak
  • 11
  • 1