使用User32.dll SendMessage来处理下载弹出窗口

时间:2015-06-24 15:59:22

标签: c# dll watin

我正在使用WatiN浏览webapp,我需要下载文档。但是,我发现WatiN不支持使用Internet Explorer 11进行下载。这就是我尝试使用此处描述的方法进行下载的原因:

How to enable automatic downloads in IE11(最佳答案) Using User32.dll SendMessage To Send Keys With ALT Modifier

基本上我正在调用user32.dll来处理小弹出DL窗口(F6选择它,选项卡,输入等)

然而没有任何反应,弹出窗口没有响应我的命令。 这是正确的方法吗?

我的代码如下所示:

//Before my method
[DllImport("user32.dll")]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

private void button1_Click(object sender, EventArgs e)
        {
            //some code....
            IE myPopup = IE.AttachTo<IE>(Find.ByUrl("http://abcd.do"));
            FileDownloadHandler fileDownloadHandler = new FileDownloadHandler("test");
            myPopup.AddDialogHandler(fileDownloadHandler);
            myPopup.Link(Find.ByUrl("httpabcdefg.do")).ClickNoWait();

            ushort action = (ushort)260; //WM_SYSKEYDOWN
            System.Threading.Thread.Sleep(2000);

            ushort key = (ushort)System.Windows.Forms.Keys.F6;
            ushort key2 = (ushort)System.Windows.Forms.Keys.Tab;
            ushort key3 = (ushort)System.Windows.Forms.Keys.Enter;
            ushort key4 = (ushort)System.Windows.Forms.Keys.Right;

            SendMessage(myPopup.hWnd, action, key, 0);
            SendMessage(myPopup.hWnd, action, key2, 0);
            SendMessage(myPopup.hWnd, action, key3, 0);
            SendMessage(myPopup.hWnd, action, key4, 0);
            SendMessage(myPopup.hWnd, action, key4, 0);
            SendMessage(myPopup.hWnd, action, key3, 0);
        }

我知道弹出窗口(myPopup)处理正确,我可以使用watin点击它。

有些事情我不清楚,我把动作WM_SYSKEYDOWN作为默认值,遵循上面引用的例子。

提前感谢您的任何帮助!

--------------的修改 -----------------

我设法做到了,我知道它根本不是最佳的,但我将DllimportSendMessage全部放在一起,而是使用了SendKeys.Send。就像那样:

private void button1_Click(object sender, EventArgs e)
            {
                //some code....
                IE myPopup = IE.AttachTo<IE>(Find.ByUrl("http://abcd.do"));
                FileDownloadHandler fileDownloadHandler = new FileDownloadHandler("test");
                myPopup.AddDialogHandler(fileDownloadHandler);
                myPopup.Link(Find.ByUrl("httpabcdefg.do")).ClickNoWait();

                SendKeys.Send("{F6}");
                SendKeys.Send("{ENTER}");
                SendKeys.Send("{RIGHT}");
                SendKeys.Send("{RIGHT}");
                SendKeys.Send("{ENTER}");
            }

1 个答案:

答案 0 :(得分:0)

您使用的代码不是自动化的正确方法,WatiN不能与Windows控件完全交互,Windows中的帮助很少。我在处理Windows控件时遇到了同样的问题,因为我们有多个版本的IE。与&lt; = IE 8.0版本相比,IE 9.0及更高版本具有不同的文件处理能力。以下代码适用于IE 9.0及更高版本。请确保添加适当的引用(请参阅使用&#39;)。

请参阅以下代码并根据您的要求进行修改。

using System.Threading;
using System.Windows.Automation;
using WatiN.Core;
using WatiN.Core.Native.Windows;

namespace TestFramework.Util
{
 public static class WindowsHelper
 {
#region Public Methods

/// <summary>
/// Download IE file.
/// </summary>        
/// <param name="action">Action can be Save/Save As/Open/Cancel.</param>
/// <param name="path">Path where file needs to be saved (for Save As function).</param>
public static void DownloadIEFile(string action, string path = "", string regexPatternToMatch = "")
{
    Browser browser = null;
    if (Utility.Browser != null) // Utility.Browser is my WatiN browser instance.
    {
        if (string.IsNullOrEmpty(regexPatternToMatch))
        {
            browser = Utility.Browser;
        }
        else
        {
            Utility.Wait(() => (browser = Browser.AttachTo<IE>(Find.ByUrl(new System.Text.RegularExpressions.Regex(regexPatternToMatch)))) != null);
        }
    }
    else
    {                
        return;
    }

    // If doesn't work try to increase sleep interval or write your own waitUntill method
    Thread.Sleep(3000);
    // See information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
    Window windowMain = null;
    Utility.Wait(() => (windowMain = new Window(NativeMethods.GetWindow(browser.hWnd, 5))).ProcessID != 0);

    TreeWalker trw = new TreeWalker(Condition.TrueCondition);
    AutomationElement mainWindow = trw.GetParent(AutomationElement.FromHandle(browser.hWnd));

    Window windowDialog = null;
    Utility.Wait(() => (windowDialog = new Window(NativeMethods.GetWindow(windowMain.Hwnd, 5))).ProcessID != 0);

    windowDialog.SetActivate();
    AutomationElementCollection amc = null;
    Utility.Wait(() => (amc = AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(TreeScope.Children, Condition.TrueCondition)).Count > 1);

    foreach (AutomationElement element in amc)
    {
        // You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
        if (element.Current.Name.Equals(action))
        {
            // If doesn't work try to increase sleep interval or write your own waitUntil method
            // WaitUntilButtonExsist(element,100);
            Thread.Sleep(1000);
            AutomationPattern[] pats = element.GetSupportedPatterns();

            // Replace this for each if you need 'Save as' with code bellow
            foreach (AutomationPattern pat in pats)
            {
                // '10000' button click event id 
                if (pat.Id == 10000)
                {
                    InvokePattern click = (InvokePattern)element.GetCurrentPattern(pat);
                    click.Invoke();
                }
            }
        }
        else if (element.Current.Name.Equals("Save") && action == "Save As")
        {
            AutomationElementCollection bmc = element.FindAll(TreeScope.Children, Automation.ControlViewCondition);
            InvokePattern click1 = (InvokePattern)bmc[0].GetCurrentPattern(AutomationPattern.LookupById(10000));
            click1.Invoke();
            Thread.Sleep(1000);

            AutomationElementCollection main = mainWindow.FindAll(TreeScope.Children, Condition.TrueCondition);
            foreach (AutomationElement el in main)
            {
                if (el.Current.LocalizedControlType == "menu")
                {
                    // First array element 'Save', second array element 'Save as', third second array element   'Save and open'
                    InvokePattern clickMenu = (InvokePattern)
                                el.FindAll(TreeScope.Children, Condition.TrueCondition)[1].GetCurrentPattern(AutomationPattern.LookupById(10000));
                    clickMenu.Invoke();
                    Thread.Sleep(1000);

                    ControlSaveDialog(mainWindow, path);

                    break;
                }
            }
        }
    }
}


/// <summary>
/// Control for save dialog.
/// </summary>
/// <param name="mainWindow">Main window.</param>
/// <param name="path">Path.</param>
private static void ControlSaveDialog(AutomationElement mainWindow, string path)
{
    // Obtain the save as dialog
    var saveAsDialog = mainWindow
                        .FindFirst(TreeScope.Descendants,
                                   new PropertyCondition(AutomationElement.NameProperty, "Save As"));
    // Get the file name box
    var saveAsText = saveAsDialog
            .FindFirst(TreeScope.Descendants,
                       new AndCondition(
                           new PropertyCondition(AutomationElement.NameProperty, "File name:"),
                           new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
            .GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;

    // Fill the filename box 
    saveAsText.SetValue(path);
    Thread.Sleep(500);
    Utility.PressKey("LEFT");
    Utility.PressKey("LEFT");
    Thread.Sleep(1000);

    // Find the save button
    var saveButton =
            saveAsDialog.FindFirst(TreeScope.Descendants,
            new AndCondition(
                new PropertyCondition(AutomationElement.NameProperty, "Save"),
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));

    // Invoke the button
    var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
    pattern.Invoke();
}

#endregion
 }
}


public static class Utility
{       
    public static IE Browser { get; set; }

   // Wait specified number of seconds
   public static void Wait(int seconds)
   {
    System.Threading.Thread.Sleep(seconds * 1000);
   }

  // Wait for condition to evaluate true, timeout after 30 seconds
  public static void Wait(Func<bool> condition)
  {
    int count = 0;

    while (!condition() && count < 30)
    {
        System.Threading.Thread.Sleep(1000);
        count++;
    }
  }

  //Send tab key press to browser
  public static void PressTab()
  {
      System.Windows.Forms.SendKeys.SendWait("{TAB}");
      System.Threading.Thread.Sleep(300);
  }

  //Send specified key press to browser
  public static void PressKey(string keyname)
  {
      System.Windows.Forms.SendKeys.SendWait("{" + keyname.ToUpper() + "}");
      System.Threading.Thread.Sleep(300);
  }
}