1. 程式人生 > >C# 依據鼠標坐標取網頁內成員坐標.ie

C# 依據鼠標坐標取網頁內成員坐標.ie

readonly acc win ast screen 閱讀 pty 瀏覽器 簡單

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");

C# 依據鼠標坐標取網頁內成員坐標.ie