有时候你需要后台获取ie浏览器 鼠标所在位置的元素坐标,然而你使用屏幕坐标是不可行的
所以我们需要把坐标转换成浏览器内坐标 然后再通过elementFromPoint获取网页成员。
private void tmrWatcher_Tick(object sender, EventArgs e) { IntPtr hWnd = WindowFromPoint(MousePosition); dynamic document = GetHtmlDocumentByHandle(hWnd); if (document != null) { Rectangle r = GetHtmlElementPoint(hWnd, MousePosition, document); // 根据鼠标坐标取网页成员坐标 Marshal.FinalReleaseComObject(document); Console.WriteLine(r.X + ":" + r.Y + ":" + r.Width + ":" + r.Height); } }
上面是一个时钟tmrWatcher的Tick回调函数,在上面使用了WindowFromPoint函数 主要是获取
MousePosition所在的窗口句柄,然后再通过GetHtmlDocumentByHandle函数(获取文档从句柄)
public static object GetComObjectByHandle(int Msg, Guid riid, IntPtr hWnd) { object _ComObject; int lpdwResult = 0; if (!SendMessageTimeout(hWnd, Msg, 0, 0, SMTO_ABORTIFHUNG, 1000, ref lpdwResult)) return null; if (ObjectFromLresult(lpdwResult, ref riid, 0, out _ComObject)) return null; return _ComObject; } public object GetHtmlDocumentByHandle(IntPtr hWnd) { string buffer = new string('\0', 24); GetClassName(hWnd, ref buffer, 25); if (buffer != "Internet Explorer_Server") return null; return GetComObjectByHandle(WM_HTML_GETOBJECT, IID_IHTMLDocument, hWnd); }实际上与我上次的帖子:http://blog.csdn.net/u012395622/article/details/46404193
并没什么太大的出入,而获取一个网页文档的成员只是简单的调度Mshtml COM接口
public Rectangle GetHtmlElementPoint(IntPtr hWnd, Point point, dynamic document) { if (document == null && hWnd != IntPtr.Zero) return Rectangle.Empty; ScreenToClient(hWnd, ref point); dynamic element = document.elementFromPoint(point.X, point.Y); if (element == null) return Rectangle.Empty; try { Rectangle o = new Rectangle() { Y = element.offsetTop, X = element.offsetLeft, Width = element.offsetWidth, Height = element.offsetHeight }; while (element.offsetParent != null) { element = element.offsetParent; o.Y += element.offsetTop; o.X += element.offsetLeft; } return o; } catch { return Rectangle.Empty; } }上面代码是实现获取 元素在网页内的一个确切坐标,整体并不是很难阅读的。
之所以while(element.offsetParent != null) { ... }是因为网页始终与客户端不相
同我们不能用常规在Win32操作控件位置那样去看待它 它很麻烦,而且层次
很难分明,所以会造成你根本不知道到底有多宽不过还好,一般计算一个
成员元素在窗口什么位置,只要把父容器的位置加起来就行了。反正有点
解释的不清楚,大家莫见怪
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetClassName( [In]IntPtr hWnd, [MarshalAs(UnmanagedType.VBByRefStr)]ref string IpClassName, [In]int nMaxCount ); [DllImport("oleacc.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ObjectFromLresult( [In]int lResult, [In]ref Guid riid, [In]int wParam, [Out, MarshalAs(UnmanagedType.IUnknown)]out object ppvObject ); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.I4)] public static extern int RegisterWindowMessage( [In]string lpString ); [DllImport("user32.dll", EntryPoint = "SendMessageTimeoutA", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SendMessageTimeout( [In]IntPtr MSG, [In]int hWnd, [In]int wParam, [In]int lParam, [In]int fuFlags, [In]int uTimeout, [In, Out]ref int lpdwResult ); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.SysInt)] public static extern IntPtr WindowFromPoint( [In]Point Point ); public const int SMTO_ABORTIFHUNG = 2; public readonly static int WM_HTML_GETOBJECT = RegisterWindowMessage("WM_HTML_GETOBJECT"); public readonly static Guid IID_IHTMLDocument = new Guid("626fc520-a41e-11cf-a731-00a0c9082637");