12

In C# I start up a browser for testing, I want to get the PID so that on my winforms application I can kill any remaining ghost processes started

driver = new FirefoxDriver();

How can I get the PID?

Yi Zeng
  • 32,020
  • 13
  • 97
  • 125
user1320651
  • 808
  • 2
  • 15
  • 42

8 Answers8

17
        int _processId = -1;

        var cService = ChromeDriverService.CreateDefaultService();
        cService.HideCommandPromptWindow = true;

        // Optional
        var options = new ChromeOptions();
        options.AddArgument("--headless");

        IWebDriver webdriver = new ChromeDriver(cService, options);
        _processId = cService.ProcessId;

        Console.Write("Process Id : " + _processId);

        webdriver.Navigate().GoToUrl("https://www.google.lk");

        webdriver.Close();
        webdriver.Quit();
        webdriver.Dispose();
Gehan Fernando
  • 1,221
  • 13
  • 24
  • 3
    This should be the accepted answer. The DriverService class is the one that provides info (a PID) to retrieve the process of the current opened browser instance. Very helpful, also when working with multiple instances of a browser. It helped me a lot. Thanks for sharing this answer! – ElektroStudios Jul 26 '19 at 14:18
  • 1
    How does this only have one up vote! this is the only answer needed. – Harleyz Aug 14 '19 at 16:48
  • I agree - this is the best answer. Just voted it up! – Daniel Williams Jul 23 '20 at 16:51
  • 2
    Certainly correct me if I'm wrong, this only gets the PID of the DriverServer process, not the browser it is associated with. – Reed Oct 02 '20 at 21:17
  • Yes, this returns DriverService process id - the property summary explicitly says that: "Gets the process ID of the running driver service executable" - the answer is misleading – Piotr M. Dec 12 '20 at 21:22
13
var g = Guid.NewGuid();
driver.Navigate().GoToUrl("about:blank");
driver.ExecuteScript($"document.title = '{g}'");
var pid = Process.GetProcessesByName("firefox").First(p => 
p.MainWindowTitle.Contains(g.ToString()));
MD. Khairul Basar
  • 4,976
  • 14
  • 41
  • 59
W0nd3r
  • 131
  • 1
  • 2
12

Looks more like a C# question, instead of Selenium specific.

This is a very old non-deterministic answer, please reconsider if you want to try this out.

My logic would be you get all process PIDs with the name firefox using Process.GetProcessesByName Method, then start your FirefoxDriver, then get the processes' PIDs again, compare them to get the PIDs just started. In this case, it doesn't matter how many processes have been started by a specific driver (For example, Chrome starts multiple, Firefox only one).

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Firefox;

namespace TestProcess {
    [TestClass]
    public class UnitTest1 {
        [TestMethod]
        public void TestMethod1() {
            IEnumerable<int> pidsBefore = Process.GetProcessesByName("firefox").Select(p => p.Id);

            FirefoxDriver driver = new FirefoxDriver();
            IEnumerable<int> pidsAfter = Process.GetProcessesByName("firefox").Select(p => p.Id);

            IEnumerable<int> newFirefoxPids = pidsAfter.Except(pidsBefore);

            // do some stuff with PID if you want to kill them, do the following
            foreach (int pid in newFirefoxPids) {
                Process.GetProcessById(pid).Kill();
            }
        }
    }
}
Yi Zeng
  • 32,020
  • 13
  • 97
  • 125
  • 6
    Not deterministic. Other tests running in parallel may create processes between two 'GetProcessesByName' calls – Illidan May 22 '18 at 18:36
7

I didn't try with Firefox, but that is the way that works with Chrome:

        // creating a driver service
        var driverService = ChromeDriverService.CreateDefaultService();
        _driver = new ChromeDriver(driverService);

        //create list of process id
        var driverProcessIds = new List<int> { driverService.ProcessId };

        //Get all the childs generated by the driver like conhost, chrome.exe...
        var mos = new System.Management.ManagementObjectSearcher($"Select * From Win32_Process Where ParentProcessID={driverService.ProcessId}");
        foreach (var mo in mos.Get())
        {
            var pid = Convert.ToInt32(mo["ProcessID"]);
            driverProcessIds.Add(pid);
        }

        //Kill all
        foreach (var id in driverProcessIds)
        {
            System.Diagnostics.Process.GetProcessById(id).Kill();
        }
juanora
  • 542
  • 10
  • 21
1

Try to use parent process id:

  public static Process GetWindowHandleByDriverId(int driverId)
    {
        var processes = Process.GetProcessesByName("chrome")
            .Where(_ => !_.MainWindowHandle.Equals(IntPtr.Zero));
        foreach (var process in processes)
        {
            var parentId = GetParentProcess(process.Id);
            if (parentId == driverId)
            {
                return process;
            }

        }
        return null;
    }

    private static int GetParentProcess(int Id)
    {
        int parentPid = 0;
        using (ManagementObject mo = new ManagementObject($"win32_process.handle='{Id}'"))
        {
            mo.Get();
            parentPid = Convert.ToInt32(mo["ParentProcessId"]);
        }
        return parentPid;
    }
ggJa
  • 19
  • 3
  • This seems like such a better way than the accepted answer because it isn't a brute force way of finding the browsers pid. Also the WebDriver now has a CurrentWindowHandle property so you dont even need to look for all Chromes on the PC. – Max Young May 24 '17 at 20:18
  • This will kill all the chrome instances even if is not a test or if is another test running on parallel... – juanora Jul 26 '18 at 13:54
  • The 'CurrentWindowHandle' property is of type String, and the value, once casted to Int64, will throw an arithmetic overflow exception when trying to pass it to the IntPtr/UIntPtr constuctor. So that handle does not seem to be a Win32 window handle, thus it will not help to find the process. At least for my Firefox. – ElektroStudios Jul 26 '19 at 14:00
0

To get process id and attempt to kill it you would use Process class. The methods of interests are:

  • GetProcessesByName
  • Kill

Once you resolve a process by name you can query it's property: process.Id for an id. Keep in mind, some browsers, like Google Chrome have several running processes (Chrome has at least one running process per tab). So if you want to kill it, you need to kill all the processes.

oleksii
  • 35,458
  • 16
  • 93
  • 163
0

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/

0

you can give a name to the start window, and find the process by name

Driver = new TouchChromeDriver(service, options, TimeSpan.FromSeconds(30));
        Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);

        var conts = GetHashCode();
        (Driver as IJavaScriptExecutor).ExecuteScript($"document.title = '{conts}'");
        Thread.Sleep(TimeSpan.FromSeconds(1));
        var pc = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle == $"{conts} - Google Chrome");
        if (pc != null)
            pidChromeWindow = pc.Id;

        pidChromeDriver = service.ProcessId;
Kotyara
  • 11
  • 2
  • Hi Kotyara! Thanks for offering an answer to this question. I see you're new here, so I'll offer some advice - people are more likely to accept an answer and vote it up if there's some explanation as to why and how the proposed solution works. Currently this code snippet may work, but the person using it won't necessarily understand it - which could lead to difficulty debugging and fault finding. – IAmJersh Jul 21 '21 at 09:55
  • Hi @TheHitchenator thanks, I will keep this in mind in the future – Kotyara Jul 21 '21 at 12:01