2010-06-08 12 views
5

Estoy trabajando en la automatización del explorador de Internet y parte de ello consiste en descargar archivos de un sitio alojado en asp 2.0 y usa autenticación basada en formularios, para crear fin Para finalizar la automatización utilicé la automatización del navegador.Presione el botón Guardar del "diálogo de descarga de archivos" de Internet Explorer mediante C#

Pude llegar al paso donde puedo hacer clic en una URL que trae el cuadro de diálogo "Descargar archivo" del navegador, luego estaba tratando de hacer uso de SendKeys para hacer clic en el botón Guardar, pero en vano no estaba funcionando.

Aquí está el código donde utilizo el método FindWindow para obtener el puntero hWnd del cuadro de diálogo Descarga de archivos, y luego usando setActiveWindow lo hago la ventana activa para que los comandos SendKeys funcionen en él y luego use SendKeys Probé para enviar Alt + S, pero no funcionó. Observé que, Tab, Escape and Enter funciona, pero luego el botón Enter on Save no funciona.

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

Usando el mismo código pude acceder al bloc de notas cambiando el valor en FindWindow a "Untitled - Notepad".

¿Tengo que hacer algo diferente, ya que es un diálogo y ahora una ventana? Estoy usando IE8.

Este es el código alternativo que probé después de la respuesta.

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

Para mayor claridad agrego la pantalla del diálogo.

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

+0

¿Ha escrito su propia aplicación de automatización o está usando algo como el selenio? –

+0

escribí mi propia automatización, que es bastante trivial. Básicamente toma el objeto de la aplicación IE, navega a una url. Ingresa usando DOM y luego hace clic en una URL que trae el diálogo de descarga. –

Respuesta

1

así, usted tiene que encontrar la ventana con el título de la descarga de diálogo. y de lo que tiene que encontrar la ventana con el título del botón de descarga/y luego enviar a ese mensaje ventana, haga clic

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; 
    } 

y se puede utilizar Winspector (análogo de espionaje ++). es una utilidad muy útil. Puede descubrimiento de muchas cosas acerca de las ventanas;)

+0

vea la pregunta actualizada, res regresa a 0. y en spy ++ aunque puedo ver que se está registrando un mensaje, pero no está forzando que la ventana cargue el cuadro de diálogo para guardar. –

+0

, por lo que puede intentar enviar eventos del mouse hacia abajo y hacia arriba – smash

1

intenta lo siguiente, que parecía funcionar para mí:

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

sugeriría comprobar los rendimientos de cada función sin embargo.

0
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");

Eso fue en realidad un falso positivo si no estoy equivocado; el comportamiento predeterminado aparentemente como un failsafe parece ser cerrar el cuadro de diálogo. Más bien, fue positivo que se puede hacer clic en el botón Cancelar, pero intentar hacer clic en Abrir o Guardar generará lo mismo, pero en ese contexto, respuesta no deseada ...

Parece que este es un cuadro de diálogo, solo estamos va a tener que lidiar a menos que alguien más pueda confirmar con gratitud lo contrario?

1

Encontré una manera de hacer esto con Internet Explorer 6 en Windows XP.

(Lo sentimos, el código 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 

Por favor, diga si funciona para usted.

2

Esto funciona en C++ Tenga en cuenta que el botón 'Guardar' se llama '& Guardar' no 'Guardar'

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

}

1

encontré la mayor parte de este en StackOverflow: How to handle Message Boxes while using webbrowser in C#? y he modificado por mí

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); 
} 
} 
+0

demasiado código y menos descripciones no son bienvenidos. Por favor explica la solución. Gracias – Nabin

0

Ninguno de código sugirió que trabajó, termino ed para utilizar la escritura AutoIt para cerrar un diálogo de impresión, el código de la siguiente manera:

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