Xaprb

Stay curious!

How to create a VB6 console program

with 33 comments

Visual Basic 6 programs can be run as console programs, if configured correctly. There are four basic requirements to create a useful console program in VB6:

  • Remove all forms and dialogs
  • Provide access to standard input, output, and error streams
  • Provide access to the command-line arguments
  • Re-link the program for the Windows Console subsystem

Remove forms and dialogs

By default, a VB6 project has “forms” or “windows,” which can contain application code. When running a program in the console, you don’t want anything but the console, ever. When you create a VB6 project, just remove all the forms from it, and add a module. You need at least one module, which will contain a subroutine called Main(). When you look at the project properties, you will see the “startup object” set to Sub Main.

There is still a possibility that some dialogs can be created. For example, a runtime error will pop up a dialog. To avoid this, choose the “Unattended Execution” checkbox in the Project Properties dialog. By default, dialogs will now be shunted to the Windows Event Log. You can control this with the App.StartLogging method, if desired.

Get access to stdio streams

A console app usually needs to work with standard input and output. There are at least two ways to accomplish this: by using the Win32 API, and by using the Scripting.FileSystemObject‘s text streams. In either case, the streams will not be available when running the app in the debugger, so it may be a good idea to create a wrapper around the calls and only try to use them if they are available. The Win32 API calls are easy to use, and I have posted sample code for your reading pleasure. The Scripting.FileSystemObject‘s text streams are equally easy to use. Microsoft’s FileSystemObject documentation should help you get started on those. You will need to add a reference to “Microsoft Scripting Runtime” in your project to use the FileSystemObject.

Get access to command-line arguments

The text of the command-line arguments with which the VB6 console app was invoked is available by calling the Command() function, but it is non-trivial to parse the text into individual arguments such as those C programmers are used to using. It’s not impossible; depending on your needs you may be able to use regular expressions, the Split() function, a tokenizer (finite state machine), or invoke the Win32 API again by calling the CommandLineToArgvW function. The latter uses Unicode, so you will need to convert between VB strings and Unicode. The StrConv() function will help here, but on the reverse conversion you will need to do a bit more. Google will provide many links to examples of using these two functions for this job.

Re-link the program for the Windows Console subsystem

There seems to be no option in the VB project properties or compile options to do this automatically when making the program, so you will need to re-link after compilation. If you don’t do this, your program will not run correctly. The standard streams will not be available, for one thing. Fortunately, it is quite easy to do:

"C:\Program Files\Microsoft Visual Studio\vb98\LINK.EXE" /EDIT /SUBSYSTEM:CONSOLE <yourfile.exe> (this code should all be on one line).

A handy shortcut is to create a batch file with the command in it. You can then drag your .EXE file onto the batch file. Assuming LINK.EXE is in your path, the following will work:

LINK.EXE /EDIT /SUBSYSTEM:CONSOLE %1

Don’t name the batch file “link.bat” or it will call itself! Another of Microsoft’s insecure default behaviors.

Acknowledgements

I have gleaned this code from all over the Internet. Very little of it is my own.

Written by Baron Schwartz

October 14th, 2005 at 1:00 pm

Posted in Uncategorized

33 Responses to 'How to create a VB6 console program'

Subscribe to comments with RSS

  1. Wow, an on-point article that is easy to read with a quick answer to the question I’ve got. That, and the suggestions really work, too! Kudos!

    Brad

    Brad

    11 Jan 06 at 4:26 pm

  2. Excellent article, easy to follow, thank you!

    Marcos

    27 Jan 06 at 11:48 am

  3. Yes – very handy and easy to follow… good job!

    Rob

    21 Apr 06 at 10:45 am

  4. One of the best useful solution to quite simple but insufficiently documented problems. Thanks.

    Arun

    12 May 06 at 2:44 pm

  5. Yeah, I like this code. Many thanks ;)

    Robert Tuan

    17 May 06 at 1:14 am

  6. Thanks man. That REALLY help me a lot. Thank you very much!!

    Diogo Costa

    20 May 06 at 11:31 am

  7. Thanks, that’s just the thing I was looking for.

    srosh

    1 Jul 06 at 3:33 pm

  8. Thanks, this was exactly what I was looking for. Just one little “glitch” remains. I have an app that I would like to be gui if run without cmd line arguments, but console if the user requests it. So if I link with the console subsystem but run the program without arguments (like dbl-clicking it in explorer), I get a console that pops up and then my app… Any ideas how to avoid this?

    Thanks

    David

    3 Jul 06 at 8:48 am

  9. David, I’ve not been programming in the Windows world for a while so I can’t test this, but as I recall I’ve never been able to make any program linked with the console NOT start the console. I don’t know the internals of how it works, though.

    Xaprb

    3 Jul 06 at 10:28 am

  10. Thanks Xaprb. I thought about it some more and couldn’t actually find an example of an app that did what I was asking… guess it doesn’t really matter.

    David

    5 Jul 06 at 1:57 am

  11. Nice trick!

    tuanpa

    19 Jul 06 at 8:19 pm

  12. Great article.

    Ramin

    2 Aug 06 at 5:40 pm

  13. Thanks for the concise article.

    I was hoping to send commands to the console via my VB6 application. It appears that these commands are treated as text, rather than commands. I tried testing this by sending ‘pause’ to console. It simply writes the word pause, rather than executing the Pause command.

    Thoughts?

    Craig

    11 Aug 06 at 11:05 am

  14. I think you can create an object that represents the system shell and tell it to do things. Something like CreateObject(“System.Shell”)? I’m sorry I can’t be more help, as I’ve been away from VB6 and Windows for quite a while. I can’t recall much about it now.

    Xaprb

    11 Aug 06 at 11:12 am

  15. In response to Craig:

    Maybe you can use the CallByName function? Unfortunately it’s not possible (as far as I know) to call standard Visual Basic functions using this function, but if you don’t need very much commands, it might be a possibility to create wrapper-functions for each function and call these wrappers using CallByName.

    Bram

    20 Aug 06 at 4:37 pm

  16. To Craig:

    The commands in this example are supposed to display the text on the console only. Most of common “DOS-style” commands are actually handled by a special console application (in Windows it is usually cmd.exe, the exact location is given by the ComSpec environment variable). You would have to execute that application and use your command as a command line parametr, probably together with “/C”:

    C:\WINDOWS\system32\cmd.exe /C pause

    It is possible to execute such command by the VB6 Shell function, but I’m afraid that this function is not aware that your application might be a console application and will actually create a new console for the CMD.EXE. (I didn’t try this, however). In that case you would have to use Windows API to run other console applications (namely CreateProcess and probably WaitForSingleObject) – but that’s a good amount of work. It’s really not worth for “pause” commands, I’d say its not worth for “dir” either.

    However, you can use Shell even in normal VB6 application and run a DOS command as above, only using /K instead of /C on the CMD.EXE command line. This will open a new console, execute the given command (it may even be any other console application, eg. xcopy, or a batch file) and leave the console window open. Until this console is closed (try “EXIT” command), it can be used for entering additional commands by hand.

    Martin

    14 Sep 06 at 2:30 am

  17. A small update to my previous post:

    Using the Shell function to execute another console application will not create another console, if the current VB application already owns one (as in this case). So principially this will work well. The only caveat is that the Shell function runs the application in paralell to current process. All we need is to wait until the child process terminates. A few API calls will do it. An example follows (note the differences when run as a normal VB application and when run as a console app):

    Option Explicit
    
    Const PROCESS_QUERY_INFORMATION = &H400&
    Const SYNCHRONIZE = &H100000
    Const INFINITE = -1&
    
    Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    
    Public Sub ShellWait(PathName As String, WindowStyle As VbAppWinStyle)
        Dim ID As Long, Proc As Long
        
        ID = Shell(PathName, WindowStyle)
        Proc = OpenProcess(SYNCHRONIZE + PROCESS_QUERY_INFORMATION, 0, ID)
        WaitForSingleObject Proc, INFINITE
        CloseHandle Proc
    End Sub
    
    Sub Main()
        ShellWait "CMD.EXE /C dir C:", vbMinimizedFocus
        ShellWait "CMD.EXE /C pause", vbMinimizedFocus
    End Sub

    I’d also like to thank the author of the original article. It was extremely helpful to me. I was basically aware of all the needed API functions. The only elusive thing was the relink trick.

    Martin

    15 Sep 06 at 7:50 am

  18. Well, yeah, that’s the general outline, alright. For all the code, ready to roll right into your applications, see my Console application sample and Command Line processing sample. On the first page, there are links to several free addins that eliminate the awkward Link step above, as well. One aspect of the Console sample that folks really appreciate is that it fully supports debugging within the VB IDE.

    Karl E. Peterson

    26 Sep 06 at 4:07 pm

  19. Excellent article. I keep coming back to this link over the years each time I need to do this. Thankyou.

    Timo

    26 Apr 07 at 7:36 pm

  20. Using the Shell function to execute another console application will not create another console, if the current VB application already owns one (as in this case). So principially this will work well. The only caveat is that the Shell function runs the application in paralell to current process. All we need is to wait until the child process terminates. A few API calls will do it. An example follows (note the differences when run as a normal VB application and when run as a console app):Wow, an on-point article that is easy to read with a quick answer to the question I’ve got. That, and the suggestions really work, too! Kudos!

    Tony

    9 May 07 at 1:54 am

  21. Hi
    i am tearing my hair of because i don’t know how to get the return value after that i have executed an exe file from within an VB application. The language used is VB6

    The code that is already written looks as follow:

    ShellId = Shell("C:\WINDOWS\system32\cmd.exe /c " & command & " > " & fileName, vbHide)
    ShellHandle = OpenProcess(SYNCHRONIZE, 0, ShellId)

    I wonder how to get the returned value from the executed file if it’s possible to do so. In this example it is netdom.exe that i hope to catch the return value from.

    Many thanks..
    Adam

    Adam

    9 May 07 at 8:58 am

  22. Cool ;)

    B0B

    4 Oct 07 at 4:18 pm

  23. Fab – great job.

    David Bowen

    14 Feb 08 at 7:30 am

  24. ok i did everything that it said in this article and it works apparently,

    except 2 bugs,

    it writes out to the same first line and writes over itself,
    i guess this is not a problem cause the gui interprets every line anyway(??)

    2. my program is behaving differently when it is run than when i debug it. (i have just been observing the watch values and not allowing stdout write stdout)

    is a UCI chess program

    –> from gui
    uci
    uci (me typing)

    avery

    29 May 08 at 7:19 pm

  25. Just wondering how might i do the opposite
    make a regular vb6 program read and write to a win32 (not neccesarily vb6) win32 console ? (ie stdin stdout)

    avery

    29 May 08 at 7:37 pm

  26. I worked for a company in 1999 where I had to make some commandtools. We were using VB6 as the only developer env. – none of us was C/C sharks. We droped the commandline tool idea, but since then, I haved searched the net for exactly what your example does. Many have written that it is not possible to create a commandline tool in vb – it is a VISUAL tool ;-). But I have never gived up. Tonight my eyes get wet… :-). Great Work.
    Just one comment: I just placed a vbcrlf in the WriteStdOut in your code.

    Jorgen

    3 Jul 08 at 6:28 pm

  27. Brilliant! Really, really great article!

    Paul Santa Maria

    30 Sep 08 at 6:25 pm

  28. Hi

    . First of all, thanks for your great article. I wrote a program in vb6 and it can accept some command from cmdline arguments. Now! I have a question,How can I display some text at dos windows?

    . For example, when a user type “/?” argument, my program show some syntax of my program commands. Just like “dir /?” or … . At vb.net we can use “Console.Write(“SomeTextHere”)” to do this but what about vb6???

    Thanks in advanced.

    IgImAx

    2 Oct 08 at 6:59 pm

  29. In Visual C++ the default way of making programs (despite being “Visual”) IS through the command line. I HATE API programing for VB. I like simple commands like
    text1.text=”this is a test”
    I wish MORE commands were standard (not API) commands, because I HATE having to write out non-intuitive delarations in my code to acomplish a seamingly simple task. And I wen I found this article, I was HOPING for a SIMPLE way (no API calls or other crap) of acheaving a command line application. But your best answer involves doing FOUR WHOLE DIFFERENT STEPS just to set it up. And that is stuff that has to be done BEFORE writing the actual program. I was HOPING that just switching to Sub Main (instead of Form1) for starting the program in console mode would work. I tried that but it didn’t work, so I was hoping for another VERY easy solution. But you just gave me the worlds most convoluted programing crap EVER! The ONLY reason I like VB more than C++, is because it is an overall easier programing language to use. However, C++ is MUCH better than VB for command line apps. And I still can’t get over the thought that there MUST be SOME easier way (maybe installing a typelib or dll file) that would make it VERY easy to write a command line app in VB.

    Videogamer

    2 Nov 08 at 1:23 am

  30. Wow, great article. Thanks a lot, you saved me a lot of headaches!

    Dave

    21 May 09 at 9:21 am

  31. Thank you, very useful advice. So I didn’t have to reinvent the wheel.

    Greenland

    1 Jun 09 at 6:28 am

  32. Excellent article! I needed a “simple” File-Open dialog which is not simple at all when it comes to including in a distro (CommonDialog requires an OCX which only comes with a Visual Studio distro). I found a link on usoft’s support site which got the program built, BUT I needed the other half, which was to allow it to be called as a command and output to stdout. Your article did both these – thanks!

    Chris

    11 Feb 10 at 12:38 am

  33. Thank you, though I’m an experienced VB programmer I also had to use C/C++ to have this job accomplished. Great job!

    Amaro

    3 Mar 11 at 4:20 pm

Leave a Reply