12

I'm trying to capture a screenshot of whole browser screen (e.g. with any toolbars, panels and so on) not only an entire page, so I'm got this code:

using (FirefoxDriver driver = new FirefoxDriver())
{ 
    driver.Navigate().GoToUrl(url);                

    ScreenCapture sc = new ScreenCapture();

    // How can I find natural IntPtr handle of window here, using GUID-like identifier returning by driver.currentWindowHandle?
    Image img = sc.CaptureWindow(...);
    MemoryStream ms = new MemoryStream();
    img.Save(ms, ImageFormat.Jpeg);
    return new FileStreamResult(ms, "image/jpeg");
}
Deanna
  • 23,876
  • 7
  • 71
  • 156
kseen
  • 359
  • 8
  • 56
  • 104
  • 1
    It is a shame that Selenium folks resist to NOT implement getting the native window handle. I wrote a feature request years ago and it was rejected. Until 2020 this feature has never been implemented although it would not be complicated (at least on Windows. May be it is impossible on Linux or Mac which have a more primitive GUI than Windows, I don't know) – Elmue Jul 29 '20 at 18:59

3 Answers3

3

You could get the window handle using Process.GetProcesses:

using (FirefoxDriver driver = new FirefoxDriver())
{
    driver.Navigate().GoToUrl(url);

    string title = String.Format("{0} - Mozilla Firefox", driver.Title);
    var process = Process.GetProcesses()
        .FirstOrDefault(x => x.MainWindowTitle == title);

    if (process != null)
    {
        var screenCapture = new ScreenCapture();
        var image = screenCapture.CaptureWindow(process.MainWindowHandle);
        // ...
    }
}

This of course assumes that you have a single browser instance with that specific title.

Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
  • Nice trick, btw, but if there are two different instances of FireFox with the same title? – kseen Jul 20 '12 at 10:47
  • @kseen You could replace [`FirstOrDefault`](http://msdn.microsoft.com/en-us/library/bb549039) with [`SingleOrDefault`](http://msdn.microsoft.com/en-us/library/bb549274), so that if there are two different browser intances with the same title you'll get an exception. If you are on a test case you could assert it. – Paolo Moretti Jul 20 '12 at 11:29
  • @PaoloMoretti how can i get handle to current window(existing Window which is opened manually) which is not opened by driver means i can't use driver.getWindowHandle(); – Dgan Oct 10 '15 at 09:21
3

Just and idea for hack. You may use Reflection methods to get process of firefox instance. First declare FirefoxDriverEx class inherited from FirefoxDriver - to access protected Binary property which encapsulates Process instance:

 class FirefoxDriverEx : FirefoxDriver {
        public Process GetFirefoxProcess() {
            var fi = typeof(FirefoxBinary).GetField("process", BindingFlags.NonPublic | BindingFlags.Instance);
            return fi.GetValue(this.Binary) as Process;
        }
    }

Than you may get process instance for access to MainWindowHandle property

using (var driver = new FirefoxDriverEx()) {
            driver.Navigate().GoToUrl(url);

            var process = driver.GetFirefoxProcess();
            if (process != null) {
                var screenCapture = new ScreenCapture();
                var image = screenCapture.CaptureWindow(process.MainWindowHandle);
                // ...
            }
        }
necrostaz
  • 380
  • 1
  • 2
  • 6
  • Could you please add another methods for finding windows in other than FireFox browsers, e.g. IE, Chrome, Safari in Selenium? The issue is that I can't find `ChromeBinary` or somethibg else like `FireFoxBinary`. – kseen Aug 09 '12 at 19:12
  • This method is not suitable for IE or Chrome because in those cases browser's processes controlling by external selenium services such as IEDriverServer.exe and chromedriver.exe. This method just hack and working 'as is'. For find working method you may look into selenium driver's sources and probably build your own versions. – necrostaz Aug 10 '12 at 09:20
  • So, there is just one robuts method exists for getting a handle of browser window and this is finding a window using WinAPI by partial title of window? – kseen Aug 10 '12 at 13:41
1

Out of box, selenium does not expose driver process id or Browser hwnd but it is possible. Below is the logic to get hwnd

  • When driver is initialized, get the url for hub and extract the port number
  • From port number, find the process id which is using this port for listening, ie. PID of driver
  • After navigation, from all instances of iexplore find the parent PID matches the pid of driver, i.e browser pid.
  • Get the Hwnd of browser pid once browser hwnd is found , you can use win32 api to bring selenium to foreground.

its not possible to post full code here, the full working solution (C#) to bring browser in front is on my blog

http://www.pixytech.com/rajnish/2016/09/selenium-webdriver-get-browser-hwnd/