按“文件下载对话框”的保存按钮通过 c# 的 Internet Explorer

发布于 2024-09-04 08:33:05 字数 1804 浏览 9 评论 0原文

我正在研究 Internet Explorer 自动化,其中一部分涉及从托管在 ASP 2.0 上并使用基于表单的身份验证的网站下载文件,因此为了创建端到端自动化,我使用了浏览器自动化。

我能够到达可以单击 URL 的步骤,该 URL 会显示浏览器的“文件下载”对话框,然后我尝试使用 SendKeys 单击“保存”按钮,但无济于事不工作。

下面是我使用 FindWindow 方法获取文件下载对话框的 hWnd 指针的代码,然后使用 setActiveWindow 将其设为活动窗口,以便 SendKeys 命令在其上工作,然后使用 SendKeys 我尝试发送 Alt +但没有成功。我观察到,Tab、Escape 和 Enter 有效,但保存按钮上的 Enter 不起作用。

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

private void Form1_Load(object sender, EventArgs e)
{
    IntPtr hwnd = FindWindow(null, "File Download");
    IntPtr nullptr = (IntPtr)0;
    if (hwnd != nullptr)
    {
        SetActiveWindow(hwnd);
        SendKeys.SendWait("%S");
    }
}

使用相同的代码,我可以通过将 FindWindow 中的值更改为“无标题 - 记事本”来访问记事本。

我是否需要做一些不同的事情,因为它是一个对话框,现在是一个窗口?我用的是IE8。

这是我在回答后尝试的替代代码。

IntPtr hwnd = FindWindow(null, "File Download");
            IntPtr hokBtn = IntPtr.Zero;
            hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
            hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
            uint id = GetDlgCtrlID(hokBtn);
            SetActiveWindow(hwnd);
            IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
            if (res.ToInt32() == 1)
                MessageBox.Show("success");

为了清楚起见,我添加了对话框的屏幕。

替代文本 http://www.freeimagehosting.net/uploads/4f23586401。 .png

I am working on internet explorer automation and part of it involves downloading files from a site whcih is hosted on asp 2.0 and uses forms based authentication, so to create end to end automation I used browser automation.

I was able to reach to the step where I can get to click on a URL which brings the "File Download" dialog of the browser, then I was trying to make use of SendKeys to click on the save button but to no avail it was not working.

Here is the code where I make use of FindWindow method to get the hWnd pointer of the File Download Dialog, and then using setActiveWindow I make it the active window so that the SendKeys commands works on it and then using SendKeys I tried to send Alt + S but it didn't work. I observed that, Tab, Escape and Enter works, but then Enter on Save button doesn't work.

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

private void Form1_Load(object sender, EventArgs e)
{
    IntPtr hwnd = FindWindow(null, "File Download");
    IntPtr nullptr = (IntPtr)0;
    if (hwnd != nullptr)
    {
        SetActiveWindow(hwnd);
        SendKeys.SendWait("%S");
    }
}

Using the same code I was able to access notepad by changing the value in FindWindow to "Untitled - Notepad".

Do I need to do something different as it is a dialog and now a window? I am using IE8.

This is the alternate code I tried after the answer.

IntPtr hwnd = FindWindow(null, "File Download");
            IntPtr hokBtn = IntPtr.Zero;
            hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
            hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
            uint id = GetDlgCtrlID(hokBtn);
            SetActiveWindow(hwnd);
            IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
            if (res.ToInt32() == 1)
                MessageBox.Show("success");

For clarity I am adding the screen of the dialog.

alt text http://www.freeimagehosting.net/uploads/4f23586401.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

虚拟世界 2024-09-11 08:33:05

尝试以下似乎对我有用的方法:

IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
    MessageBox.Show("success");

不过,我建议您检查每个函数的返回值。

Try the following which seemed to work for me:

IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
    MessageBox.Show("success");

I would suggest you check the returns from each function though.

不甘平庸 2024-09-11 08:33:05

这在 C++ 中有效
请注意,“保存”按钮名为“&Save”而不是“Save”

CString Title;
    Title=_T("File Download");
    HWND FEX =  ::FindWindowEx( NULL,NULL,NULL,Title);
    if (FEX != NULL)
    {

        //press the Save button on the dialog.
        HWND hokBtn = ::FindWindowEx(FEX, NULL, L"Button", L"&Save");
        if (hokBtn != NULL)
        {

            UINT id = ::GetDlgCtrlID(hokBtn);
            ::SetActiveWindow(hokBtn);
            ::PostMessage(hokBtn, WM_KEYDOWN, 0x20, 0);
            ::PostMessage(hokBtn, WM_KEYUP, 0x20, 0);
        }

}

This works in C++
Note that the 'Save' button is named '&Save' not 'Save'

CString Title;
    Title=_T("File Download");
    HWND FEX =  ::FindWindowEx( NULL,NULL,NULL,Title);
    if (FEX != NULL)
    {

        //press the Save button on the dialog.
        HWND hokBtn = ::FindWindowEx(FEX, NULL, L"Button", L"&Save");
        if (hokBtn != NULL)
        {

            UINT id = ::GetDlgCtrlID(hokBtn);
            ::SetActiveWindow(hokBtn);
            ::PostMessage(hokBtn, WM_KEYDOWN, 0x20, 0);
            ::PostMessage(hokBtn, WM_KEYUP, 0x20, 0);
        }

}

箜明 2024-09-11 08:33:05

好吧,你必须找到带有下载对话框标题的窗口。然后您必须找到标题为下载按钮/的窗口,然后向该窗口发送单击消息

  BM_CLICK = 0x00F5

  [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);

  [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 = User32.FindWindowEx(hDialog, hOkBtn, "Button", IntPtr.Zero);
            id = User32.GetDlgCtrlID(hOkBtn);
            attempt++;
        } while (id != idBtn && attempt < 20);
        if (!hOkBtn.Equals(IntPtr.Zero))
        {
            //click the button
            res = User32.SendMessage(hOkBtn, (int)WindowsMessages.BM_CLICK, 1,  IntPtr.Zero);
        }
        if (res.ToInt32() == 1)
            return true;
        return false;
    }

,您就可以使用 winspector (spy++ 的类似物)。这是非常有用的实用程序。你可以发现很多关于windows的东西;)

well, you have to find window with title of downloading dialog. and than you have to find window with title of download button/ and then send to that window click message

  BM_CLICK = 0x00F5

  [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);

  [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 = User32.FindWindowEx(hDialog, hOkBtn, "Button", IntPtr.Zero);
            id = User32.GetDlgCtrlID(hOkBtn);
            attempt++;
        } while (id != idBtn && attempt < 20);
        if (!hOkBtn.Equals(IntPtr.Zero))
        {
            //click the button
            res = User32.SendMessage(hOkBtn, (int)WindowsMessages.BM_CLICK, 1,  IntPtr.Zero);
        }
        if (res.ToInt32() == 1)
            return true;
        return false;
    }

and you can use winspector (analog of spy++). it's very useful utility. You can discovery many things about windows;)

暗恋未遂 2024-09-11 08:33:05

我找到了一种在 Windows XP 中使用 Internet Explorer 6 执行此操作的方法。

(抱歉,VBA 代码)

'ButtonHwnd is the pointer to the Save button
Private Declare Function SetCursorPos Lib "user32" (ByVal X As Integer, ByVal Y As Integer) As Long
Private Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Private Const MOUSEEVENTF_LEFTDOWN As Long = &H2
Private Const MOUSEEVENTF_LEFTUP As Long = &H4
Dim pos As RECT
' We get the button position
GetWindowRect ButtonHwnd, pos

' We simulate an entering of the cursor in the button. IE think this is a human :-).
' We need three steps: out, entering and in.
' Out
SetCursorPos (pos.Left - 10), (pos.Top - 10)
Sleep 100
' Entering
SetCursorPos pos.Left, pos.Top
Sleep 100
' In
SetCursorPos (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2

' We do clic with the left button. You can use SendInput instead
' With 400 miliseconds it works.
mouse_event MOUSEEVENTF_LEFTDOWN, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0
Sleep 400
mouse_event MOUSEEVENTF_LEFTUP, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0

请告知它是否适合您。

I found a way to do this with Internet Explorer 6 in Windows XP.

(Sorry, VBA code)

'ButtonHwnd is the pointer to the Save button
Private Declare Function SetCursorPos Lib "user32" (ByVal X As Integer, ByVal Y As Integer) As Long
Private Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Private Const MOUSEEVENTF_LEFTDOWN As Long = &H2
Private Const MOUSEEVENTF_LEFTUP As Long = &H4
Dim pos As RECT
' We get the button position
GetWindowRect ButtonHwnd, pos

' We simulate an entering of the cursor in the button. IE think this is a human :-).
' We need three steps: out, entering and in.
' Out
SetCursorPos (pos.Left - 10), (pos.Top - 10)
Sleep 100
' Entering
SetCursorPos pos.Left, pos.Top
Sleep 100
' In
SetCursorPos (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2

' We do clic with the left button. You can use SendInput instead
' With 400 miliseconds it works.
mouse_event MOUSEEVENTF_LEFTDOWN, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0
Sleep 400
mouse_event MOUSEEVENTF_LEFTUP, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0

Please, tell if it works for you.

酒与心事 2024-09-11 08:33:05

我在 StackOverflow 上找到了大部分内容: 如何处理消息在 C# 中使用网络浏览器时出现框?
我为我修改了它

using System.Runtime.InteropServices; //for the dll import (to press a key)

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

private async void downloadstuff()
{
await Task.Delay(40000);  //i need this delay, but you might not :)
{
    IntPtr hwnd = FindWindow("#32770", "File Download");  //this is the window it finds
    hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "&Save");  //this is the button to pres
    uint message = 0xf5;
    SendMessage(hwnd, message, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000);
{
    IntPtr hwnd2 = FindWindow("#32770", "Save As");
    hwnd2 = FindWindowEx(hwnd2, IntPtr.Zero, "Button", "&Save");
    uint message2 = 0xf5;
    SendMessage(hwnd2, message2, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000);                //i press it anyway, just in case :)
{   //this is the download complete box (if its checked it doesn't show up)
    IntPtr hwnd3 = FindWindow("#32770", "Download complete");
    hwnd3 = FindWindowEx(hwnd3, IntPtr.Zero, "Button", "Close");
    uint message3 = 0xf5;
    SendMessage(hwnd3, message3, IntPtr.Zero, IntPtr.Zero);
}
}

I found most of this on StackOverflow: How to handle Message Boxes while using webbrowser in C#?
and i modified it for me

using System.Runtime.InteropServices; //for the dll import (to press a key)

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

private async void downloadstuff()
{
await Task.Delay(40000);  //i need this delay, but you might not :)
{
    IntPtr hwnd = FindWindow("#32770", "File Download");  //this is the window it finds
    hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "&Save");  //this is the button to pres
    uint message = 0xf5;
    SendMessage(hwnd, message, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000);
{
    IntPtr hwnd2 = FindWindow("#32770", "Save As");
    hwnd2 = FindWindowEx(hwnd2, IntPtr.Zero, "Button", "&Save");
    uint message2 = 0xf5;
    SendMessage(hwnd2, message2, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000);                //i press it anyway, just in case :)
{   //this is the download complete box (if its checked it doesn't show up)
    IntPtr hwnd3 = FindWindow("#32770", "Download complete");
    hwnd3 = FindWindowEx(hwnd3, IntPtr.Zero, "Button", "Close");
    uint message3 = 0xf5;
    SendMessage(hwnd3, message3, IntPtr.Zero, IntPtr.Zero);
}
}
半仙 2024-09-11 08:33:05
IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
    MessageBox.Show("success");

如果我没记错的话,这实际上是一个误报。看似故障保护的默认行为似乎是关闭对话框。相反,可以单击“取消”按钮是一个积极的结果,但尝试单击“打开”或“保存”将在该上下文中生成相同的不需要的响应...

似乎这是一个我们必须要打开的对话框除非其他人可以感激地确认否则如何处理?

IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
    MessageBox.Show("success");

That was actually a false positive if I'm not wrong; the default behaviour seemingly as a failsafe appears to be to close the dialog box. Rather, it was a positive that the cancel button can be clicked, but attempting to click Open or Save will generate the same yet in that context unwanted response...

It seems that this is a dialog box we're just going to have to deal with unless someone else could gratefully confirm otherwise?

软甜啾 2024-09-11 08:33:05

建议的代码都不起作用,我最终使用 AutoIt 脚本关闭打印对话框,代码如下:

Local $hWnd = WinWait("[CLASS:#32770]", "Print", 20)
WinActivate($hWnd)
WinWaitActive("[CLASS:#32770]", "Print", 10)
Sleep(100)
Send("{ENTER}")

None of the code suggested worked, I ended up to use AutoIt script to close a Print Dialog, the code follows:

Local $hWnd = WinWait("[CLASS:#32770]", "Print", 20)
WinActivate($hWnd)
WinWaitActive("[CLASS:#32770]", "Print", 10)
Sleep(100)
Send("{ENTER}")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文