Curiosity killed the Programmer

23 בספטמבר 2008

casper with chrome Inspired by "Google Chrome" web-browser I tried to create some small application and called it "Casper Browser". I tried to check the approach of using multi-process architecture for web-browser and for .Net applications in general. At the past I built a couple multi-process applications in .Net, but these applications were GUI-less and shared functionality by using ".Net Remoting" mechanism.


The main problem while building this small test-project was to get "Main-Form" from another process and to put it in main application's GUI (as new tab in tabs' container). I knew that "Process" class contains pointer (IntPtr -> MainWindowHandle) to Main-Form of the process, if that process contains main form that used by "Application.Run(…)" procedure (this is very common in Win-Forms applications in .Net).


When I tried to create "Control" or "Form" by using function "FromHandle" with "MainWindowHandle", it always returned NULL:






using (var p1 = Process.Start(DEF_EXE_PROC_PATH)){if (p1 == null) return;

Thread.Sleep(1000); // wait for main frm. init. 

var h1 = p1.MainWindowHandle;var c1 = FromHandle(p1.MainWindowHandle); // returns NULL

}


The googling for "Process + MainWindowHandle + FromHandle + C#" returned bunch of useless links, except one with project "Window Tabifier". This project uses API of "kernel32.dll", "user32.dll" and other DLLs of windows. Personally, I never liked using of "[DllImport(...)]", it's like mixing "unclear" (unsafe) code with "clean" .Net code (my opinion). Anyway, Giorgi Dalakishvili did a good job and thanks to his example I get a "temporary" solution for my problem with NULL ("temporary" -> before I'll find more "clean" solution without using of "DllImport").


The new code:






using(var p1 = Process.Start(DEF_EXE_PROC_PATH)){if (p1 == null) return;

//p1.WaitForInputIdle();     // useless for this proc.

Thread.Sleep(1000);          // wait for main frm. init.var h1 = p1.MainWindowHandle; // create new tabvar tab1 = new TabPage(p1.MainWindowTitle);tabsContainer.TabPages.Add(tab1);tabsContainer.SelectedTab = tab1; // create win. ref. and put it new tabvar w = new window(h1);w.SetParent(tab1.Handle);w.Move(Point.Empty, tab1.Size, true);windows.Add(w);

}


This example uses two classes that I copied from "Window Tabifier" project. The class "winapi" contains different API function that extracted from DLLs, these functions are used by "window" class (wrapper for window handler).


from tabifier to casper


Back to main goal of the application:


"Google Chrome" uses the approach of "each browser-tab runs in separate process" and all tabs are added in one tabbified browser window.


chrome


chrome processes


As you can see, each tab is presented as process in "Task Manager", has own environment and uses separated resources (see CPU and Memory parameters).


The web-sites for tests: CNN, NY-Times and IHT.


So I wanted to simulate this approach and built small application that uses "WebBrowser" class that included in .Net SDK.


casper architecture


My simple "Casper Browser" with 3 tabs with same web-sites:


 casper


casper processes


As you can see, each tab is presented as separated process, each process uses much more memory then "Chrome" processes, that because I'm using MS "WebBrowser" that is much "heavier" than Chrome's "WebKit" (render engine).


But, the simple approach of using multi-process application for web-browser is working and seems efficient, even with MS "WebBrowser".
Each process uses about 25~30 MB, total: ~88 MB.


Killing one process (browser-tab):


casper process kill


Killing of process with "WebBrowser" will close form and tab that contained this form will be empty. This means that closing of integrated process didn't cause collapsing of main application. If some "BrowserTab" (as integrated process) will collapse because of fatal error/exception that wasn't treated/caught in it's code, main application will continue running. Same approach is good in case that some tab will stack, but this will not affect main application or other tabs.


casper with killed browser


Now I'll try the "old approach", each tab will contain "WebBrowser" form as a part of main application.






// create new tab
var tab1 = new TabPage();
tabsContainer.TabPages.Add(tab1);
tabsContainer.SelectedTab = tab1;
// create browser form
var frm = new BrowserForm{TopLevel = false,Parent = tab1,Dock = DockStyle.Fill,Visible = true};

forms.Add(frm);
tab1.DataBindings.Add("Text", frm, "Text");


casper single process


Now we have one process that contains tabs with browsers. If any browser will stack, the entire application will stack, if any browser will collapse the entire application will collapse too.


In case of memory usage single process uses about ~61 MB that is 27 MB less then multi-process version, but it has the all mentioned disadvantages.


If I'll resolve the problem of functionality sharing and other stuff in multi-process version, I'll be able to create some general model for multi-process application with on GUI.


casper all in one


web kit logo That all for this time, the project sources you can download from here. I'm planning to learn "WebKit" SDK and how to implement it for .Net, so next time I'll try to build browser that will be base on it's render engine, that much lighter than MS Browser object.


PS
Of course I'm not responsible for any damage that may be caused by using this post or by using my code sources.
 


 

Add comment
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

תגי HTML מותרים: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

5 comments

  1. Basil Goldman24 בספטמבר 2008 ב 6:08

    Max. You is great.
    Just create UI using WPF and sell it to Microsoft.

    Basil

    להגיב
  2. Eran Kampf25 בספטמבר 2008 ב 3:25

    When working in .NET you can just use multiple App Domains which is a lot simpler than using multiple processes.

    Is there any significant advantage of using processes over App Domains?

    להגיב
  3. Eran Kampf25 בספטמבר 2008 ב 3:27

    Oh btw, you're getting a significant higher memory consumption than chrome mainly because you're using .NET and not necesarily due to the WebBrowser.

    Loading an App Domain has a memory signature of about ~15mb if I remmember correctly. That means each process uses 15mb even if its a "Hello World!" console…

    להגיב
  4. Maxim25 בספטמבר 2008 ב 5:40

    Eran,
    1. You're right. App Domain is VERY HEAVY thing (but the memory usage of console application or any other depends on resources that it uses, "Hello World!" takes much less then 15MB).
    2. Here, I tried the Google's approach, each tag has own process. Means that I share one UI for many processes and use their functionality + advantages of multi-processing. Recently I used this logic in some project, worked fine (for this project I didn't concern about the memory usage), but it has another disadvantage: it is very hard to communicate between the processes. I need to find some way to simplify this + the ability to navigate each process to different CPU (Core), like in parallel extensions.
    3. My next test will be with "WebKit" RE, maybe it will be more lighter.

    להגיב
  5. Ian Boyd4 במרץ 2012 ב 4:38

    In fairness it should be noted that Internet Explorer's been doing this since January 2006 in IE7 on Windows Vista. (http://msdn.microsoft.com/en-us/library/ie/bb250462(v=vs.85).aspx)

    That's what "Internet Explorer Protected Mode" means.

    Chrome's initial public release was December 2008.

    להגיב