Embedding WebKit in a WinForms application

This is how to embed a WebKit instance within a WinForms application. I promised, a long time ago, to show this, but never got around to it. The process itself is pretty simple, assuming you have WebKit compiled (which can be pretty difficult) because you’ll need to be able to link with the WebKit libraries, specificially: WebKit.lib and WebKitGUID.lib (which, of course, have dependencies on all of the other libraries produced in the compilation). I’m going to be using a older version of WebKit, the same one I played with in my previous blog posts, as I don’t have time to check out the newest version of WebKit. Hopefully, the interfaces are the same or similar and what I’m about to describe here can be adapted easily to work with the latest version.

What we’re going to do is create a CLI wrapper to allow the .Net application to access the native WebKit code. To mix managed and unmanaged code, we’re going to need to create a C++/CLI application. Yes, it is going to be ugly code, but it works and (I think) much simpler than trying to P/Invoke functions in WebKit.dll.

Here’s the wrapper code (I’ve also included a compiled dll in the /Release folder):
WebKitCLIWrapper.dll.zip

WebKitNativeController.h and WebKitNativeController.cpp is adapted from the demo code provided by Apple. WebKitCLIWrapper.h (shown below) is the C++/CLI .NET code that wraps the native controller.

#pragma once

#include
"WebKitNativeController.h"

namespace WebKitCLIWrapper
{
    
using namespace System;
    
using namespace System::Collections;

    
public ref class Wrapper
    {
        
public:
            Wrapper(IntPtr hwnd, String^ htmlContent)
            {
                webKitController =
new WebKitNativeController();

                IntPtr bstrPtr = System::Runtime::InteropServices::Marshal::StringToBSTR(htmlContent);
                webKitController->Init((HWND)(
int)hwnd, (BSTR*)&bstrPtr);
                System::Runtime::InteropServices::Marshal::FreeBSTR(bstrPtr);
            }

            ~Wrapper()
            {
                webKitController->UnInit();
                webKitController->Release();
            }

            
void LoadURL(String^ url)
            {

                IntPtr bstrPtr = System::Runtime::InteropServices::Marshal::StringToBSTR(url);
                webKitController->LoadURL(*((BSTR*)&bstrPtr));
                System::Runtime::InteropServices::Marshal::FreeBSTR(bstrPtr);
            }
            
        
protected:
            WebKitNativeController*        webKitController;
    };
}

Now, we can simply include WebKitCLIWrapper.dll in any .Net project as a reference and access the wrapper to create a WebKit instance. So if your in Visual C#, create a new WinForms app, create a Panel (panel1) on a form, and add the following to the form’s Load event:

WebKitCLIWrapper.Wrapper wrap = new Wrapper(panel1.Handle, "");
wrap.LoadURL(
"http://arstechnica.com/");

However, before running the application, you need all the necessary libraries and necessary resources referenced by WebKit.dll in the app’s working directory (I like to set it to Debug).

For convenience, here’s a zip containing all you’ll need:
WebKit_dlls+resources.zip
(as I mentioned, this is an older version of WebKit)

With all the necessary files in place, launch the app, and a WebKit instance should load in the specified panel (panel1) along with the web page specified in LoadURL() call.

arstechnica.com loaded in a webkit container within a WinForms application

If you’d like to display and process a specific piece of HTML code, get rid of the LoadURL() call, place the code to be embedded in a string, and pass it as the 2nd argument to the WebKitCLIWrapper.Wrapper constructor. For example, this will load and embed a youtube video:

string embed = "<object width=\"425\" height=\"344\"><param name=\"movie\" value=\"http://www.youtube.com/v/SuBqIrgKnNg&hl=en&fs=1\"></param><param name=\"allowFullScreen\" value=\"true\"></param><embed src=\"http://www.youtube.com/v/SuBqIrgKnNg&hl=en&fs=1\" type=\"application/x-shockwave-flash\" allowfullscreen=\"true\" width=\"425\" height=\"344\"></embed></object>";
WebKitCLIWrapper.
Wrapper wrap = new Wrapper(panel1.Handle, embed);

cookie monster npr interview, displayed in a webkit instance with a WinForms panel

The wrapper interface is very bare-bones, but it’s good enough if you just need to display some web or HTML content in your app or, if your looking to build a .NET web browser, it will hopefully provide a starting point for how to interact with WebKit.

10 Comments

  1. Bassel

    Thank you very much for doing this. It’s exactly what I was looking for. I got it to work fine with the prepackaged dll you provided, but when I try to compile it from source, it’s complaining the it can’t find webkit\WebKit.h

  2. Avishkar Autar

    Check your VC++ include directories, make sure there’s an entry for the /WebKitBuild/include folder

  3. Abhilash

    How can embed webkit in Linux SDL or GLWindow ? Any help will be appreciated.
    In the WebKitNativeController code I can see gWebView->setHostWindow((OLE_HANDLE)hwndMain); Instead of this i need to pass handle of SDL window or GLWindow.

  4. Avishkar Autar

    Sorry, can’t help you with SDL or GLWindow, everything above is very much Windows only. You can’t use the same interface used here, as it’s based on the Win32 COM, so it’s not just a matter of passing a different handle. Also rendering to something like OpenGL will require modifying the functions that do rendering in order to plot pixels to a buffer that can be converted to a compatible texture (to texture map onto a polygon).

    As a starting point, you might want to check out the source to Midori (http://www.twotoasts.de/index.php?/pages/midori_summary.html), which is a lightweight Linux/GTK browser based on WebKit

  5. guu

    How Can I do your dll with VC6 or even MinGW ?
    I want do it with old way, such like LoadLibraray(“xxx.dll”);

    Thanks

  6. Avishkar Autar

    You can’t.

    This is not straight C or C++ code, it’s .NET C++/CLI code, you must use a compiler which targets the .NET Common Language Infrastructure.

  7. guu

    Damn man,I hate .NET

    thanks

  8. Minh Vu

    Hi,
    I found your article very interesting. Now I’m finding a way to attach a webkit based browser to my winform application which could run on Ubuntu. Actually I’m migrating a winform application to Ubuntu and my application uses IE browser which cannot run on Ubuntu. If you have any idea, please help me. Thank you very much!

  9. WTF

    Thanks

  10. very good, I am having a problem with authentication on a page, the error is 401.2 but not even let me open the pop up to enter the username and password, IIS was looking at something but not that it can be. Any ideas?