【问题标题】:Retrieve current URL from C# windows forms application从 C# windows 窗体应用程序中检索当前 URL
【发布时间】:2011-07-16 02:46:22
【问题描述】:

我一直在使用 Visual C# 设计一个程序,但遇到了让我的程序与 Web 浏览器交互的问题。基本上我需要的是从网络浏览器(Internet Explorer、Firefox、Chrome 等)中检索 URL 地址。

我认为这不会是一项太难的任务,但经过几天和几天的研究和测试,这似乎几乎是不可能的!到目前为止,我遇到过这个......

Get Firefox URL?

代码如下:

using NDde.Client;
Class Test
{
    public static string GetFirefoxURL()
    {
        DdeClient dde = new DdeClient("Firefox", "WWW_GetWindowInfo");
        dde.Connect();
        string url = dde.Request("URL", int.MaxValue);
        dde.Disconnect();
        return url;
    }
}

这对于 Firefox 来说是完美的,但由于某种原因,我无法让它与其他任何东西一起使用。我已经将代码中写着“Firefox”的部分更改为“Iexplore”,就像我在互联网上发现的那样,并尝试了其他形式的 Internet Explorer 表达方式,但出现以下错误:

“客户端无法连接到“IExplorer|WWW_GetWindowInfo”,请确保服务器应用程序正在运行并且它支持指定的服务名称和主题名称对”

我们将不胜感激任何有关此问题的帮助,因为它已成为一项艰巨的任务。

【问题讨论】:

  • 您不会在不同的应用程序中扩展相同的DDE。而且,我记得,您可能需要将 COM 用于 IE(不确定 chrome)。
  • 是什么让您相信任何浏览器都有一种独特的方式来实现这一目标?我什至不希望所有流行的浏览器都有一种非独特的方式。
  • 我找到的有用链接:stackoverflow.com/questions/3579649/…(尽管我 99% 确信这可以简化)
  • 正如我在回答中所说,所有主流浏览器(除了 Chrome)都支持 WWW_GetWindowInfo,因此您应该能够想出一个具有共性的方法,至少在那些支持 WWW_GetWindowInfo 的浏览器上。
  • 感谢大家的帮助和cmets。 Simon 的方法非常适合我的需要,让我看到了 Microsoft 编程中完全不同的部分!

标签: c# .net url


【解决方案1】:

这是基于Microsoft UI Automation的代码:

public static string GetChromeUrl(Process process)
{
    if (process == null)
        throw new ArgumentNullException("process");

    if (process.MainWindowHandle == IntPtr.Zero)
        return null;

    AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
    if (element == null)
        return null;

    AutomationElement edit = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
    return ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}

public static string GetInternetExplorerUrl(Process process)
{
    if (process == null)
        throw new ArgumentNullException("process");

    if (process.MainWindowHandle == IntPtr.Zero)
        return null;

    AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
    if (element == null)
        return null;

    AutomationElement rebar = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "ReBarWindow32"));
    if (rebar == null)
        return null;

    AutomationElement edit = rebar.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

    return ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}

public static string GetFirefoxUrl(Process process)
{
    if (process == null)
        throw new ArgumentNullException("process");

    if (process.MainWindowHandle == IntPtr.Zero)
        return null;

    AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
    if (element == null)
        return null;

    AutomationElement doc = element.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
    if (doc == null)
        return null;

    return ((ValuePattern)doc.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}

您可以使用UI Spy tool 了解所有 3 个浏览器的视觉层次结构。您可能需要调整一些东西以确保它在您的特定情况下确实有效,但您应该通过这些示例了解总体思路。

还有一个转储系统中当前运行的所有 3 种类型的进程(IE、FF、CH)的所有 url 的示例:

static void Main(string[] args)
{
    foreach (Process process in Process.GetProcessesByName("firefox"))
    {
        string url = GetFirefoxUrl(process);
        if (url == null)
            continue;

        Console.WriteLine("FF Url for '" + process.MainWindowTitle + "' is " + url);
    }

    foreach (Process process in Process.GetProcessesByName("iexplore"))
    {
        string url = GetInternetExplorerUrl(process);
        if (url == null)
            continue;

        Console.WriteLine("IE Url for '" + process.MainWindowTitle + "' is " + url);
    }

    foreach (Process process in Process.GetProcessesByName("chrome"))
    {
        string url = GetChromeUrl(process);
        if (url == null)
            continue;

        Console.WriteLine("CH Url for '" + process.MainWindowTitle + "' is " + url);
    }
}

【讨论】:

  • 大家好,非常感谢您的回复!他们都非常有帮助。 @simon mourier,我真的很喜欢你的方法,它为我以后需要的东西开辟了很多可能性。但是,当我去实现它时(在添加对 UIAutomation 的引用之后),我在“TreeScope.Children”上收到一个错误,指出“无法解析符号'TreeScope'。有什么想法吗?另外,我收到一个错误,说明自动化属性已定义在未引用的程序集中。任何想法?再次感谢您的巨大帮助。
  • 糟糕,忽略最后一条评论。无论如何我都会留下它,以防万一其他人看到这个帖子并犯下我刚刚犯的同样愚蠢的错误。当我需要添加所有引用(我没有看到)时,我只添加了 UIAutomation 客户端引用。我现在要搞乱代码,看看情况如何!我会尽快回复。再次感谢大家的帮助。
  • 代码完美运行,西蒙!非常感谢,这正是我需要的。现在,如果您有时间,我不介意快速上一堂关于它是如何工作的课程,这样我可以更好地理解它,并可能为其他浏览器(如 Safari)实现它。如果您没有时间,我会理解并感谢您已经完成的工作。谢谢!
  • @Sam - 嗯...我看过 Safari,结果看起来不太好...它确实以某种方式支持 UI 自动化,但 UI Spy 显示我们无法获得到 url 控制面板,与其他浏览器不同。而且我认为 Safari 也不支持 WWW_GetWindowInfo DDE 主题。 Safari 对我来说似乎很糟糕。
  • 无赖!好吧,至少我可以摆脱这三个,这本身就是一个巨大的帮助。我现在至少可以用你帮助我学习的东西继续我的编码,希望以后我能找到另一种 Safari 的方法。再次感谢西蒙!
【解决方案2】:

Mourier,感谢您的解决方案Microsoft UI 自动化。 即便如此,它也不适用于 Firefox 41.0, 我用小工具"Automation Spy"分析了火狐的窗口结构。 然后我稍微改变了搜索条件,效果很好!

 public static string GetFirefoxUrl(Process process)
        {
            if (process == null)
                throw new ArgumentNullException("process");

            if (process.MainWindowHandle == IntPtr.Zero)
                return null;

            AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
            if (element == null)
                return null;


            element = element.FindFirst(TreeScope.Subtree, 
                  new AndCondition(
                      new PropertyCondition(AutomationElement.NameProperty, "search or enter address", PropertyConditionFlags.IgnoreCase),
                      new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)));


            if (element == null)
                return null;

            return ((ValuePattern)element.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
        }

这是 Chromium 48 的解决方案:

 public static string GetChromeUrl(Process process)
    {
        if (process == null)
            throw new ArgumentNullException("process");

        if (process.MainWindowHandle == IntPtr.Zero)
            return null;

        AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
        if (element == null)
            return null;

        AutomationElement edit = element.FindFirst(TreeScope.Subtree,
             new AndCondition(
                  new PropertyCondition(AutomationElement.NameProperty, "address and search bar", PropertyConditionFlags.IgnoreCase),
                  new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)));

        return ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
    }

Automation Spy 显示 Firefox 窗口控件结构。名称为“搜索或输入地址”的“编辑”类型控件保存 url:

注意:在您的 .NET 项目中,您需要 2 个引用:

  • UIAutomationClient.dll
  • UIAutomationTypes.dll

【讨论】:

    【解决方案3】:

    在 IE 的 oDde.Request("URL", int.MaxValue) 中使用参数“1”而不是“URL”。

        public static void ProcessIEURLs()
        {
    
            string sURL;
            try
            {
                DdeClient oDde = new DdeClient("IExplore", "WWW_GetWindowInfo");
    
                try
                {
                    oDde.Connect();
    
                    sURL = oDde.Request("1", int.MaxValue);
    
                    oDde.Disconnect();
    
                    bool bVisited = false;
                    if ( oVisitedURLList != null && oVisitedURLList.Count > 0 )
                    {
                        bVisited = FindURL(sURL, oVisitedURLList);
                    }
    
                    if ( !bVisited )
                    {
                        oVisitedURLList.Add(sURL);
                    }
                }
                catch ( Exception ex )
                {
                    throw ex;
                }
    
            }
            catch ( Exception ex )
            {
                throw ex;
            }
        }
    

    【讨论】:

      【解决方案4】:

      这是我目前所拥有的(尽管我在 Chrome 上没有找到任何有用的文章,除了使用 FindWindowEx(我个人不是特别喜欢这种方法)。

      public class BrowserLocation
      {
          /// <summary>
          /// Structure to hold the details regarding a browed location
          /// </summary>
          public struct URLDetails
          {
              /// <summary>
              /// URL (location)
              /// </summary>
              public String URL;
      
              /// <summary>
              /// Document title
              /// </summary>
              public String Title;
          }
      
          #region Internet Explorer
      
          // requires the following DLL added as a reference:
          // C:\Windows\System32\shdocvw.dll
      
          /// <summary>
          /// Retrieve the current open URLs in Internet Explorer
          /// </summary>
          /// <returns></returns>
          public static URLDetails[] InternetExplorer()
          {
              System.Collections.Generic.List<URLDetails> URLs = new System.Collections.Generic.List<URLDetails>();
              var shellWindows = new SHDocVw.ShellWindows();
              foreach (SHDocVw.InternetExplorer ie in shellWindows)
                  URLs.Add(new URLDetails() { URL = ie.LocationURL, Title = ie.LocationName });
              return URLs.ToArray();
          }
      
          #endregion
      
          #region Firefox
      
          // This requires NDde
          // http://ndde.codeplex.com/
      
          public static URLDetails[] Firefox()
          {
              NDde.Client.DdeClient dde = new NDde.Client.DdeClient("Firefox", "WWW_GetWindowInfo");
              try
              {
                  dde.Connect();
                  String url = dde.Request("URL", Int32.MaxValue);
                  dde.Disconnect();
      
                  Int32 stop = url.IndexOf('"', 1);
                  return new URLDetails[]{
                      new URLDetails()
                      {
                          URL = url.Substring(1, stop - 1),
                          Title = url.Substring(stop + 3, url.Length - stop - 8)
                      }
                  };
              }
              catch (Exception)
              {
                  return null;
              }
          }
      
          #endregion
      }
      
      class Program
      {
          static void Main(string[] args)
          {
              Console.WriteLine("Internet Explorer: ");
              (new List<BrowserLocation.URLDetails>(BrowserLocation.InternetExplorer())).ForEach(u =>
              {
                  Console.WriteLine("[{0}]\r\n{1}\r\n", u.Title, u.URL);
              });
              Console.WriteLine();
      
              Console.WriteLine("Firefox:");
              (new List<BrowserLocation.URLDetails>(BrowserLocation.Firefox())).ForEach(u =>
              {
                  Console.WriteLine("[{0}]\r\n{1}\r\n", u.Title, u.URL);
              });
              Console.WriteLine();
          }
      }
      

      【讨论】:

        【解决方案5】:

        在 16 位时代,IE 和 has been since version 3.02 支持 WWW_GetWindowInfo!适用于 Firefox 和 Opera

        我相信 Chrome 实际上是一个奇怪的版本。

        我不知道这四个之外的情况。

        【讨论】:

          【解决方案6】:

          最好的选择是使用 selenium webdriver。具有完整前提的最佳和强大的完整 API

          【讨论】:

          • 假设 OP 希望在测试框架内执行此操作。我对这个问题的印象是他/她想要在他/她自己的代码库中使用该功能。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-09
          • 1970-01-01
          • 2020-11-13
          相关资源
          最近更新 更多