Click here to Skip to main content
15,884,628 members
Articles / Programming Languages / C#

Reuse Selenium WebDriver COM (.NET) version

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
15 Feb 2013CPOL3 min read 26.4K   437   8   2
This article describes how to use COM objects for Selenium scripts development.

Introduction

Here is the COM object version of the previous article which I have managed to create a long time ago. But at this moment I think the RMI Java solution is much easier to maintain. We can also use the .NET remoting method to achieve the same functionality as described in the Java article.

Background

For the COM version, my aim is to keep and use the webdriver via COM objects.

Please note

COM object version means that you need to take the Selenium code (which is open source) and make the WebDriver method's COM visible. This is hard to maintain and eventually we will need a team of several devs to achieve this. But just to show how this can be made, as I am sure many others thought about this solution, I am posting it here.

How to

Here are the steps to make the WebDriver COM visible.

  1. I took the last source code version from Selenium 2.26.
  2. Opened the Selenium sln with Visual Studio Express 2010
  3. Updated the WebDriver interface from this:
  4. C#
    public interface IWebDriver : ISearchContext, IDisposable

    to this:

    C#
    [Guid("fb3d782e-1983-4dba-9ffc-7142193dbbbf"),
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface IWebDriver : ISearchContext, IDisposable
    {
    1. Also added WebDriverWrapper class into the Selenium WebDriver project. I will explain this a little bit later. You can find this file into the attached archive.
  5. Then I added the IWebDriverDispatch interface into the WebDriver project:
    C#
    namespace OpenQA.Selenium
    {
        [Guid("b59fd455-90df-4d5e-b85f-c508bb6d385b"),
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        interface IWebDriverDispatch
        {
        }
    } 
  6. I changed the INavigation interface like this:

    Before:

    C#
    public interface INavigation

    After:

    C#
    [Guid("7fb9a3f0-4bb4-435c-b512-e51a1a330327"), 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface INavigation
    {
  7. I made the WebDriverWrapper visible to COM:

    Before:

    C#
    public class WebDriverWrapper : IWebDriver
    {

    After:

    C#
    [Guid("f8fc24ff-e244-4cdd-8125-6a08095639cd"),
    ClassInterface(ClassInterfaceType.AutoDual),
    ComSourceInterfaces(typeof(IWebDriverDispatch))]
    [ComVisible(true)]
    public class WebDriverWrapper : IWebDriver
    {
  8. Changed the project "Register for COM interop" properties like below:
    1. Open Properties:
    2. Properties

    3. In the Properties window, activate the Build tab and tick Register for COM Interop:

      Image 2

  9. Rebuilt the Selenium Solution.
  10. Created the Server, the application that will put the WebDriver into COM.
    C#
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        //[STAThread]
        static void Main()
        {
            WebDriverWrapper engine = new WebDriverWrapper();
        }
    } 

    Don't forget to add a reference to WebDriver.dll in the project references.

  11. Created the Client, the application that will hold the Selenium scripts:
    C#
    class Program
    {
        static void Main(string[] args)
        {
            IWebDriver obj = (IWebDriver)Marshal.GetActiveObject(typeof(WebDriverWrapper).ToString()); 
            obj.Navigate().GoToUrl("<a href="http://www.facebook.co/">http://www.facebook.co</a>m");   }
    }

    Don't forget to add a reference to the WebDriver DLL in the project references.

And here it is, Start the server, wait for Firefox to start, start the Client, you will see that the browser will navigate to the URL from the client.

Now what is WebDriverWrapper for...

This is actually the core of this project. When the server starts it actually puts the WebDriver object into the COM list:

C#
public WebDriverWrapper()
{
    if (driver == null)
    {
        FirefoxProfile profile = new FirefoxProfile();
        driver = new FirefoxDriver(profile);
        navigateEngine = new WebNavigateWrapper();
        navigateEngine.SetValue = driver.Navigate(); 
        Register_OLE32(typeof(WebDriverWrapper), this);
    }
}

The Register_OLE32 function actually inserts on the fly the WebDriverEngine object into COM. Here you will need some DllImports from the Windows:

C#
[DllImport("ole32.dll", EntryPoint = "CLSIDFromString")]
public static extern int CLSIDFromString(byte[] lpszCLSID, out Guid pclsid);
[DllImport("oleaut32.dll", EntryPoint = "RegisterActiveObject")]
public static extern int RegisterActiveObject([MarshalAs(UnmanagedType.IUnknown)] object punk, ref Guid rclsid, uint dwFlags, out uint pdwRegister);
[DllImport("ole32.dll", EntryPoint = "GetRunningObjectTable")]
public static extern int GetRunningObjectTable(int reserved, out UCOMIRunningObjectTable ROT);
[DllImport("ole32.dll", EntryPoint = "CreateItemMoniker")]
public static extern int CreateItemMoniker(byte[] lpszDelim, byte[] lpszItem, out UCOMIMoniker ppmk);

Pinvoke is not the purpose of this article and I will not stay on this too much. Don't forget our purpose is to pass WebDriver from Server to Client.

The Register_OLE32:

C#
public void Register_OLE32(Type type, Object obj)
{
    UnicodeEncoding enc = new UnicodeEncoding();
    int errorcode;
    Guid guid = new Guid();
    uint register; 
    string itemname = type.ToString();
    byte[] item = enc.GetBytes(itemname);
    errorcode = CLSIDFromString(item, out guid);
    Marshal.ThrowExceptionForHR(errorcode); 
    errorcode = RegisterActiveObject(obj, ref guid, ACTIVEOBJECT_STRONG, out register);
    Marshal.ThrowExceptionForHR(errorcode);
}

Please Note

In the source code version of Selenium 2.26 i had a problem with starting Firefox Driver. This is because the webdriver.xpi file was not generated each time I have been calling to FirefoxDriver() constructor. Please find webdriver.xpi in the shared archive and place it manually into the Server's bin\Debug folder.

Points of Interest

I hope the developers from Selenium will find either RMI Java version or .Net COM version useful and the next versions of Selenium will come up with something like this already implemented. I am sharing this solution cause I hope it will be useful to all those who try to implement advanced testing scripts.

History

  • Version 4

License

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


Written By
Software Developer Endava, Chisinau
Moldova (Republic of) Moldova (Republic of)
Graduate: Romania, University of Bucharest, Mathematical - Informatical faculty.

Comments and Discussions

 
QuestionNeed code for WebNavigateWrapper class Pin
Liliya Strupinskaya29-Jan-13 12:16
Liliya Strupinskaya29-Jan-13 12:16 
AnswerRe: Need code for WebNavigateWrapper class Pin
Mircea Sirghi7-Feb-13 11:02
Mircea Sirghi7-Feb-13 11:02 
I have inserted it directly in the selenium project and because it is too big I have posted here only the dll of it. I will provide the full solution at the end of the february. But for now, you may want to know, I am thinking about a different approach. I would rather make all the webdriver related classes serializable to make it possible to obtain Web Driver remotely. Com object version is a tough solution. The most easiest one is to create a Wrapper over WebDriver that is serializable and can be used via .Net remoting. I have raised this problem to Selenium guys but it seams they did not understand the benefits of it. The wrapper solution is good because any time you want to take the last available webdriver you need only to update the wrapper which provides access to the web driver's functions. Hope this does make sense...
hakkuss

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.