Register | Login

Stacking Code

public interface IBlog { string Dump(Stream consciousness); }

Screenshot Generator Tinkering

Monday, 17 January, 2011 @ 6:07 AM < Adam Boddington
Tags: Building Neno, Pivot, Windows Forms

This is post #34 in the Building Neno series. Please click here for a description of the Building Neno project and instructions on how to access the source code for this post.

This post is mostly for my own future reference in case I ever revisit this. I've been tinkering with the screenshot generator to increase it's performance. Despite having the disk and database work farmed out to worker threads, the WebBrowser controls still take a long time to browse their respective pages. I suspect they're not all working at the same time.

More Threads!

I initially thought my low performance might be because all my WebBrowser controls are on the same thread, or it might be some kind of bottleneck on the underlying ActiveX control itself. So I rolled a new screenshot generator, a console application this time, that spawns a new STA thread for each WebBrowser control like this...

for (int x = 1; x < 9; x++)
{
    var thread = new Thread(
        number =>
        {
            var webBrowser = new WebBrowser { Height = 1024, Name = "WebBrowser" + (int)number, ScrollBarsEnabled = false, Width = 1024 };
            webBrowser.DocumentCompleted += WebBrowser_DocumentCompleted;

            if (NavigateToNextPost(webBrowser))
                Application.Run();
        });

    thread.SetApartmentState(ApartmentState.STA);
    WebBrowserThreads.Add(thread);
    thread.Start(x);
    Console.WriteLine("WebBrowser{0} spawned.", x);
}

foreach (Thread thread in WebBrowserThreads)
    thread.Join();

Windows Forms controls require an STA thread and a message pump, which is what the call to Application.Run is all about. The boolean check is there to make sure there is a post for the control to navigate to, otherwise the thread simply exits.

The call to Application.Run is accompanied by a call to Application.ExitThread to stop the message pump when the thread is done.

private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var webBrowser = (WebBrowser)sender;
    CaptureScreenshot(webBrowser, e.Url.ToString());

    if (!NavigateToNextPost(webBrowser))
        Application.ExitThread();
}

It all runs great, with the disk and database work still handled by additional threads. But the overall improvement is only 9.5 seconds.

ssg

ssg2

The WebBrowser controls seem to run slowly, one after the other, like they're sharing a common resource. This could be my imagination -- I simply don't know and I'm not sure how to find out. I've spent more time than I want to on this, so I'll just keep it in mind and move on. The application runs, it just doesn't run as fast as I had hoped.

Rendering

One thing I did notice when playing around with the screenshot generator is that the screenshots weren't rendering exactly right. There was some extra padding in places, and floats were behaving differently. Checking the same pages in IE8 showed everything to be okay... So why was the WebBrowser control rendering differently from IE8?

The answer lies in how the WebBrowser control renders by default, which is explained here. To avoid breaking existing applications that use the WebBrowser control, the control renders in IE7 standards mode by default. To make it run in IE8 standards mode, a registry key must be added to the computer the application is running on. It can't be set via .NET... I was somewhat incredulous when I read this, but I suppose it isn't a .NET control, just a managed wrapper, and as such will have some of its native implementation poking through here and there.

Setting "ssg2.exe" = 8000 under HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION didn't work for me. I had to set it to 8888 instead. "ssg.vshost.exe" didn't help in the 8000 scenario and wasn't required to get 8888 to work. The end result was a much nicer render in my screenshots, albeit with a bad taste in my mouth from modifying the registry.

I could get my site to render 100% correctly in IE7, but that's not my idea of a good time.

EDIT: I've noticed adding this registry setting breaks the WebBrowser.ScrollBarsEnabled property. Despite it being false, I now have a vertical scrollbar in all of my screenshots. This happens in both versions of the screenshot generator.

Alternative Control

In my investigations I came across the GeckoFX control. It's a Firefox browser control that can be placed in Windows Forms applications the same way the WebBrowser control can. Unfortunately it doesn't like multithreading very much, but one guy has worked around that using processes instead of threads.

Conclusion

The console version of the screenshot generator suggests to me that I could place the same code inside of my MVC application, which would allow me to generate the entire Pivot collection in a single call. However, my hosting server probably doesn't have Flash installed, and it definitely won't have the registry settings required to render pages using IE8 standards mode, so it's all a moot point for now anyway.

I could use the GeckoFX control instead (sans multithreading -- probably a good thing). It's something to keep in mind if the requirement should arise.

There are 0 comments.


Comments

Leave a Comment

Please register or login to leave a comment.


Older
Brisbane Flood, 2011

Newer
Lookups, Poppy's Way

Older
Brisbane Flood, 2011

Newer
Lookups, Poppy's Way

browse with Pivot


About


Projects

Building Neno


RSS
Recent Posts

Codility Nitrogenium Challenge
OS X Lock
HACT '13
Codility Challenges
Priority Queue


Tags

Architecture (13)
ASP.NET (2)
ASP.NET MVC (13)
Brisbane Flood (1)
Building Neno (38)
C# (4)
Challenges (3)
Collections (1)
Communicator (1)
Concurrency Control (2)
Configuration (1)
CSS (5)
DataAnnotations (2)
Database (1)
DotNetOpenAuth (2)
Entity Framework (1)
FluentNHibernate (2)
Inversion of Control (5)
JavaScript (1)
jQuery (4)
Kata (2)
Linq (7)
Markdown (4)
Mercurial (5)
NHibernate (20)
Ninject (2)
OpenID (3)
OS X (1)
Pivot (6)
PowerShell (8)
Prettify (2)
RSS (1)
Spring (3)
SQL Server (5)
T-SQL (2)
Validation (2)
Vim (1)
Visual Studio (2)
Windows Forms (3)
Windows Service (1)


Archives


Powered by Neno, ASP.NET MVC, NHibernate, and small furry mammals. Copyright 2010 - 2011 Adam Boddington.
Version 1.0 Alpha (d9e7e4b68c07), Build Date Sunday, 30 January, 2011 @ 11:37 AM