Launching and Controlling External Applications from VB.NET Application

Today we will see how to launch external applications from within VB.NET application and control its input and output. For this demo, we will make our own Command Prompt – a form from where you can execute DOS commands and get the result too.

The Problem

How to control an external program from within our VB.NET application, send input to it and get output from it.

The Solution

Start a new application (or add a form to your application).

Add two textboxes and a button to it.

Set the following properties:

TextBox1

Name       = OutputTextBox
Multiline  = True
ReadOnly   = True
Scrollbars = Both

TextBox2

Name       = InputTextBox
TabIndex   = 0

Button1

Name       = ExecuteButton
Text       = Execute

Arrange the controls on the form appropriately. See screenshot below:

Open the code window and add the following code:

Private WithEvents MyProcess As Process
Private Delegate Sub AppendOutputTextDelegate(ByVal text As String)

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Me.AcceptButton = ExecuteButton
    MyProcess = New Process
    With MyProcess.StartInfo
        .FileName = "CMD.EXE"
        .UseShellExecute = False
        .CreateNoWindow = True
        .RedirectStandardInput = True
        .RedirectStandardOutput = True
        .RedirectStandardError = True
    End With
    MyProcess.Start()

    MyProcess.BeginErrorReadLine()
    MyProcess.BeginOutputReadLine()
    AppendOutputText("Process Started at: " & MyProcess.StartTime.ToString)
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    MyProcess.StandardInput.WriteLine("EXIT") 'send an EXIT command to the Command Prompt
    MyProcess.StandardInput.Flush()
    MyProcess.Close()
End Sub

Private Sub MyProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.ErrorDataReceived
    AppendOutputText(vbCrLf & "Error: " & e.Data)
End Sub

Private Sub MyProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles MyProcess.OutputDataReceived
    AppendOutputText(vbCrLf & e.Data)
End Sub

Private Sub ExecuteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExecuteButton.Click
    MyProcess.StandardInput.WriteLine(InputTextBox.Text)
    MyProcess.StandardInput.Flush()
    InputTextBox.Text = ""
End Sub

Private Sub AppendOutputText(ByVal text As String)
    If OutputTextBox.InvokeRequired Then
        Dim myDelegate As New AppendOutputTextDelegate(AddressOf AppendOutputText)
        Me.Invoke(myDelegate, text)
    Else
        OutputTextBox.AppendText(text)
    End If
End Sub

Run the code. Enter any DOS command in the InputTextBox and press enter (or click Execute button). The output should appear in the OutputTextBox.

If you are not familiar with DOS, type HELP and it should show you the list of all commands it recognizes.

Enjoy!

How & Why this Works

MyProcess is declared WithEvents so that we can trap the events it raises.  Alternatively you may put a Process control to your form.

Setting the CreateNoWindow property instructs it that we do not want it to show any window (in this case, the black command prompt window it would normally show).

We redirect the standard Input, Output and Error streams so that we can handle them ourself. We provide it the input from our InputTextBox, and get the output/error in our  OutputTextBox.

This technique would only work for applications that use the standard input/output (StdIn/StdOut/StdErr).

Future Enhancements

There is no error handling added here for the simplicity of demo. You should always add appropriate error handlers where there is a chance of error occurring.

Disclaimer

Beware that some DOS commands can be harmful to your system. e.g. If you execute a FORMAT /  DEL etc. commands, the deleted files would be unrecoverable.

Execute DOS commands at your own risk. I take no responsibility for any damage caused to your system whatsoever.

EDIT: 31-may-2012 — Applied syntax highlighter tags to code

Advertisements

68 Responses to “Launching and Controlling External Applications from VB.NET Application”

  1. Daniel Says:

    Brillian Pradeep, works beautiful, the best example of Process that I have found (and I have searched a lot), thanks for sharing!

  2. Daniel Says:

    Hi Pradeep, one question about your solution: is it possible to add a progress bar (marquee) that indicates that MyProcess is active? If yes, how should it be implemented?

    Thanks again!

    • pradeep1210 Says:

      If I’m not wrong, you need the progress bar to begin when you type a command and hit enter and to reach 100% until it is ready again. e.g. When you issue COPY command, progress bar starts when you begin copying and progresses as and when files are copied to destination folder, reaching 100% when it finises.

      Unfortunately this is not possible. Understand that this is just a pretty interface for the DOS window you are used to seeing. You don’t have any way to monitor the progress of a DOS command. So such a progressbar can’t be implemented here.

      • Daniel Says:

        Thanks for your reply Pradeep. Is there a way to know that the DOS command has finished?

      • pradeep1210 Says:

        This depends on the command being executed. If it provides some output that can be identified as its end, then you can check for that in the MyProcess_OutputDataReceived event. Otherwise I think there is no other way.

  3. Daniel Says:

    I’ll explore a bit more and if I find an alternative, I’ll let you know. Cheers!

    • pradeep1210 Says:

      Here is a workaround. Though it is really a DOS trick and not much to do with the program itself.
      1. Modify the body of MyProcess_OutputDataReceived procedure as follows:

      AppendOutputText(vbCrLf & e.Data)
      If e.Data = “FINISHED EXECUTING” Then
          ” Do whatever you want to do here.
          ” e.g. I show a messagebox here.
          MessageBox.Show(“FINISHED EXECUTING”)
      End If

      2. Now when you want to execute any command, append && ECHO FINISHED EXECUTING to it.
      e.g. DIR C: /s && ECHO FINISHED EXECUTING

  4. Daniel Says:

    Fantastic:-)

    • Daniel Says:

      Currently, I”m automating console apps via CMD (like sftp), so ECHO is not a good option. What I”m trying now and is working fine so far, is:

      Do While tmp OutputTextBox.Text

      tmp = OutputTextBox.Text
      Application.DoEvents()
      System.Threading.Thread.Sleep(1000)
      Loop

      so it exits when there is no more StandardOutput, what do you think about it?

      • pradeep1210 Says:

        It looks like if the DOS command doesn’t output anything for more than 1 second, this won’t work. This would work only if something is being output continuously to the textbox. So it is unreliable.
        Also in cases where it works, you lose extra 1 second after the DOS command has finished executing.

        I think a better & more reliable alternative would be:
        1. Before execution, generate a unique temp filename, or simply delete the file if it exists so that you know you didn’t have any file with that name.
        2. Instead of ECHO command, just use the appropriate DOS command (or .BAT file) to create that file at some specific location. (say %temp% folder etc.)
        3. Now in your program you can easily check for existence of that file. If it exists you know that the DOS command has finished processing.

        You can easily modify the methods in this program to accommodate this algorithm.

  5. Daniel Says:

    I opened a new thread to control, so actually the 1s pause only affects the new thread, the CMD process goes on. I’ve added a string control (if theLastString = $xxx) and set a variable time control (the 1s is to control the login, which is the difficult part to check: where do you add the temp file at this moment?). The best solution would be to know if OutputStandard is receiving data or not, does it have a “ReadyState” or something like that?

  6. Ashok Says:

    Hi Pradeep, How can I cature a message box out from the external application from vb .net?

    • pradeep1210 Says:

      There is no direct way. There might be methods using APIs to capture the window handle and get the text from it. But this article doesn’t deal with that topic. It deals only with applications that use the standard input/output streams (as also stated in the article).

  7. BrianS Says:

    Hey I’ve been looking for reasons why I couldn’t make sending and receiving input from the process created and your explainations about using WithEvents have helped alot. Thank you very much for taking the time out to create this solution.

  8. Coder Says:

    Absolutely excellent, keep up the good work

  9. Palugdo Says:

    Can U Show how to the progress of that application in progress bar

  10. Code Engineer Says:

    WOW! That’s a great post. Can we make something like this to be operated from remote?

  11. SergeMorel Says:

    I’m trying to use this with a batch file (RUN.bat).
    Everything runs fine on startup & it gets the output.
    But the input doesn’t work. I have no idea why , you have an idea & how to fix this?
    Thanks in advance

  12. Jaro Says:

    Hello. I am running some external command line tool within VB2010. This tool runs for a while and during that time shows the percentage progress 0 – 100 % increasingly in cmd window. Then it finish. Is that any way, how can I catch this percentage as output during its work ? Would be great to use it for VB progressbar.

  13. Fred Says:

    Brilliant code very nice

    How can i get rid of the input text box and just have set command like
    c:\apps\tools\
    execute nandpro usb: -r16 nand1.bin
    for loop
    execute cmd nandpro usb: -16 nand2.bin

    Cheers
    Fred

  14. Fred Says:

    first thanks for quick reply.

    I kind of understand it – what i trying to acomplish is

    it needs to go to first i.e “c:\apps\tools\ ” folder where the program is – then if I have 2 radio buttons where if i click one it

    send the command “nandpro usb: -r16 nand1.bin”

    which then reads your nand chip or

    if I press radio button 2 it sends “nandpro usb: -r64 nand1.bin”

    which reads 64mb nand chip

    I need this process to “for loop 3 times” each time renaming the nand save i.e nand1.bin for first read , nand2.bin second read, nand3.bin third read.

    willing to off some payment if needed

    • pradeep1210 Says:

      I’m not sure if I can suggest some generic solution for this, until I get into the details of your problem. You can get me privately on my email (see about page) and I’ll be glad to help you. 🙂

  15. Robert Snow (@Soulflare3) Says:

    This works really well, but I have run into an issue I haven’t figured out how to fix. After sending a command the program will wait until the activity has stopped before doing anything else. This is fine, but not for the program I am making (It’s controlling a java application) I need to be able to send different commands while it is running, for example to control the secondary application, to cancel a command, etc. Any ideas?

  16. Emil Says:

    Hi, great tutorial.
    It is possible to make psexec work in this way ? Because I tried to modiffy the filename to “psexec” and put some arguments but it’s not working.
    I got this “StandardIn has not been redirected.” error when debugging.
    I also tried to run psexec from the application, but the output of psexec it’s written in the OutputTextBox with an “errror *” in front….

    • pradeep1210 Says:

      Changing the following line in MyProcess_ErrorDataReceived should solve your problem:
      Change:
      AppendOutputText(vbCrLf & “Error: ” & e.Data)
      To:
      AppendOutputText(vbCrLf & e.Data)

  17. Emil Says:

    Thanks for your answer. The problem is not with the “Error: ” message. As you know when you start psexec.exe application it will start a new window. What I’m trying to do is to start the psexec.exe window somethink like this:

    psexec \\computername -u “username” -p “password” /s /i cmd

    the problem is that when I run this command in a cmd.exe it will start another cmd.exe window from the system account.

    I want to know if it’s possible to embed that window in windows form as you did with “cmd.exe” and run there commands.
    Thank You,
    Emil

    • pradeep1210 Says:

      OK. So you need to modify the Form_Load code and pass in the Arguments.
      With MyProcess.StartInfo
      .FileName = "C:\Temp\PsTools\PsExec.exe"
      .Arguments = "-u username -p password /s /i cmd"
      .UseShellExecute = False
      .CreateNoWindow = True
      .RedirectStandardInput = True
      .RedirectStandardOutput = True
      .RedirectStandardError = True
      End With

      Since you are requesting to run the CMD application here, so that (black) application window will show.

      If you want to completely get rid of the black window, then you would need to build a new application with the original code as in this article, so that CMD is launched inside this application. Then copy the exe to client machine and execute that exe via PsExec.

  18. Emil Says:

    Hi,
    Thanks for answering me. Maybe you didn’t understood well what I’m trying to do.
    In “OutputTextBox” is captured the output from CMD commands when you click on “Execute” button (following you code above).
    If I run “psexec \\comp -u username – p password /s cmd” inside app form it will start a new CMD window outside of the main form. What I’m trying to do is to find a way to capture that CMD window started with psexec output and send input to it using the second text box and execute button.
    I already changed the command and arguments as you posted above but the only output that I got is:

    Process Started at: 4/4/2012 3:20:33 PM

    PsExec v1.98 – Execute processes remotely
    Copyright (C) 2001-2010 Mark Russinovich
    Sysinternals – http://www.sysinternals.com

    and after that I can type anything in command text box and click execute because it will not do nothing. I can see that the cmd process will start on remote machine but I cannot send anything to it.

    So is there a way to redirect output and input from and to CMD process started by psexec in OutputTextBox?
    Psexec I think it’s parent process and CMD started by it is it’s child.
    Thank you!

    • pradeep1210 Says:

      No, that won’t work.

      The PsExec launches the application (CMD window), and we don’t have the handle of the application. You may be able to enumerate the system processes and find out the process of that window. Though I’m not sure if there is any sure shot way of identifying that window there.

  19. jonathan Says:

    Hi i ve tried it and does not work … when i try i get syntax error

    • pradeep1210 Says:

      It’s hard to tell anything unless you provide more details.
      Which line of code causes error?
      What is the error message?
      Did you try just the exact same code or with modifications?

      • jonathan Says:

        I am Using the exact same code. I want to make the code work first then I will go on and see for modification ….
        When I use same exact code her is th eoutput of the errors:

        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(8) : error BC30203: Identifier expected.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(10) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(46) : error BC30203: Identifier expected.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(48) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(50) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(62) : error BC30203: Identifier expected.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(64) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(66) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(68) : error BC30451: ‘e’ is not declared. It may be inaccessible due to its protection level.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(74) : error BC30203: Identifier expected.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(76) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(78) : error BC30035: Syntax error.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(80) : error BC30451: ‘e’ is not declared. It may be inaccessible due to its protection level.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(86) : error BC30203: Identifier expected.
        C:\Users\jonathan.boisvert\Documents\Modus FX\Visual Basic\Projects\Tech-Tool\Tech-Tool\Tech-Tool\CMD.vb(88) : error BC30035: Syntax error.

        In the code window I get some line like: ByVal e As System.EventArgs) Handles Me.Load –>>>> Byval is underline and says syntax error I get this error at multiple places ….

      • pradeep1210 Says:

        Are you sure that you your project is of Windows Forms Application type?
        It looks to me like you have created a Console Application or Class Library.

        What happens if you create a new Windows Forms Application and do whatever is mentioned in the article? Do you still face the same problems?

      • jonathan Says:

        Yes I am sure it is a windows forms Application. I have tried to do this in a new projects as you mentioned in the last reply and I get the same results …

      • jonathan Says:

        I am in visual basic windows form application…… and not a visual C# or C++ windows form application …. is this the problem??? if so how can I adapt this code for visual basic ….

      • pradeep1210 Says:

        The code is for Windows Forms Application (visual basic). So it should work. Looks strange!
        Which Visual Studio version are you using?

      • pradeep1210 Says:

        I just update the code in the post. Nothing much – just removed multiple line continuations. Just try with the new code and see if it makes any difference, though I doubt it will.

  20. jonathan Says:

    Visual basic 2010 … and YES it worked thank you very much

  21. luminess air Says:

    Pretty element of content. I simply stumbled upon your website and in
    accession capital to claim that I get in fact enjoyed account your blog posts.

    Any way I’ll be subscribing on your feeds or even I success you get admission to persistently fast.

  22. Alex Says:

    Thanks for the very helpful post. It works for me as described, however when I am closing the form I get an error in the Sub AppendOutputText under Me.Invoke(myDelegate,text) with the Error message Cannot access a disposed object. Object name:’Form1′ .

    • pradeep1210 Says:

      Since it was meant for demo purposes only, I tried to keep it as simple as possible for people to understand. The focus is on the working of the program, rather than handling errors etc. You may need to check the validity of the object in that call, or put a try..catch block around it, since you are closing the form anyways.

  23. Kristian B Says:

    Hello. I am trying to create an application where you can launch a Minecraft server and control the server inside my application. So I have added a button named “Lauch bukkit” and when it’s pressed it executes these codes
    (I dont know if “[CODE] works [/CODE] but)

    MyProcess.StandardInput.WriteLine("CD /D C:\Users\MyUsername\Documents\Server\nymappe\")
    MyProcess.StandardInput.WriteLine("java -Xmx1024M -Xms1024M -jar craftbukkit-1.3.2-R3.0.jar")
    MyProcess.StandardInput.Flush()
    TextBox2.Text = ""
    

    and then it launches the server all fine, but when I try to execute a command from InputTextBox it doesn’t work…
    How do I fix this?

    And when I set

    .CreateNoWindow = True
    
    to
    
    .CreateNoWindow = False
    

    then it opens a cmd window and if I type anything into the cmd window, it works.

  24. Neil Acevedo Says:

    When I try to run it (Windows Basic 2010 Express) with same code and design, everything is fine except this part:

    Me.AcceptButton = ExecuteButton
    MyProcess = New Process
    With MyProcess.StartInfo
    .FileName = “ipconfig.bat”
    .UseShellExecute = False
    .CreateNoWindow = True
    .RedirectStandardInput = True
    .RedirectStandardOutput = True
    .RedirectStandardError = True
    End With
    MyProcess.Start()

    MyProcess.BeginErrorReadLine()
    MyProcess.BeginOutputReadLine()
    AppendOutputText(“Process Started at: ” & MyProcess.StartTime.ToString)

    It says “Wind32Exception was unhandled” at the MyProcess.Start(), Solution?

    • pradeep1210 Says:

      “ipconfig.bat” is a file and not a program.
      You can choose to do either of the following two options:
      1. Pass that filename to cmd.exe
      .FileName = "cmd.exe c:\yourfilepath\ipconfig.bat"

      OR

      2. Execute cmd.exe and then write ipconfig.bat to the input:
      .FileName = "cmd.exe"
      ...

      MyProcess.StandardInput.WriteLine("ipconfig.bat")
      MyProcess.StandardInput.Flush()

  25. උදය Says:

    how to edit command run in separate windows

  26. qualakon Says:

    This is excellent, I have one question. How can you stop a continuous command? Usually it’s Ctrl-C but that’s not working. for example, ping -t google.com runs forever.

  27. waldopulanco Says:

    Hi! I have a proble with psexec.exe. here is the error

    here is the code
    “Me.AcceptButton = ExecuteButton
    MyProcess = New Process
    With MyProcess.StartInfo
    .FileName = “C:\PSTools\psexec.exe”
    .Arguments = “\\computer01 cmd”
    .UseShellExecute = False
    .CreateNoWindow = True
    .RedirectStandardInput = True
    .RedirectStandardOutput = True
    .RedirectStandardError = True
    End With
    MyProcess.Start()

    here is the output:

    Process Started at: 2/4/2016 8:56:15 PM

    PsExec v2.11 – Execute processes remotely
    Copyright (C) 2001-2014 Mark Russinovich
    Sysinternals – http://www.sysinternals.com

    Connecting to computer01…

    Microsoft Windows XP [Version 5.1.2600]
    Starting PSEXESVC service on computer01…

    Connecting with PsExec service on computer01…

    Starting cmd on computer01…

    cmd exited on computer01 with error code 0.

    As you notice it was successfully connected in computer01 but after that it was exited. so it will not accept any command..

    I hope you can help me. thanks in advance!

  28. Adaz Says:

    Hi,
    I cannot make it work on Windows’es older that Win10 ver1607.
    Please help me, the details are here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f6da734b-d39e-4fb7-9f5e-73245d0c7199/powershell-redirect-output-not-working?forum=vbgeneral

    Thank you,
    Adaz

    • pradeep1210 Says:

      If it is working on some systems and not on others, then I think it has more to do with system settings rather than anything in the program. I can just guess at the moment. Probably it is something related to security (antivirus, firewall, user privileges, administrative restrictions etc.), windows update, service pack or something related to system settings. But that’s just my best guess.
      Try figuring out what is common among those systems and is not on the systems that have it running successfully. That might help.

      • Adaz Says:

        The difference is the Windows version (as I mentioned).

        On a working environment, it displays an empty window with a blinking cursor, and it does not accept any input. The input is accepted from the app, and the output is displayed in the app’s text window.

        On a non-working environment, it displays the window, but powershell runs inside it, and accepts input from the command window, and the output is displayed in the command window as well.

        So powershell runs, but the redirection does not work for some reasons…

        Can you help me why?

        Thank you,

        Adaz

      • Adaz Says:

        Sorry, forgot to mention, that now I tried .CreateNoWindow = False

  29. Adaz Says:

    It works with cmd.exe, but not with powershell.exe. Can somebody explain this?

  30. Maciel Says:

    Hi Pradeep! My name is Maciel, from Brazil.
    I made the window prompt and it works. If I run the robocopy command by bat file, the prompt show me the paths of copied files, percentage progress of each file, etc. But… if I run the same command line in prompt inside de vb form, the textbox show me ONLY the percentage. Why? Could you help me please?

  31. Edson Sobreira Says:

    Hello Pradeep1210, thanks for sharing.
    I would like your help in somenthing:
    I realized that all examples I found, include this one, which is by the way, the most complete, only get information from CMD when the processing is over.
    Is there a way to get information from CMD on the fly?
    I have some processes made in pyton (to be a server between Arduino and Scratch 2.0) and AVRdude to flash Attiny85. Both use CMD console, however using VB, the screen freezes when I click the button, because the CMD still executing the command.
    Thanks!

    • pradeep1210 Says:

      There should be no reason for screen to freeze. I’m not sure about python how it works, but I tried with windows command prompt with a long running command and it works perfectly fine.

      I tried with the following command which gives a continuous output without freezing the window.
      ping 127.0.0.1 -t

      NB: The above is only for test. There is no good way to stop this in the sample code. You will have to close the form and end task command prompt from Task Manager.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: