WebBrowser弹出窗口之(三) – alert( ) / confirm( )

来源:互联网 发布:亚马逊newsql数据库 编辑:程序博客网 时间:2024/05/10 05:15

    alert/confirm等javascript函数产生的对话框是标准的windows对话框,例如

image

通过HOOK对话框的初始化消息WM_INITDIALOG,检测其标题是否为“来自网页的消息”(英文系统需要匹配项文字符串)(因为钩子是针对主线程的,不会捕获到其它进程的消息,如IE的),然后找到“确定”按钮,通过发送按钮的命令消息来模拟点击“确定”按钮,来实现自动关闭。其中,对话框中显示的消息也在一个window中,可以通过字符串匹配来找到,安装HOOK函数的方法与showModalDialog相同,只是处理的消息不同

private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode, IntPtr pWParam, IntPtr pLParam)
        {
                    if (iCode < 0)
                    return CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);

                CWPRETSTRUCT cwp = (CWPRETSTRUCT)
                    Marshal.PtrToStructure(pLParam, typeof(CWPRETSTRUCT));
                Win32Message msg = Win32Message.WM_NULL;
                try {
                    msg = (Win32Message)cwp.message;
                } catch {
                    return CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam); ;
                }

if (msg == Win32Message.WM_INITDIALOG) {    //
    // A dialog was initialized, find out what sort it was via it's Caption text
    string caption = GetWindowText(cwp.hwnd);

// 此处从配置文件中读取需要自动关闭的窗口,配置文件中一行为一项格式为
//  titile | message | button
// 先匹配title再匹配message,匹配上后查找button,然后发送消息点击按钮


const string AUTO_CLOSE_CONFIG_FILE = "autoclose.config";
                            FileInfo fi = new FileInfo(AUTO_CLOSE_CONFIG_FILE);
                            if (_autoCloseList == null && fi.Exists) {
                                try {
                                    noock.log.DefaultLogger.Logger.Info("[Auto-closing]Loading config: {0} ...", AUTO_CLOSE_CONFIG_FILE);
                                    _autoCloseList = new List();
                                    using (FileStream fs = new FileStream(fi.ToString(), FileMode.Open)) {
                                        using (StreamReader sr = new StreamReader(fs)) {
                                            string line = null;
                                            while ((line = sr.ReadLine()) != null) {
                                                if (line.Length == 0 || line[0] == '#')    // comments
                                                    continue;
                                                string[] fields = line.Split('|');
                                                if (fields.Length != 3) {
                                                    noock.log.DefaultLogger.Logger.Warning("Invalid config in file: " + fi.ToString());
                                                    continue;
                                                }
                                                _autoCloseList.Add(new AlertWindowInfo(fields[2].Trim(), fields[0].Trim(), fields[1].Trim()));
                                            }
                                        }
                                    }
                                    noock.log.DefaultLogger.Logger.Info("[Auto-closing] Loaded {0} items", _autoCloseList.Count);
                                } catch (Exception ex) {
                                    noock.log.DefaultLogger.Logger.Exception("[AutoClose]: Failed to load auto-close list: " + fi.FullName, ex);
                                }
   }
// Call the next hook in the chain
return CallNextHookEx(_pWH_CALLWNDPROCRET, iCode, pWParam, pLParam);
}

窗口匹配的函数

private static bool MatchWindowAndClickButton(IntPtr hwnd, string caption, string expectedCaption, string message, string button)
        {
            if (-1 == caption.IndexOf(expectedCaption))
                return false;
            bool contentMatched = false;
            IntPtr pButton = IntPtr.Zero;

            // Check out further properties of the dialog
            foreach (IntPtr pChildOfDialog in listChildWindows(hwnd)) {
                // Go through all of the child controls on the dialog and see what they reveal via their text
                int iLength = GetWindowTextLength(pChildOfDialog);
                if (iLength <= 0)
                    continue;

                StringBuilder sbProbe = new StringBuilder(iLength + 1);
                GetWindowText(pChildOfDialog, sbProbe, sbProbe.Capacity);
                string msg = sbProbe.ToString();
                noock.log.DefaultLogger.Logger.Info("Child window:[{0}]", msg);
                if (msg.IndexOf(message) != -1) {
                    contentMatched = true;
                    noock.log.DefaultLogger.Logger.Debug("Matched window message: [{0}]", msg);
                    continue;
                }
                if (msg.IndexOf(button) != -1) {
                    pButton = pChildOfDialog;
                    noock.log.DefaultLogger.Logger.Debug("Matched button: [{0}]", msg);
                }
            }

            if (pButton != IntPtr.Zero && contentMatched) {
                noock.log.DefaultLogger.Logger.Info("Found a window , try to close: [{0}]:{1}:{2}",caption, message,button);
                Int32 ctrlId = GetDlgCtrlID(pButton);
                //PostMessage(hwnd, WM_COMMAND, ctrlId, (int)pButton);
                //SendMessage(pButton, WM_COMMAND, ctrlId, (int)pButton);
                SendMessage(hwnd, WM_COMMAND, ctrlId, (int)pButton);
                return true;
            }
            return false;
        }

获取窗体文本的函数

public static string GetWindowText(IntPtr hwnd)
{
    Int32 iLength = GetWindowTextLength(hwnd);
    StringBuilder sb = new StringBuilder(iLength + 1);

    GetWindowText(hwnd, sb, sb.Capacity);
    return sb.ToString();
}

需要注意配置文件内容要用UTF-8格式,因为C#默认是UTF-8,否则里面出现中文的时候可能出现乱码,导致窗口匹配的时候匹配不上。
实际上这里用到的全是windows的API,与C#本身关系并不大,通过C++、C都可以实现。

原创粉丝点击