Click here to Skip to main content
15,885,818 members
Articles / Programming Languages / C#

Tabbed Multi Process Application

Rate me:
Please Sign up or sign in to vote.
4.90/5 (18 votes)
8 Apr 2014CPOL4 min read 31.4K   37   15
Multi-process application - Create your own tabbed application container.

Introduction

Sometimes you might have wondered how Chrome browser creates different tabs as different process and how they add into a tab. This article is all about creating a Tabbed multi process application.
Multi process architecture is a known concept to all and has been in use for the past several years, for example, Google chrome, a popular browser where each tab is a separate process. How do they do it ?
Few months ago, a similar requirement was raised in our team too, which prompted me to use such a design. This application helps client in easy management of different networks and also easy identification of user interface as the application is tabbed.

This article is all about how each tab could host different application processes.

Background

Starting from the very basics, in Windows, each UI object has a unique value called handle (refer to the below link). A handle is a pointer and in C#, for every UI object, there is property named Handle using which we could retrieve its Handle. Using this handle and using Windows API, we can easily embed an application into a Windows UI component.

Now let us make our hands wet....

Start Visual Studio and create a solution with two Windows applications in it, one being Child and another being Parent - both should be in the same platform (You could use any existing application as a child application like WordPad, I would suggest to target x86 platform initially if using a legacy application like Notepad).

In the parent application, add a ‘Table layout panel’ control and configure it with two columns.

In the left column – you could add a treeview / buttons as per your choice for launching the application.

In the right column, add a tab panel and set the Dock Property to Fill.

In the parent application, add static classes named WindowsAPI and WindowsConstants. (These classes will help in calling Windows API.)

In the WindowsAPI class, add namespace reference to “Microsoft.Win32” and “System.Runtime.InteropServices Now, modify the class definition with the following code:

C#
[DllImport("user32.dll",SetLastError = true)]  
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 
[DllImport("user32.dll", CharSet =CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.Bool)]<span></span>
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

SetParent API - Use this to create forms and then place child windows on it.

ShowWindowAPI - Sets the specified window's show state.

In the class WindowsConstants, add the following constants:

C#
public static readonly int SW_MAXIMIZE = 3;  

Coming back to the Mainform of the parent application, subscribe the click event of the button/treeview; add the following code in the click event handler.

C#
Process process =Process.Start("Wordpad.exe"); 
process.WaitForInputIdle();
tab.Text = "Wordpad "+ counter;
WindowsAPI.SetParent(process.MainWindowHandle,tab.Handle); 
WindowsAPI.ShowWindow(process.MainWindowHandle,WindowsConstant.SW_MAXIMIZE);

This will make the child application (say notepad.exe here) to attach a process to a tab. But the new process contains title bar menubar and border, which makes it easy to close the application. When we are in control of both child and parent application, we can easily get over this problem by changing the Form properties (BorderStyle). But how can we control the menu and border properties of an application which is out of our control (Say the case of wordpad.exe)? Like SetParent, there are Windows API for changing the Windows border of any application.

Modify the WindowsAPI class to accommodate new WindowsAPI.

C#
public static IntPtr GetWindowLongPtr(HandleRef hWnd, int nIndex)
{
  if (IntPtr.Size == 8)// This is towork in both 64 bit and 32 bit 
      return GetWindowLongPtr64(hWnd,nIndex); 
  else  
      return GetWindowLong32(hWnd, nIndex); 
}  
[DllImport("user32.dll", EntryPoint= "GetWindowLong")]
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex);
 
[DllImport("user32.dll", EntryPoint= "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex); 
public static IntPtrSetWindowLongPtr(HandleRef hWnd, int nIndex, IntPtr dwNewLong)
{  
   if (IntPtr.Size == 8)// This is to work in both 64 bit and 32 bit
      return SetWindowLongPtr64(hWnd,nIndex, dwNewLong);
  else                
      return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
}
[DllImport("user32.dll",EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong); 
[DllImport("user32.dll",EntryPoint = "SetWindowLongPtr")]
  
 
private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);

Now modify the WindowsConstants class with the following values:

C#
public static readonly int GWL_STYLE = -16;
public static readonly UInt32 WS_CAPTION = 0xC00000; 
public static readonly UInt32 WS_BORDER = 0x00800000; //window with border 
public static readonly UInt32 WS_DLGFRAME = 0x00400000;

Now in the click event handler of the button, modify the code to remove the title bar and form border.

C#
long style =WindowsAPI.GetWindowLongPtr(new HandleRef(this, process.MainWindowHandle), 
WindowsConstants.GWL_STYLE).ToInt64();
style= style & ~( WindowsConstants.WS_CAPTION |WindowsConstants.WS_BORDER | WindowsConstants.WS_DLGFRAME);  
IntPtr styleValue = new IntPtr(style); WindowsAPI.SetWindowLongPtr(new HandleRef
( this, process. MainWindowHandle), WindowsConstants.GWL_STYLE, styleValue);

This will initially get the window style of the child application’s main window and then remove the caption, border and dialog frame properties then reset the updated style to the mainwindow.

Now this will really help in removing the border and title bar from a window.

But still, we haven’t made the new application the child of the parent application.

We need to do this because, on termination of the parent application, its child application may not all the time get removed from the process queue. This will result in execution of the application in background without our knowledge consuming the processor resources and memory which is a waste.

Now modify the WindowsConstants class by adding new constants.

C#
public static readonly long WS_CHILD =0x40000000L;
public static readonly long WS_POPUP =0x80000000L;

In the button click event handler, once again set the window style.

C#
 style = WindowsAPI.GetWindowLongPtr(new HandleRef(this, tab.Handle), WindowsConstants.GWL_STYLE).ToInt64();
style &= ~ WindowsConstants.WS_POPUP;style|= WindowsConstants.WS_CHILD;
 styleValue = new IntPtr(style); //Setting window to be child of current application and the popup behaviour of window is removed. 
WindowsAPI.SetWindowLongPtr(new HandleRef(this, tab.Handle), WindowsConstants.GWL_STYLE, styleValue);   

This will help in removing the child application on closing the parent from process queue.

Finally, the button's click event handler code is as follows:

C#
private void StartWordPadButton_Click(object sender, EventArgs e)
{
Process ProcessInfo = Process.Start("Wordpad.exe"); // You may give your
 //child application path here
ProcessInfo.WaitForInputIdle();
TabPage tab = new TabPage();
tab.Text = "Wordpad ";
tabControl1.TabPages.Add(tab);
long style =0;
style = WindowsAPI.GetWindowLongPtr(new HandleRef
(this, ProcessInfo.MainWindowHandle), WindowsConstant.GWL_STYLE).ToInt64();
style = style & ~(WindowsConstant.WS_CAPTION |
WindowsConstant.WS_BORDER |WindowsConstant.WS_DLGFRAME);

IntPtr styleValue = new IntPtr(style);
WindowsAPI.SetWindowLongPtr(new HandleRef(this, 
ProcessInfo.MainWindowHandle), WindowsConstant.GWL_STYLE, styleValue);
style = WindowsAPI.GetWindowLongPtr(new HandleRef
(this, ProcessInfo.MainWindowHandle), WindowsConstant.GWL_STYLE).ToInt64();  
style &= ~WindowsConstant.WS_POPUP;

style |= WindowsConstant.WS_CHILD;
styleValue = new IntPtr(style);
//Setting window to be child of current application and the popup behaviour of
 window is removed. 

WindowsAPI.SetWindowLongPtr(new HandleRef(this, 
ProcessInfo.MainWindowHandle), WindowsConstant.GWL_STYLE, styleValue);
WindowsAPI.SetParent(ProcessInfo.MainWindowHandle,tab.Handle);
WindowsAPI.ShowWindow(ProcessInfo.MainWindowHandle,WindowsConstant.SW_MAXIMIZE)
}

Your suggestions and feedback will be very helpful to me for my upcoming articles.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionNot so useful Pin
Frank Shaw24-Nov-15 15:08
Frank Shaw24-Nov-15 15:08 
Everyone will know how to embed application in this way when they need to do, but they will encounter many problems when they try to. This article is just TOO SIMPLE. I'm dealing this requirement recently which really makes me mad, for example:
1. UI' s layout will mess up when you embed (UI has data loading logic when launch)
2. It will have a obvious flicker when you try to embed, the slower UI is, the obvious it is.
3. Sometimes UI cannot embed when UI launch slow.
4. How to deal with programs' communication?


Still, I appreciate your effort, it certainly can give everyone a good start
QuestionPossibly use MAF for more control and Remoting communication Pin
Member 1029747024-Oct-15 9:19
Member 1029747024-Oct-15 9:19 
QuestionDoes this work using WPF? I cannot find TabPage(Win Forms?) and TabItem has no handle Pin
Oldroyd13-Aug-15 21:43
Oldroyd13-Aug-15 21:43 
QuestionOther Applications can not run? Pin
Lucapachiolri23-Mar-15 23:19
Lucapachiolri23-Mar-15 23:19 
QuestionHow to avoid one of these processes` hanging?? Pin
wonderzerg8-Oct-14 22:36
wonderzerg8-Oct-14 22:36 
Questionvery useful Pin
Sacha Barber15-Aug-14 3:03
Sacha Barber15-Aug-14 3:03 
QuestionMy vote of 5 Pin
mohdaneeselampara15-Aug-14 2:27
mohdaneeselampara15-Aug-14 2:27 
QuestionMy vote of 5 Pin
Emre Ataseven9-Apr-14 21:29
professionalEmre Ataseven9-Apr-14 21:29 
AnswerRe: My vote of 5 Pin
Vipin Kumar Mallaya G25-Jul-14 9:25
Vipin Kumar Mallaya G25-Jul-14 9:25 
QuestionLooks great but where is code? Pin
Garry Lowther8-Apr-14 23:08
Garry Lowther8-Apr-14 23:08 
AnswerRe: Looks great but where is code? Pin
Vipin Kumar Mallaya G25-Jul-14 9:29
Vipin Kumar Mallaya G25-Jul-14 9:29 
GeneralRe: Looks great but where is code? Pin
Srivathsal V2-Oct-14 23:22
professionalSrivathsal V2-Oct-14 23:22 
QuestionGood stuff bro Pin
Volynsky Alex8-Apr-14 22:03
professionalVolynsky Alex8-Apr-14 22:03 
GeneralMy vote of 5 Pin
Аslam Iqbal8-Apr-14 20:22
professionalАslam Iqbal8-Apr-14 20:22 
GeneralRe: My vote of 5 Pin
Vipin Kumar Mallaya G25-Jul-14 9:30
Vipin Kumar Mallaya G25-Jul-14 9:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.