en-UShe-IL
You are here:   Blog
Register   |  Login

Blog Archive:

Maximize
* Can be used in order to search for older blogs Entries

Search in blogs


Blog Categories:

Maximize
* Can be used in order to search for blogs Entries by Categories

Blog Tags:

Maximize
* Can be used in order to search for blogs by keywords

TNWikiSummit


Awared MVP 


 


Microsoft® Community Contributor 


Microsoft® Community Contributor


 Read first, before you you use the blog! Maximize
מרץ29

Written by: ronen ariely
29/03/2014 23:09 RssIcon

Case study

We need to develop small application, which can be executed in variety ways, on variety interfaces. For example we need to be able to execute the application using: (1) command line (with or without parameters), or by (2) double click the exe file, or (3) from command shell / PowerShell. Moreover, we need our application to return information, using variety of Graphical user interfaces (GUI), according the execution option that we used. For eample, if we executed the application using GUI (option 3), then we need to let the user choose which GUI to use according to the parameter he passed to the executing command. If he didn't use any parameter (default), or if he used 'gui' as the parameter's value (option 1, 2), then we open a 'windows form', as our GUI. If the user pass the parameter 'console' and he using a shell interface, than the result will be seen on current shell without opening new GUI (option 2).


Introduction

By default the Graphical user interfaces is compatible with the type of application we develop (also called project type in some situation). For example a pure console application return information using the console Graphical user interfaces, while windows forms application use build in forms as a GUI, a web application use the browser as GUI, and a flash application use the flash GUI, etc. How can we put all in one application?!?

A better question, that developers have to understand is, what the hell are the differences between different application's types? What is making one application a "console application" and second application a "windows forms" application? Does it make sense that a developer know how to develop only one specific type, while he can't understand basic code in different type? In short, the answer for the last question is Yes, if he is very poor developer which actually do not develop but build applications using the build in tools.

It is true that a developer can gain expertise in a certain type of applications, and with time, gain experience and control the built-in options and tools, for this type. But if he understands what is going on behind the scenes, then he can also develop and change the behavior of the application, and actually create "new" application type.

So what is the difference between project types in Visual Studio (VS)? What is the difference between creating a console project in Visual Studio versus creating windows forms project? The answer is simple, VS provides several ready-made templates, for different application types, in order to save the developer working time. The only substantive difference between different types of applications is the template in which we use. Those templates come with build in code, which someone else wrote for us. This code can be found in the application itself, in references, or another source connected to the application. Even if we do not familiar the template/type of application, we have to understand the significance of choosing a specific type of project or a project template, when we start to work. Moreover. We must understand the code that comes with that template.

How often did you sow "professionals" saying something like: "This cannot be done using project type A"? Let's change this misconception!

Theoretically we can start with notepad and develop our application from scratch without using a build-in template! But even in that case we will actually use some build-in code came which came with the developing framework (Dot.Net for example). Moreover we can start a project type A, and add to that project elements which usually come with project type B. For example start a new console application, and open a windows form or a browser, and vice versa.

The Solution

In our case we want to get an application which use both console GUI and windows form GUI. Since windows forms is a bit more complex template then console app template its look easier to base our solution on windows forms application.

Step 1: Start a new project

1.1 Choose type: windows forms (language C#). 

1.2 Name the project ArielyMultiTypesApplication


Step 2: Import unmanaged methods

2.1 Open Program.cs file, which include the Windows forms application entry point.

* In most popular computer systems, a computer program usually has a single entry point. Using Windows forms it is a static method named Main.

2.2 In order to use PInvoke we need to add the use of System.Runtime.InteropServices.


* PInvoke: Platform Invocation Services allows managed code to call unmanaged functions that are implemented in a DLL.


using System.Runtime.InteropServices;


2.3. Import several methods to the "Program" class


[DllImport("kernel32", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
 
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
 
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
 
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
 
[DllImport("kernel32.dll", EntryPoint = "AllocConsole", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();


Step 3: Check which type of GUI should be started, and use it

Basically we read the argument posted to the execution command and make several checks using IF/ELSE IF/ELSE in order to choose the GUI.

3.1 add optionally passing arguments to the Main method by using

static void Main(string[] args)

3.2 Add the basic if/else statements to the Main method

string mode = args.Length > 0 ? args[0] : "gui";
if (mode == "gui") {
    // Open windows form as our GUI
}
else if (mode == "console"){
    if (process.ProcessName == "cmd" || process.ProcessName == "powershell") {
        // Use Current shell as our GUI
    }
    else {
        //Open New console shell as our GUI.
    }
}



How do we open the GUI interface?

As we can see in the image above, we have three options. (1) Open a Windows form, (2) Open a new console shell, (3) Use current shell.

3.3 move the original code into the right place in our new code.

In order to open the Windows form we just use the original code from the "main" method, as this is a windows forms application, we already have the code ready for us in the template.

3.4 For options 2 & 3 we first of all declare several elements: (a) IntPtr element using the imported method GetForegroundWindow, (b) INT element which will get the thread ID. Next import the method GetWindowThreadProcessId, in order to get the thread ID, and declare a Process element which is our process.

IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);

Once we have our process as an element, we can check if we are using a command line process or a shell process, in order to determine if we need to open a new console shell or use current shell.

3.5 In order to use current shell we attach current process to the console using the imported method AttachConsole. When using this method the console open within our shell, and wait for the user to press a key (just like we use a command "console.readkey()"). Once the sendkey event is catch the application go back to the main shell. In this case we want to go back to the main shell automatically, therefore we send an "enter" key: 

SendKeys.SendWait("{ENTER}");



3.6 In order to open a new console shell we are using the imported method AllocConsole, which allocates a new console for the calling process. A console shell is closing by default once the commands ended. In this case we want the user to be able to read the information and leave the console open. Therefor we use the command Console.ReadLine().

* The full code can be download here
http://gallery.technet.microsoft.com/C-Sharp-Multi-Types-dceeccbe

Forum Questions

* http://social.msdn.microsoft.com/Forums/he-IL/9bc16b96-a145-476e-bef3-316425271fbe/consolewriteline-to-command-line?forum=nethe

Resources

* Platform Invoke Tutorial
http://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx

* PInvoke.net is primarily a wiki, allowing developers to find, edit and add PInvoke* signatures. This is the best place to find example of using unmanaged APIs from managed code (languages such as C# or VB.NET).
http://www.pinvoke.net/index.aspx

Your First C# Windows Form
http://www.homeandlearn.co.uk/csharp/csharp_s1p5.html

Windows forms application entry point
http://msdn.microsoft.com/en-us/library/acy3edy3.aspx