C# 根據滑鼠座標取網頁內成員座標.ie,
有時候你需要後台擷取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");