使用 C# 在 IE 11 中自动下载文件
Automate of file download in IE 11 using c#
我正在尝试获取 window 处理程序并按下“保存”按钮。我在 IE8 和 9 上找到了几个示例。但是该代码在 IE 11 上不起作用。
const int BM_CLICK = 0x00F5;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern uint GetDlgCtrlID(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
//hDialog - handle of dialog window. idBtn - Id of button
public static bool ClickButtonOnDialog(IntPtr hDialog, UInt32 idBtn)
{
IntPtr res = IntPtr.Zero;
uint id;
IntPtr hOkBtn = IntPtr.Zero;
int attempt = 0;
do
{
Thread.Sleep(300);
//searching for button
hOkBtn = FindWindowEx(hDialog, hOkBtn, "Button", IntPtr.Zero);
id = GetDlgCtrlID(hOkBtn);
attempt++;
} while (id != idBtn && attempt < 20);
if (!hOkBtn.Equals(IntPtr.Zero))
{
//click the button
res = SendMessage(hOkBtn, (int)BM_CLICK, 1, IntPtr.Zero);
}
if (res.ToInt32() == 1)
return true;
return false;
}
public static void FindAndSave()
{
IntPtr hOkBtn = IntPtr.Zero;
uint message = 0xf5;
IntPtr hwnd = FindWindow(null, "Internet Explorer");
hOkBtn = FindWindowEx(hwnd, hOkBtn, "Button", "Cancel");
SendMessage(hOkBtn, (int)message, 1, IntPtr.Zero);
我可以使用下面的代码下载并关闭文件下载对话框
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void DownLoadFile(IE browser)
{
browser.Link(Find.ByText("download")).ClickNoWait();
Thread.Sleep(1000);
AutomationElementCollection dialogElements = AutomationElement.FromHandle(FindWindow(null, "Internet Explorer")).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement element in dialogElements)
{
if (element.Current.Name.Equals("Save"))
{
var invokePattern = element.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
invokePattern.Invoke();
}
}
}
我的做法:
使用 windows API 调用通过 window 标题识别 window。
[DllImport("user32.dll"]
static extern IntPtr FindWindowByCaption
遍历 IE window,直到我们找到带有 "Frame Notification Bar or "通知栏的元素作为 Window Class 名称
找到名为 "Open" 或 "Save" 的按钮并执行点击。
public void DownLoadFile(string strWindowTitle)
{
IntPtr TargetHandle = FindWindowByCaption(IntPtr.Zero, strWindowTitle);
AutomationElementCollection ParentElements = AutomationElement.FromHandle(TargetHandle).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ParentElement in ParentElements)
{
// Identidfy Download Manager Window in Internet Explorer
if (ParentElement.Current.ClassName == "Frame Notification Bar")
{
AutomationElementCollection ChildElements = ParentElement.FindAll(TreeScope.Children, Condition.TrueCondition);
// Idenfify child window with the name Notification Bar or class name as DirectUIHWND
foreach (AutomationElement ChildElement in ChildElements)
{
if (ChildElement.Current.Name == "Notification bar" || ChildElement.Current.ClassName == "DirectUIHWND")
{
AutomationElementCollection DownloadCtrls = ChildElement.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ctrlButton in DownloadCtrls)
{
//Now invoke the button click whichever you wish
if (ctrlButton.Current.Name.ToLower() == "save")
{
var invokePattern = ctrlButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
invokePattern.Invoke();
}
}
}
}
}
}
}
这是有效的 IE 11 代码。它是 System.Windows.Automation 和 Win32 API 的混合体。可能让它与 Win32 非托管 API 一起工作。我使用 WinID 获取菜单的 class 名称,然后遍历其子元素。
IE 11有这个下载框。
我们需要从“保存”的向下箭头访问“另存为”。
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string className, string windowTitle);
public static void IeDownLoadSaveAs(string windowTitle = null)
{
if (windowTitle == null)
windowTitle = "https://googledownload.com - Internet Explorer";
//get the message handle
//the last param "Untitled...is the title of the window and it must match
IntPtr parentHandle = WindowHandleInfo.FindWindow("IEFrame", windowTitle);
var parentElements = AutomationElement.FromHandle(parentHandle).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement parentElement in parentElements)
{
// Identidfy Download Manager Window in Internet Explorer
if (parentElement.Current.ClassName == "Frame Notification Bar")
{
var childElements = parentElement.FindAll(TreeScope.Children, Condition.TrueCondition);
// Idenfify child window with the name Notification Bar or class name as DirectUIHWND
foreach (AutomationElement childElement in childElements)
{
if (childElement.Current.Name == "Notification bar" || childElement.Current.ClassName == "DirectUIHWND")
{
var downloadCtrls = childElement.FindAll(TreeScope.Descendants, Condition.TrueCondition);
foreach (AutomationElement ctrlButton in downloadCtrls)
{
//Now invoke the button click whichever you wish
if (ctrlButton.Current.Name.ToLower() == "")
{
var saveSubMenu = ctrlButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
saveSubMenu.Invoke();
var saveMenuHandle = WindowHandleInfo.FindWindow("#32768", "");
var subMenuItems = AutomationElement.FromHandle(saveMenuHandle).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement item in subMenuItems)
{
if (item.Current.Name.ToLower() == "save as")
{
var saveAsMenuItem = item.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
saveAsMenuItem.Invoke();
}
}
}
}
}
}
}
}
}
我用很简单的方法实现了。只需使用击键即可。
SendKeys.SendWait("%");
SendKeys.SendWait("%{s}");
希望这会节省您的大量时间。
我有两个 IE 进程 运行 - 上面的代码总是选择错误的 32 位 IE 进程。因此,我合并了多个 Whosebug 问题的答案并编写了以下代码来完成此操作(不导入 dll)。
请注意,您需要在项目中添加对 UIAutomationClient 的引用 - 才能使用 AutomationElement 方法。
public static void IESaveFile(string title)
{
Thread.Sleep(1000);
//Get the Internet Explorer window handle using the window title
var ieWindowHandle = Process.GetProcesses().FirstOrDefault(process => process.MainWindowTitle.Contains(title))?.MainWindowHandle;
var dialogElements = AutomationElement.FromHandle(ieWindowHandle??IntPtr.Zero).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement element in dialogElements)
{
if (element.Current.ClassName != "Frame Notification Bar") continue;
var ChildElements = element.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ChildElement in ChildElements)
{
// Identify child window with the name Notification Bar or class name DirectUIHWND
if (ChildElement.Current.Name != "Notification bar" && ChildElement.Current.ClassName != "DirectUIHWND") continue;
var DownloadCtrls = ChildElement.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ctrlButton in DownloadCtrls)
//Now invoke the button click on the 'Save' button
if (ctrlButton.Current.Name.ToLower().Equals("save"))
((InvokePattern) ctrlButton.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
}
}
}
我正在尝试获取 window 处理程序并按下“保存”按钮。我在 IE8 和 9 上找到了几个示例。但是该代码在 IE 11 上不起作用。
const int BM_CLICK = 0x00F5;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern uint GetDlgCtrlID(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
//hDialog - handle of dialog window. idBtn - Id of button
public static bool ClickButtonOnDialog(IntPtr hDialog, UInt32 idBtn)
{
IntPtr res = IntPtr.Zero;
uint id;
IntPtr hOkBtn = IntPtr.Zero;
int attempt = 0;
do
{
Thread.Sleep(300);
//searching for button
hOkBtn = FindWindowEx(hDialog, hOkBtn, "Button", IntPtr.Zero);
id = GetDlgCtrlID(hOkBtn);
attempt++;
} while (id != idBtn && attempt < 20);
if (!hOkBtn.Equals(IntPtr.Zero))
{
//click the button
res = SendMessage(hOkBtn, (int)BM_CLICK, 1, IntPtr.Zero);
}
if (res.ToInt32() == 1)
return true;
return false;
}
public static void FindAndSave()
{
IntPtr hOkBtn = IntPtr.Zero;
uint message = 0xf5;
IntPtr hwnd = FindWindow(null, "Internet Explorer");
hOkBtn = FindWindowEx(hwnd, hOkBtn, "Button", "Cancel");
SendMessage(hOkBtn, (int)message, 1, IntPtr.Zero);
我可以使用下面的代码下载并关闭文件下载对话框
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void DownLoadFile(IE browser)
{
browser.Link(Find.ByText("download")).ClickNoWait();
Thread.Sleep(1000);
AutomationElementCollection dialogElements = AutomationElement.FromHandle(FindWindow(null, "Internet Explorer")).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement element in dialogElements)
{
if (element.Current.Name.Equals("Save"))
{
var invokePattern = element.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
invokePattern.Invoke();
}
}
}
我的做法:
使用 windows API 调用通过 window 标题识别 window。
[DllImport("user32.dll"] static extern IntPtr FindWindowByCaption
遍历 IE window,直到我们找到带有 "Frame Notification Bar or "通知栏的元素作为 Window Class 名称
找到名为 "Open" 或 "Save" 的按钮并执行点击。
public void DownLoadFile(string strWindowTitle) { IntPtr TargetHandle = FindWindowByCaption(IntPtr.Zero, strWindowTitle); AutomationElementCollection ParentElements = AutomationElement.FromHandle(TargetHandle).FindAll(TreeScope.Children, Condition.TrueCondition); foreach (AutomationElement ParentElement in ParentElements) { // Identidfy Download Manager Window in Internet Explorer if (ParentElement.Current.ClassName == "Frame Notification Bar") { AutomationElementCollection ChildElements = ParentElement.FindAll(TreeScope.Children, Condition.TrueCondition); // Idenfify child window with the name Notification Bar or class name as DirectUIHWND foreach (AutomationElement ChildElement in ChildElements) { if (ChildElement.Current.Name == "Notification bar" || ChildElement.Current.ClassName == "DirectUIHWND") { AutomationElementCollection DownloadCtrls = ChildElement.FindAll(TreeScope.Children, Condition.TrueCondition); foreach (AutomationElement ctrlButton in DownloadCtrls) { //Now invoke the button click whichever you wish if (ctrlButton.Current.Name.ToLower() == "save") { var invokePattern = ctrlButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; invokePattern.Invoke(); } } } } } } }
这是有效的 IE 11 代码。它是 System.Windows.Automation 和 Win32 API 的混合体。可能让它与 Win32 非托管 API 一起工作。我使用 WinID 获取菜单的 class 名称,然后遍历其子元素。
IE 11有这个下载框。
我们需要从“保存”的向下箭头访问“另存为”。
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string className, string windowTitle);
public static void IeDownLoadSaveAs(string windowTitle = null)
{
if (windowTitle == null)
windowTitle = "https://googledownload.com - Internet Explorer";
//get the message handle
//the last param "Untitled...is the title of the window and it must match
IntPtr parentHandle = WindowHandleInfo.FindWindow("IEFrame", windowTitle);
var parentElements = AutomationElement.FromHandle(parentHandle).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement parentElement in parentElements)
{
// Identidfy Download Manager Window in Internet Explorer
if (parentElement.Current.ClassName == "Frame Notification Bar")
{
var childElements = parentElement.FindAll(TreeScope.Children, Condition.TrueCondition);
// Idenfify child window with the name Notification Bar or class name as DirectUIHWND
foreach (AutomationElement childElement in childElements)
{
if (childElement.Current.Name == "Notification bar" || childElement.Current.ClassName == "DirectUIHWND")
{
var downloadCtrls = childElement.FindAll(TreeScope.Descendants, Condition.TrueCondition);
foreach (AutomationElement ctrlButton in downloadCtrls)
{
//Now invoke the button click whichever you wish
if (ctrlButton.Current.Name.ToLower() == "")
{
var saveSubMenu = ctrlButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
saveSubMenu.Invoke();
var saveMenuHandle = WindowHandleInfo.FindWindow("#32768", "");
var subMenuItems = AutomationElement.FromHandle(saveMenuHandle).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement item in subMenuItems)
{
if (item.Current.Name.ToLower() == "save as")
{
var saveAsMenuItem = item.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
saveAsMenuItem.Invoke();
}
}
}
}
}
}
}
}
}
我用很简单的方法实现了。只需使用击键即可。
SendKeys.SendWait("%");
SendKeys.SendWait("%{s}");
希望这会节省您的大量时间。
我有两个 IE 进程 运行 - 上面的代码总是选择错误的 32 位 IE 进程。因此,我合并了多个 Whosebug 问题的答案并编写了以下代码来完成此操作(不导入 dll)。
请注意,您需要在项目中添加对 UIAutomationClient 的引用 - 才能使用 AutomationElement 方法。
public static void IESaveFile(string title)
{
Thread.Sleep(1000);
//Get the Internet Explorer window handle using the window title
var ieWindowHandle = Process.GetProcesses().FirstOrDefault(process => process.MainWindowTitle.Contains(title))?.MainWindowHandle;
var dialogElements = AutomationElement.FromHandle(ieWindowHandle??IntPtr.Zero).FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement element in dialogElements)
{
if (element.Current.ClassName != "Frame Notification Bar") continue;
var ChildElements = element.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ChildElement in ChildElements)
{
// Identify child window with the name Notification Bar or class name DirectUIHWND
if (ChildElement.Current.Name != "Notification bar" && ChildElement.Current.ClassName != "DirectUIHWND") continue;
var DownloadCtrls = ChildElement.FindAll(TreeScope.Children, Condition.TrueCondition);
foreach (AutomationElement ctrlButton in DownloadCtrls)
//Now invoke the button click on the 'Save' button
if (ctrlButton.Current.Name.ToLower().Equals("save"))
((InvokePattern) ctrlButton.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
}
}
}