Monday, 27 August 2012

Attaching console to Windows Forms Applicaion

This is a blog post that i have created for the only reason to remind myself at a later time that something like this is possible. At the end are various resources that help understand this concept better.

A windows form application and a console application are based on different subsystems. A subsystem is nothing but an environment in which an application runs. what that means basically is that when a console program has to put something on the monitor it will use a particular set of system calls and APIs while for a GUI program an entirely different collection of APIs may be required to draw something on screen.

The code used to attach a console to the windows form application is based around 'AllocConsole()' (see MSDN descrition) function. This function is defined in kernel32.dll and can be called by importing the dll file using DllImport attribute. The code for importing dll would be:

[DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AllocConsole();

The extern attribute in the above given code is used to signal the presence of AllocConsole method in an external assembly i.e. some executable other that the current one. The Marshal attribute is used to bridge the data types used in .net framework (which are managed ) and external executables which uses unmanaged types. In this case since the kernel32 is implemented in c/c++  and the windows form application written in C# thus the return type BOOL of c/c++ must be bridged with bool of C#.
Marshalling and setting SetLastError fields in above code is not mandatory for this particular example and can be done away with however in scenarios where the  datatypes widely differ marshalling must be done.

Simply put the above code introduces the function AllocConsole present in kernel32.dll to the current scope (much like including header files) so that it can be called by rest of the program.
The above code must be written inside an enclosing class instead of a function and the method must be declared as static extern.

Now all we have to do is to  call 'AllocFunction()' at the required place. I included  it in the Form_Load method so that it remains available for the complete duration of the program. Although a feature like this is seldom required for a GUI application but during development and testing stage this proves to be a great alternative for debugging over message boxes and event logs.

It is important to note that the dll cannot be included by add-reference method as this dll is written in native language while the dlls that can be imported by add-reference method are the dlls written in .net thus DllImport is used. Also DllImport is not a method (unlike LoadLibrary or LoadLibraryEx in C++), instead it is an Attribute.

Some resources that are good for getting to know the windows subsystem better are:

  • These articles [(1) & (2)] on technet briefly explains the concept of GUI and CUI subsystems. 
  • MSDN blog explaining how OS knows which subsystem to use for a program.
  • about conhost.exe , articles 1 & 2.