从浏览器获取 URL 到 C# 应用程序
Posted
技术标签:
【中文标题】从浏览器获取 URL 到 C# 应用程序【英文标题】:Get URL from browser to C# application 【发布时间】:2011-04-04 12:36:58 【问题描述】:如何使用 C# .NET windows form 应用程序从正在运行的 Chrome 或 Opera 实例获取 url? 谢谢!
【问题讨论】:
你能描述一下你想要完成的事情吗? 选择 IE,我们可以帮助您。 是的,当然 :) 我正在尝试做应用程序,它将获取(当前选项卡)活动网站的 URL(中性:Firefox、IE、Chrome 等)到我的应用程序.在 Firefox 中,我使用 NDde.dll 和 DdeClient 类 - 非常简单,但它仅适用于 Firefox。类似的 user32.dll 的 DllImport 帮助我从 IE 获取 url...只有 IE :) (或者我不知道如何为其他浏览器扩展它)你知道如何在其他浏览器中执行此操作吗?任何通用方法或专门针对特定浏览器。 在此处查看 Microsoft UI 自动化的答案。为我工作 Firefox 41.0 和 Chromium 48 ---> ***.com/questions/5317642/… 【参考方案1】:除非浏览器记录在案以自己提供该信息,否则我认为没有可靠的方法可以做到这一点。
话虽如此,我很确定至少 Chrome 将历史信息存储在磁盘上的某个位置,所以最好的办法可能是弄清楚它的位置、格式以及如何读取它。
【讨论】:
是的,这是一种解决方案,但不适用于便携式浏览器。您可以删除文件夹或在随身碟上使用它,并且没有访问网站的标记。所以这对我来说不是一个好的解决方案:)【参考方案2】:第 2 部分:
基本上我有太多的代码来分离这个例子的最小值,但我在下面提供了我自己的算法供你倾注。
这个还跟踪浏览器中的选项卡,当它们重新出现时(仅限 IE),所以你需要去掉你不想要的部分。我似乎记得我为 IE8 修复了此问题,但不确定该修复程序是否包含在此代码中,因此如果需要稍作调整,请不要感到惊讶 :)
// Iterate all browsers and record the details
IntPtr hWnd = IntPtr.Zero;
NativeWIN32.EnumChildWindows(hWnd, new NativeWIN32.Win32Callback(BrowserEnumCallback), hWnd);
/// <summary>
/// Called back for each IE browser.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
static bool BrowserEnumCallback(IntPtr hWnd, IntPtr lParam)
// Is this app IE?
if (NativeWIN32.GetClassName(hWnd) == "IEFrame")
// If this is a new browser, add it
if (!BrowserWindows.ContainsKey(hWnd))
// Record the Browser
BrowserWindow browser = new BrowserWindow()
hWnd = hWnd
;
// Store the browser in the temp list and temp member
TempCurrentBrowser = browser;
BrowserWindows.Add(hWnd, browser);
else
// Store the browser in the temp list and temp member
TempCurrentBrowser = BrowserWindows[hWnd];
TempCurrentBrowser.WindowText = NativeWIN32.GetWindowText(hWnd);
TempCurrentBrowser.Found = true;
// Now that we know it is a browser, look for tabbed windows and address bar
NativeWIN32.EnumChildWindows(hWnd, new NativeWIN32.Win32Callback(BrowserEnumChildrenCallback), hWnd);
return true;
/// <summary>
/// Called back for each child window in the browser
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
static bool BrowserEnumChildrenCallback(IntPtr hWnd, IntPtr lParam)
string classname = NativeWIN32.GetClassName(hWnd);
switch (classname)
// This is the main address bar
case "Edit":
string url = NativeWIN32.GetWindowText(hWnd);
if (url.StartsWith(@"http://") || url.StartsWith(@"https://") || url.StartsWith("about:"))
TempCurrentBrowser.Url = url;
return true;
break;
case "ComboBoxEx32":
string url = NativeWIN32.GetWindowText(hWnd);
if (url.StartsWith(@"http://") || url.StartsWith(@"https://") || url.StartsWith("about:"))
TempCurrentBrowser.Url = url;
return true;
break;
// Record any sub pages still active, by title to avoid revisiting popup
// If this name matches the name of the browser, it is the current window
// If so, record the browser url for reference in that tab window
case "TabWindowClass":
string title = NativeWIN32.GetWindowText(hWnd);
BrowserTabWindow tabWindow;
if (!TempCurrentBrowser.TabWindows.ContainsKey(hWnd))
// Create a new tabbed window for the current browser
tabWindow = new BrowserTabWindow()
hWnd = hWnd
;
TempCurrentBrowser.TabWindows.Add(hWnd, tabWindow);
else
tabWindow = TempCurrentBrowser.TabWindows[hWnd];
tabWindow.WindowText = title;
tabWindow.Found = true;
break;
return true;
第 1 部分:
如果 Microsoft Spy++ 可以看到地址控件,那么是的。
我没有安装 Opera,但 Spy++ 中的 Chrome 控件层次结构如下所示:
我用 Internet Explorer 做过类似的事情:
记录访问过的网站的日记 - 然后弹出窗口询问用户他们在做什么 显示访问某些已知网站时弹出的小部件Firefox 是问题的孩子,因为它在内部而不是通过 Windows 控件呈现地址栏,但我看到您已经找到了解决方案。
在 C# 中,您需要对 Windows API 方法进行非托管调用。正如您仅从 C# API 代码(如下)中所看到的,它可能会涉及一些内容:
const int WM_GETTEXT = 0xD;
// used for an output LPCTSTR parameter on a method call
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct STRINGBUFFER
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szText;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);
/// <summary>
///
/// </summary>
/// <param name="hWnd">handle to destination window</param>
/// <param name="msg">message</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam"second message parameter></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, out STRINGBUFFER ClassName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
//[DllImport("user32.dll")]
//[return: MarshalAs(UnmanagedType.Bool)]
//static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
/// <summary>
/// Helper to get window classname
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetClassName(IntPtr hWnd)
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetClassName(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
/// <summary>
/// Helper to get window text
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetWindowText(IntPtr hWnd)
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
SendMessage(hWnd, WM_GETTEXT, 256, out sLimitedLengthWindowTitle);
//NativeWIN32.GetWindowText(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
所涉及的算法基本上从桌面向下搜索所有窗口,直到找到 Browser 窗口(基于特定的类或窗口属性)。然后它会根据浏览器的类型搜索特定的子元素。当您最终到达地址控件时,您可以从控件中提取地址。希望我的帮助类代码能够加快您的开发速度。
“NativeWIN32”后续 - 2013 年 12 月
NativeWIN32
引用只是对包含其他 Win32 功能的有用常量和方法的包装类。我在这里完整添加了它:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace YourProject
/// <summary>
/// Wrapper for native win32 calls
/// </summary>
public class NativeWIN32
const int WM_GETTEXT = 0xD;
// used for an output LPCTSTR parameter on a method call
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct STRINGBUFFER
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szText;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);
/// <summary>
///
/// </summary>
/// <param name="hWnd">handle to destination window</param>
/// <param name="msg">message</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam"second message parameter></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, out STRINGBUFFER ClassName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
//[DllImport("user32.dll")]
//[return: MarshalAs(UnmanagedType.Bool)]
//static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
/// <summary>
/// Helper to get window classname
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetClassName(IntPtr hWnd)
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetClassName(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
/// <summary>
/// Helper to get window text
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetWindowText(IntPtr hWnd)
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
SendMessage(hWnd, WM_GETTEXT, 256, out sLimitedLengthWindowTitle);
//NativeWIN32.GetWindowText(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
【讨论】:
您如何以编程方式确定您想要哪一个?只是寻找“http”?还是有一些我不知道的更可靠的方法? 是的,这是一个很好的解决方案,但不幸的是只有 IE,因为在 Chrome 中每个标签都没有隐藏 url。我现在检查了这个,对于 10 个选项卡,在 spy++ 中这棵树上只有一个有 url。所以不是这样,或者我有特定版本的浏览器;)检查一下,如果我错了,请告诉我。 @Saint... 为什么您想知道用户没有查看的选项卡的 URL?您可能需要进一步解释您的要求? (他们是邪恶的吗?):) img840.imageshack.us/img840/8938/chromee.png 我应该转到下一个窗口 Chrome_WidgetWin_0,但不要这样做是最好的方法。任何想法? :) @TrueBlueAussie 哎呀,在这种情况下,我认为您已经编写了两次包装器。我认为你应该删除第一个。【参考方案3】: [DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, StringBuilder ClassName);
private static string GetURL(IntPtr intPtr, string programName, out string url)
string temp=null;
if (programName.Equals("chrome"))
var hAddressBox = FindWindowEx(intPtr, IntPtr.Zero, "Chrome_OmniboxView", IntPtr.Zero);
var sb = new StringBuilder(256);
SendMessage(hAddressBox, 0x000D, (IntPtr)256, sb);
temp = sb.ToString();
if (programName.Equals("iexplore"))
foreach (InternetExplorer ie in new ShellWindows())
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ie.FullName);
if (fileNameWithoutExtension != null)
var filename = fileNameWithoutExtension.ToLower();
if (filename.Equals("iexplore"))
temp+=ie.LocationURL + " ";
if (programName.Equals("firefox"))
DdeClient dde = new DdeClient("Firefox", "WWW_GetWindowInfo");
dde.Connect();
string url1 = dde.Request("URL", int.MaxValue);
dde.Disconnect();
temp = url1.Replace("\"","").Replace("\0","");
url = temp;
return temp;
请执行以下操作以运行此代码 在您的项目中添加来自 VS.NET 的 Reference > Com > Microsoft.Internet.Controls
从http://ndde.codeplex.com/ 下载 DdeClient 类的 bin 并将其添加到您的项目中
【讨论】:
我已经为 Firefox 测试了上面的代码,工作正常!!但是它只会让我得到 URL 和页面标题。我对该页面的 html 内容更感兴趣。有什么办法可以将整个页面(HTML 内容)解析成字符串??【参考方案4】:IE11、Chrome、Firefox、Opera、Safari 都有接口来获取 URL 甚至 DOM,或者至少是文档/HTML 缓冲区。 FF 实际上有一个带有导出功能的 DLL 可以为你做这件事,我忘记了如何在其他人下可靠地做到这一点,但我知道它已经完成了。
【讨论】:
就目前而言,像这样的一些信息最好作为对 OP 的评论。如果您在记住后可以编辑一些细节,那么它可能是一个很好的答案。【参考方案5】:解决此问题的另一种方法可能是使用UI Automation 框架。
本例读取 Chrome 的当前 url:
var app = AutomationElement.FromHandle(new IntPtr(chrome_hwnd));
var propFindText = new PropertyCondition(AutomationElement.NameProperty, "Address and search bar");
var textbox = app.FindFirst(TreeScope.Descendants, propFindText);
Debug.WriteLine( textbox.GetCurrentPropertyValue(ValuePattern.ValueProperty).ToString());
Here 是关于 UI 自动化的优秀教程。
【讨论】:
【参考方案6】:从 IE 中找出打开的 Url
在 COM 选项卡中添加引用“Microsoft Internet Controls”,然后:
using SHDocVw;
我的完整指令列表如下所示:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using SHDocVw;
现在要从 IE 中找出标签页网址,请执行以下操作:
Dictionary<int, string> ieUrlsDictionary = new Dictionary<int, string>();
ShellWindows ieShellWindows = new SHDocVw.ShellWindows();
string sProcessType;
int i = 0;
foreach (InternetExplorer ieTab in ieShellWindows)
sProcessType = Path.GetFileNameWithoutExtension(ieTab.FullName).ToLower();
if (sProcessType.Equals("iexplore") && !ieTab.LocationURL.Contains("about:Tabs"))
ieUrlsDictionary[i] = ieTab.LocationURL;
i++;
//show list of url´s
for (int j = 0; j < ieUrlsDictionary.Count; j++)
Console.WriteLine(ieUrlsDictionary[j]);
【讨论】:
【参考方案7】:我通常只使用这样的东西:
//只要你打开浏览器: browserHandle = GetForegroundWindow();
SetFocus(browserHandle);
// send ctrl-d to get in address bar
SendKeys.SendWait("%d");
// send ctrl- to copy
SendKeys.SendWait("%c");
// then paste it where you want it
您需要一个 DLL 导入:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
【讨论】:
以上是关于从浏览器获取 URL 到 C# 应用程序的主要内容,如果未能解决你的问题,请参考以下文章
使用 C# 从 Google Chrome 获取当前标签页的 URL
C#:打开浏览器并从 Windows 桌面应用程序 POST 到 url