c# - 使用 C# 从 Google Chrome 获取当前选项卡的 URL

标签 c# google-chrome

过去有一种方法可以通过使用 FindWindowEx 结合 SendMessage 调用从 Google Chrome 获取事件标签的 URL,以获取当前在多功能框中的文本。最近的(?)更新似乎打破了这种方法,因为 Chrome 现在似乎正在渲染一切。 (你可以使用 Spy++、AHK Window Spy 或 Window Detective 检查)

要获取 Firefox 和 Opera 上的当前 URL,您可以使用 DDE 和 WWW_GetWindowInfo。这在 Chrome 上似乎不可能(现在?)。

This question有一个关于它过去如何工作的更多信息的答案,这是这段代码(正如我解释的那样,它不再工作 - hAddressBox0) :

var hAddressBox = FindWindowEx(
    intPtr,
    IntPtr.Zero,
    "Chrome_OmniboxView",
    IntPtr.Zero);

var sb = new StringBuilder(256);
SendMessage(hAddressBox, 0x000D, (IntPtr)256, sb);
temp = sb.ToString();

所以我的问题是:是否有一种方法来获取当前获得焦点的选项卡的 URL? (只有标题是不够的)

最佳答案

编辑:对于较新的 Chrome 版本,我在这里的回答中的代码似乎不再有效(尽管使用 AutomationElement 的想法仍然有效),所以看通过不同版本的其他答案。例如,这是 Chrome 54 的一个:https://stackoverflow.com/a/40638519/377618

以下代码似乎可以工作(感谢 icemanind 的评论),但它是资源密集型的。找到 elmUrlBar 大约需要 350 毫秒……有点慢。

更不用说我们遇到了同时运行多个 chrome 进程的问题。

// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
  // the chrome process must have a window
  if (chrome.MainWindowHandle == IntPtr.Zero) {
    continue;
  }

  // find the automation element
  AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
  AutomationElement elmUrlBar = elm.FindFirst(TreeScope.Descendants,
    new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));

  // if it can be found, get the value from the URL bar
  if (elmUrlBar != null) {
    AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
    if (patterns.Length > 0) {
      ValuePattern val = (ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0]);
      Console.WriteLine("Chrome URL found: " + val.Current.Value);
    }
  }
}

编辑:我对上面的慢速方法不满意,所以我让它更快(现在是 50 毫秒)并添加了一些 URL 验证以确保我们得到正确的 URL 而不是用户的东西可能正在网络上搜索,或者仍在忙于输入 URL。这是代码:

// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
  // the chrome process must have a window
  if (chrome.MainWindowHandle == IntPtr.Zero) {
    continue;
  }

  // find the automation element
  AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);

  // manually walk through the tree, searching using TreeScope.Descendants is too slow (even if it's more reliable)
  AutomationElement elmUrlBar = null;
  try {
    // walking path found using inspect.exe (Windows SDK) for Chrome 31.0.1650.63 m (currently the latest stable)
    var elm1 = elm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
    if (elm1 == null) { continue; } // not the right chrome.exe
    // here, you can optionally check if Incognito is enabled:
    //bool bIncognito = TreeWalker.RawViewWalker.GetFirstChild(TreeWalker.RawViewWalker.GetFirstChild(elm1)) != null;
    var elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1); // I don't know a Condition for this for finding :(
    var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
    var elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
    elmUrlBar = elm4.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));
  } catch {
    // Chrome has probably changed something, and above walking needs to be modified. :(
    // put an assertion here or something to make sure you don't miss it
    continue;
  }

  // make sure it's valid
  if (elmUrlBar == null) {
    // it's not..
    continue;
  }

  // elmUrlBar is now the URL bar element. we have to make sure that it's out of keyboard focus if we want to get a valid URL
  if ((bool)elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty)) {
    continue;
  }

  // there might not be a valid pattern to use, so we have to make sure we have one
  AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
  if (patterns.Length == 1) {
    string ret = "";
    try {
      ret = ((ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0])).Current.Value;
    } catch { }
    if (ret != "") {
      // must match a domain name (and possibly "https://" in front)
      if (Regex.IsMatch(ret, @"^(https:\/\/)?[a-zA-Z0-9\-\.]+(\.[a-zA-Z]{2,4}).*$")) {
        // prepend http:// to the url, because Chrome hides it if it's not SSL
        if (!ret.StartsWith("http")) {
          ret = "http://" + ret;
        }
        Console.WriteLine("Open Chrome URL found: '" + ret + "'");
      }
    }
    continue;
  }
}

关于c# - 使用 C# 从 Google Chrome 获取当前选项卡的 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18897070/

相关文章:

c# - 如何检测程序是否在运行时抛出的异常下执行?

c# - 将 UIImage 转换为字节数组

c# - 如何将英语中的数值转换为 C# 中的马拉地语数值?

google-chrome - 带有 SubjectAlternativeName (SAN) 的证书在 Google Chrome 中给出了 ERR_CONNECTION_RESET

javascript - 在 Chrome 控制台中展开 JavaScript 对象时显示不同的属性值

html - Chrome 自动隐藏垂直滚动条

c# - 从客户端计算机上的文件路径加载 xml 文件

C#单元测试,如何测试大于

css - Chrome 的表格单元格填充问题

javascript - 如何在 Safari 中使用 AJAX 调用之前的 WebShareAPI?