• 宋铖的博客—强国博客—人民网 2019-07-07
  • 科学恢复森林 广汽丰田用心守护自然家园 2019-06-10
  • 人民日报评论员:统筹推进新时代“五位一体”总体布局 2019-06-08
  • 日照世界帆船锦标赛基地 2019-05-23
  • 扬帆起航新时代 凝聚民心释放中国红利 2019-05-16
  • 全面把握网络强国战略思想的六个维度 2019-05-05
  • [微笑]那就是管理问题了,跟免不免费本身不相干! 2019-05-05
  • 阿呆,那是你家远祖啊,还不跪拜?[哈哈] 2019-04-30
  • 【互动话题】一句话形容过完年的你 2019-04-30
  • 主动扩大开放再发力 国务院出台六项举措鼓励利用外资 2019-04-20
  • 女性之声——全国妇联 2019-04-13
  • 为祝贺你们!为你们自豪,为你们骄傲——中国核电的创新者!这是“两弹一星”精神的延续,是“两弹一星”精神的发扬!有良心的中国人,更要感谢以毛泽东为首的老一辈无产阶 2019-04-10
  • 讲法治说情操 江北党员干部听“老马”宣讲“两会”精神 2019-04-10
  • 郧西男孩两条腿“长”在一起 十堰市人民医院手术整形帮他迈开双腿 2019-04-09
  • 新歌声惊现切葱歌 谢霆锋不当厨师做导师 2019-04-09
  • 11选5手机助手软件下载:WebBrowser弹出窗口之(二)––showModalDialog( ) & showModel

    2019-05-23 行业动态 haoservcie

    甘肃11选5开奖 www.rtn8.com showModalDialog并不创建新的浏览器窗口,也不创建新的浏览器对象,而是在WebBrowser的同一个线程中创建的窗口,而showModelessDialog( )则是在新的线程中创建的窗口,所以处理方式不相同。

    当showModalDialog( )被调用后,浏览器线程会创建一个对话框,该对话框包含两个窗口,父窗口的类为“Internet Explorer_TridentDlgFrame”,子窗口的类为“Internet Explorer_Server”,其子窗口即为IE内核的窗口,可以通过给该窗口发送消息,进行一些自动化操作(如按键、鼠标点击等)。当子窗口创建时,父窗口会收到WM_PARENTNOTIFY消息,hwnd值即为父窗口的值,wParam的值即为Internet Explorer_Server的窗口。我们捕获窗口后就可以捕捉到IE内核窗口的句柄了。
    STEP 1: 建立窗口事件的钩子函数
    // 使用Windows API函数

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr SetWindowsHookEx(HookType hooktype, HookProcedureDelegate callback, IntPtr hMod, UInt32 dwThreadId);

    // Hook Types
    public enum HookType
    {
        WH_JOURNALRECORD = 0,
        WH_JOURNALPLAYBACK = 1,
        WH_KEYBOARD = 2,
        WH_GETMESSAGE = 3,
        WH_CALLWNDPROC = 4,
        WH_CBT = 5,
        WH_SYSMSGFILTER = 6,
        WH_MOUSE = 7,
        WH_HARDWARE = 8,
        WH_DEBUG = 9,
        WH_SHELL = 10,
        WH_FOREGROUNDIDLE = 11,
        WH_CALLWNDPROCRET = 12,
        WH_KEYBOARD_LL = 13,
        WH_MOUSE_LL = 14
    }

    [StructLayout(LayoutKind.Sequential)]
            public struct CWPRETSTRUCT
            {
                public IntPtr lResult;
                public IntPtr lParam;
                public IntPtr wParam;
                public UInt32 message;
                public IntPtr hwnd;
            };

            // Delegate for the EnumChildWindows method
            private delegate Boolean EnumerateWindowDelegate(IntPtr pHwnd, IntPtr pParam);

    private static Win32API.HookProcedureDelegate _WH_CALLWNDPROCRET_PROC =
        new Win32API.HookProcedureDelegate(WH_CALLWNDPROCRET_PROC);

    // 在程序开始处调用该方法
    public static void Hook( )
    {
        if (_pWH_CALLWNDPROCRET == IntPtr.Zero) {
            _pWH_CALLWNDPROCRET = Win32API.SetWindowsHookEx(
                Win32API.HookType.WH_CALLWNDPROCRET
                ,_WH_CALLWNDPROCRET_PROC
                ,IntPtr.Zero
                ,(uint)AppDomain.GetCurrentThreadId( ));    // current thread
        }
        if (_pWH_CALLWNDPROCRET == IntPtr.Zero)
            throw new ApplicationException("Failed to install window hook via: SetWindowsHookEx( )");
    }

    // 自定义的消息钩子函数,在函数中捕捉PARENTNOTIFY消息,然后再检查该消息是否窗口创建或销毁窗口
    // 然后创建一个个事件WindowLife,在WebBrowser中添加该事件的处理函数即可
    public delegate void WindowLifeHandler(Win32Message msg, IntPtr parent, IntPtr child);
    public static event WindowLifeHandler WindowLife;
    private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode, IntPtr pWParam, IntPtr pLParam)
    {
        if (iCode < 0)
            return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);

        Win32API.CWPRETSTRUCT cwp = (Win32API.CWPRETSTRUCT)Marshal.PtrToStructure(pLParam, typeof(Win32API.CWPRETSTRUCT));
        Win32Message msg = Win32Message.WM_NULL;
        try {
            msg = (Win32Message)cwp.message;
        } catch {
            return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); ;
        }
        if (msg == Win32Message.WM_PARENTNOTIFY) {
            if ((int)cwp.wParam == (int)Win32Message.WM_CREATE || (int)cwp.wParam == (int)Win32Message.WM_DESTROY) {
                System.Diagnostics.Debug.WriteLine("WM_PARENTNOTIFY hwnd=0x{0:x8}  wParam={1} lParam=0x{2:x8}"
                    ,(int)cwp.hwnd, (Win32Message)cwp.wParam,(int)cwp.lParam);
                if (WindowLife != null)
                    WindowLife((Win32Message)cwp.wParam, cwp.hwnd, cwp.lParam);
            }
        }
        return Win32API.CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);
    }

    STEP 2:继承WebBrowser并在派生类中添加WindowLife事件的处理函数,在派生类的构造函数中增加如下代码:
    public class ExWebBrowser : System.Windows.Forms.WebBrowser
    {
         public ExWebBrowser( )
            {
                _windowLifeDelegate = new WindowsMessageHooker.WindowLifeHandler(OnWindowLife);
                WindowsMessageHooker.WindowLife += _windowLifeDelegate;
                this.Disposed += (sender, e) => {
                    WindowsMessageHooker.WindowLife -= _windowLifeDelegate;
                };

    private IntPtr _webPageDialogHandle = IntPtr.Zero;
    private static readonly string IE_WebDialogClassName = "Internet Explorer_TridentDlgFrame";
    private static readonly string IE_ServerClassName = "Internet Explorer_Server";

    public delegate void WebPageDialogHandler(IntPtr hwnd, string title);
    // 创建网页对话框时触发的事件
    public event WebPageDialogHandler ShowWebDialog;
    // 关闭网页对话框时触发的事件
    public event WebPageDialogHandler CloseWebDialog;
    private WindowsMessageHooker.WindowLifeHandler _windowLifeDelegate = null;

    private void OnWindowLife(noock.windows.Win32Message msg, IntPtr parent, IntPtr child)
    {
        StringBuilder buffer = null;
        string childClass = null;
        string parentClass = null;

            buffer = new StringBuilder(256);
        if (child != _webPageDialogHandle) {
            noock.windows.Win32API.GetClassName(child, buffer, buffer.Capacity);
            childClass = buffer.ToString( );
            System.Diagnostics.Debug.WriteLine("child class:" + childClass);
            if (childClass != IE_ServerClassName)
                return;
            noock.windows.Win32API.GetClassName(parent, buffer, buffer.Capacity);
            parentClass = buffer.ToString( );
            System.Diagnostics.Debug.WriteLine("parent class:" + parentClass);
            if (parentClass != IE_WebDialogClassName)
                return;
        }

        noock.windows.Win32API.GetWindowText(parent, buffer, buffer.Capacity);
        string title = buffer.ToString();

        if (msg == noock.windows.Win32Message.WM_CREATE) {
            _webPageDialogHandle = child;
            System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Opening:");
            if (ShowWebDialog != null) {
                ShowWebDialog(_webPageDialogHandle, title);
            }
        } else if (msg == noock.windows.Win32Message.WM_DESTROY) {
            _webPageDialogHandle = IntPtr.Zero;
            System.Diagnostics.Debug.WriteLine(title, "showModalDialog( ) Closing:");
            if (CloseWebDialog != null) {
                CloseWebDialog(child, title);
            }
        }
    }
            }

    这样就扩展了WebBrowser的事件,可以触发showModalDialog( )弹出对话框的弹出事件。
    STEP3: 因为函数的钩子是使用API实现,是系统级的,所有必须在程序退出时释放钩子函数占用的资源

    public static bool Hooked
    {
        get { return _pWH_CALLWNDPROCRET != IntPtr.Zero; }
    }
    public static void Unhook( )
    {
        if ( ! Hooked) {
            Win32API.UnhookWindowsHookEx(_pWH_CALLWNDPROCRET);
        }
    }

    但是,还有一个问题,这样只能捕捉到showModalDialog( )弹出的对话框,而不能捕捉到showModelessDialog( )弹出的非模态对话框,因为钩子函数在上面的代码中只捕捉主线程的消息,而非模态对话框则是单独的线程。遗憾的是SetWindowsHookEx( )不支持面向进程的钩子函数,除了面向线程就是面向全局的,捕捉整个桌面(一般相当于整个用户)的所有消息,虽然这样做也可以捕捉到相应的事件,但显然效率是比较低的。而且,非模态对话框在实际应用中并不多见。

    我们还可以通过一个折衷的方法,使用API来搜索WebBrowser窗口关系树中附近的窗口,看有没有其所有者是WebBrowser父窗口的网页对话框,例如代码:
    public IntPtr WebPageDialogHandle
            {
                get
                {
                    InvokeMethod invoker = new InvokeMethod(( ) =>
                    {
                        if (_webPageDialogHandle != IntPtr.Zero && Win32API.IsWindow(_webPageDialogHandle)) {
                        } else {
                            _webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDPREV);
                            if (_webPageDialogHandle == IntPtr.Zero)
                                _webPageDialogHandle = SearchWebDialog(ParentForm.Handle, Win32API.GW_HWNDNEXT);
                        }
                    }
                    );
                    this.Invoke(invoker);
                    return _webPageDialogHandle;
                }
            }

    private IntPtr SearchWebDialog(IntPtr start, uint direction)
        {
            int processId, nextProcId;
            int threadId = Win32API.GetWindowThreadProcessId(ParentForm.Handle, out processId);
            StringBuilder sb = new StringBuilder(256);

            IntPtr nextWin = Win32API.GetNextWindow(ParentForm.Handle, direction);
            int nextTh = Win32API.GetWindowThreadProcessId(nextWin, out nextProcId);
            while (nextProcId == processId) {
                if (ParentForm.Handle == Win32API.GetParent(nextWin)) {
                    Win32API.GetClassName(nextWin, sb, sb.Capacity);
                    if (sb.ToString() == IE_WebDialogClassName) {
                        _webPageDialogHandle = Win32API.FindWindowExxx(nextWin, IntPtr.Zero, IE_ServerClassName, null);
                        return _webPageDialogHandle;
                    }
                }
                nextWin = Win32API.GetNextWindow(nextWin, direction);
                nextTh = Win32API.GetWindowThreadProcessId(nextWin, out processId);
            }
            return IntPtr.Zero;
        }

    public static IntPtr FindWindowExxx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle)
            {
                IntPtr res = FindWindowEx(parentHandle, childAfter, lclassName, windowTitle);

                if (res != IntPtr.Zero)
                    return res;
                while ( (res = FindWindowEx(parentHandle, res, null, null)) != IntPtr.Zero) {
                    IntPtr aim = FindWindowExxx(res, IntPtr.Zero, lclassName, windowTitle);
                    if (aim != IntPtr.Zero)
                        return aim;
                }
                return IntPtr.Zero;
            }
    其实窗口的句柄只是内核对象中的一个地址,同一个进程的窗口句柄一般也是连续,正如代码中所示,我们不需要搜索所有的窗口,而只需要进进程ID为边界在WebBrowser父窗口的附近搜索。非模态对话框的父窗口够本是桌面窗口,而不是WebBrowser所在的窗口,所以在SearchWebDialog函数中调用了GetParent函数,而没有使用GetAncestor,因为前者返回的不一定是父窗口,也可能是所有者,这正是非模态对话框与WebBrowser窗口的关系,浏览器窗口是模态对话框的父窗口,而只是非模态框的所有者,而不是其父窗口。
    获取非模态对话框的句柄以后,就随便你对它做什么了,发送消息模拟按键、模拟鼠标点击、关闭等,都是可以的了。

     

    补上Win32API类的部分代码

    // Delegate for a WH_ hook procedure
    public delegate Int32 HookProcedureDelegate(Int32 iCode, IntPtr pWParam, IntPtr pLParam);

    [DllImport("user32.dll")]
    public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);


    /// <summary>
    /// Retrieves the identifier of the thread that created the specified window and, optionally,
    /// the identifier of the process that created the window.
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="processId">if not null, fill the process id</param>
    /// <returns>thread id</returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetParent(IntPtr hWnd);

     

    [DllImport("user32.dll", SetLastError = true, EntryPoint="GetWindow")]
    public static extern IntPtr GetNextWindow(IntPtr hWnd, uint Command);
    ---------------------
    作者:noock
    来源:CSDN
    原文:https://blog.csdn.net/Nocky/article/details/6103875
    版权声明:本文为博主原创文章,转载请附上博文链接!

    联系客服

    010-58436659

  • 宋铖的博客—强国博客—人民网 2019-07-07
  • 科学恢复森林 广汽丰田用心守护自然家园 2019-06-10
  • 人民日报评论员:统筹推进新时代“五位一体”总体布局 2019-06-08
  • 日照世界帆船锦标赛基地 2019-05-23
  • 扬帆起航新时代 凝聚民心释放中国红利 2019-05-16
  • 全面把握网络强国战略思想的六个维度 2019-05-05
  • [微笑]那就是管理问题了,跟免不免费本身不相干! 2019-05-05
  • 阿呆,那是你家远祖啊,还不跪拜?[哈哈] 2019-04-30
  • 【互动话题】一句话形容过完年的你 2019-04-30
  • 主动扩大开放再发力 国务院出台六项举措鼓励利用外资 2019-04-20
  • 女性之声——全国妇联 2019-04-13
  • 为祝贺你们!为你们自豪,为你们骄傲——中国核电的创新者!这是“两弹一星”精神的延续,是“两弹一星”精神的发扬!有良心的中国人,更要感谢以毛泽东为首的老一辈无产阶 2019-04-10
  • 讲法治说情操 江北党员干部听“老马”宣讲“两会”精神 2019-04-10
  • 郧西男孩两条腿“长”在一起 十堰市人民医院手术整形帮他迈开双腿 2019-04-09
  • 新歌声惊现切葱歌 谢霆锋不当厨师做导师 2019-04-09
  • 14场胜平负推荐 香港六合彩护民黄图 体育彩票北京单场 吉林体彩快乐扑克 信封彩图曾道人玄机 江苏十一选五定牛走势 平特一宵期期准 市彩票中心电话 江苏11选5遗漏表 吉林快3走势图下载 甘肃快三形态走势势图一定牛 中国福彩网刮刮乐 2010英超积分榜 11选5广东下注点 少儿围棋比赛