Страницы: 1
RSS
Диалоговое окно загрузки файла блокирует выполнение кода vba.
 
Хочу на почту @yandex.ru через vba загрузить .pdf файл, нажимаю "Обзор" -> появляется диалоговое окно выбора файла и код vba перестает выполняться, потому что программа ждет ответа пользователя, когда я сам вручную выберу файл для загрузки. А я хочу через vba в диалоговом окне выбора файла (отловив окно через hwnd)написать имя файла(скорее полный путь+имя файла) и нажать кнопку открыть. Но не знаю как(написать имя файла для загрузки и нажать на кнопку открыть).  
Код
Sub Загрузить_документ()

   Dim i, i1, j, k
 Dim Shell As Object
   Dim Wins As Object
   Dim WinItem As Variant
   Dim objCollection As Object
   Dim cnt
   Dim Doc As Object 'InternetExplorer
  

  SiteURL = "https://mail.yandex.ru/?uid=23207361&login=<мой логин>#compose"
   Set Shell = CreateObject("shell.application")  

   cnt = 0
   For Each WinItem In Shell.Windows
      If WinItem.LocationURL Like Left(SiteURL, 30) & "*" Then        
        Set Doc = Shell.Windows(cnt).document
        Exit For
      End If
          cnt = cnt + 1
  Next
  
 
For i = 0 To Doc.getelementsbytagname("label").Length - 1
If Doc.getelementsbytagname("label")(i).Title = "Прикрепить файлы с компьютера" Then
    Doc.getelementsbytagname("label")(i).Click  'после клика появляется диалоговое окно выбора файла
    SendKeys "проверяю пишется ли у меня название файла", True  ' не пишется, диалоговое окно выбора файла заблокировало выполнение кода, пока я ручками не выберу файл
    SendKeys "{ENTER}", True
    
' также естественно макрос не доходит до строк ниже

 hwnd = poiskokna("Выбор выкладываемого файла") 
    Do While (hwnd = 0 And countIter < 60)
        hwnd = poiskokna("Выбор выкладываемого файла")       
        countIter = countIter + 1
    Loop

    MsgBox "все ок"
End If
Next i

End Sub

' ниже подфункция поиска окна по названию окна
Public Function poiskokna(TitleFind As String) As Long
    Dim winTitle As String * 256, cnt As Long, hwnd As Long
    Const GW_HWNDNEXT = 2
    Const GW_CHILD = 5
        hwnd = GetDesktopWindow&
        hwnd = GetWindow(hwnd, GW_CHILD)
        Do While hwnd <> 0
            cnt = GetWindowText(hwnd, winTitle, 255)
            If InStr(1, winTitle, TitleFind) > 0 Then
                poiskokna = hwnd
                Exit Do
            End If
            hwnd = GetWindow(hwnd, GW_HWNDNEXT)
        Loop
End Function
Итак 2 вопроса:
1) как сделать, чтоб не прерывалось выполнение кода макроса при появлении диалогового окна выбора файла
2) когда я определю окно через hwnd, можно ли будет написать полный путь & имя файла не через sendkeys а как-нибудь по другому? (и потом нажать энтер тоже не через sendkeys?)
Помогите, пожалуйста!
Изменено: Ves - 25.03.2017 20:49:24
 
Цитата
Ves написал: в диалоговом окне выбора файла (отловив окно через hwnd)написать имя файла(скорее полный путь+имя файла) и нажать кнопку открыть
зачем диалоговое окно? - чтобы потом что-то отлавливать?... там же ловить нечего, кроме того, что выберите сами?  8)
с окном делаю так
Код
Sub save_me_first()
' - сохранить под прежним именем.....
With Application:  .EnableEvents = False: .DisplayAlerts = False: End With
filename = Application.GetSaveAsFilename( _
                 ThisWorkbook.FullName, _
                 "Книга Excel с поддержкой макросов (*.xlsm),", , "Введите имя файла для сохраняемого отчёта", "Сохранить")
ActiveWorkbook.SaveAs filename, xlOpenXMLWorkbookMacroEnabled
With Application:  .EnableEvents = True: .DisplayAlerts = True:  End With
End Sub
вместо  ThisWorkbook.FullName - можно любое интересующее имя... но кнопку "открыть" всё равно придётся наживать руками
P.S.
почему не хотите просто задать имена нужных файлов строковой переменной (по логике, известной только вам)?
Изменено: JeyCi - 25.03.2017 21:37:39
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
 
Особенность в том, что я хочу загрузить .pdf файл. Путь(постоянный) и имя файла(переменное) у меня будут потом в какой нибудь переменной s. Проблема в том, что у меня не получается через код vba автоматически загрузить файл (прописать s в строку "Имя файла" окна "Выбор выкладываемого файла". ) потому что код не выполняется, пока диалоговое окно открыто. Вызов окна - мне не нужно. Если бы было возможно кодом загрузить файл .pdf на сайт без появляющегося диалогового окна - было бы хорошо. Но я не знаю как. Кто знает -подскажите!
 
Ves, в "Приемах" есть статья: способ №3 не Ваш случай?
 
Юрий М, Спасибо, но сама суть моего вопроса в том, чтобы загрузить файл на сайт. Это мне нужно для работы, где в программе, которая работает через IE, я автоматически пытаюсь прикрепить(загрузить) файл .pdf: появляется диалоговое окно загрузки файла точь в точь как в прикрепленном примере, и выполнение кода прекращается, пока не выбрать файл руками.
 
Может это чем поможет
Согласие есть продукт при полном непротивлении сторон
 
Доброе время суток.
Как то вы странно почту с вложением через Excel отправляете - как в анекдоте гланды через одно место автогеном...
Чем не устраивает библиотека Microsoft CDO for Windows?
Рабочий код для smtp сервера Yandex (проверял на своих e-mail).
Код
Public Sub SendEMail()
    Dim pConfig As New CDO.Configuration
    Dim pMsg As New CDO.Message
    Dim pFields As ADODB.Fields
    Dim i As Long
    
    Set pMsg.Configuration = pConfig
    Set pFields = pConfig.Fields
    pFields("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate").Value = CDO.CdoProtocolsAuthentication.cdoBasic
    pFields("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = CDO.CdoSendUsing.cdoSendUsingPort
    pFields("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value = "smtp.yandex.ru"
    pFields("http://schemas.microsoft.com/cdo/configuration/smtpserverport").Value = 465
    pFields("http://schemas.microsoft.com/cdo/configuration/smtpusessl").Value = True
    ''' Данные для входа на почту yandex
    pFields("http://schemas.microsoft.com/cdo/configuration/sendusername").Value = "UserName@yandex.ru"
    pFields("http://schemas.microsoft.com/cdo/configuration/sendpassword").Value = "UserPassword"
    '''
    pFields.Update
    
    pMsg.To = "RecipientName@gmail.com"
    pMsg.From = "UserName@yandex.ru" ' обязательно pMsg.From = pFields("http://schemas.microsoft.com/cdo/configuration/sendusername").Value
    pMsg.Subject = "Проверка CDO Message"
    pMsg.TextBody = "Привет!" & vbLf & "Не беспокойся это тестовое сообщение самому себе :) "
    pMsg.AddAttachment "D:\Path\pdfFileName.pdf"
    
    pMsg.Send
End Sub

Успехов
 
Sanja, Андрей VG, спасибо за ответы, но проблема именно в диалоговом окне IE(почту я привел как пример, аналог совсем другой программы на работе(работающей через IE), где у меня не получается автоматически загрузить/прикрепить файл, так как диалоговое окно IE прерывает выполнение кода, пока вручную не выберешь файл(также как на скриншоте)). Проблема не решена.  
 
Цитата
Ves написал:
когда я определю окно через hwnd, можно ли будет написать полный путь & имя файла не через sendkeys а как-нибудь по другому? (и потом нажать энтер тоже не через sendkeys?)
Если я правильно помню, существует API функция FindWindowEx. Ищет дочерние элементы родительского окна. С ее помощью и с помощью API SendMessage можно найти хендл строки "имя файла" и вставить туда путь и после нажать кнопку Ok. Делал подобное, не могу найти пример.
Вот нашел кусок:
Код
Do Until hParent > 0
Declare Function SendMessage Lib "user32" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal WParam As Integer, ByVal LParam As String) As Integer
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
Declare Function GetDlgItem Lib "user32" Alias "GetDlgItem" (ByVal hDlg As Integer, ByVal nIDDlgItem As Integer) As Integer            

hParent = FindWindow(vbNullString, "Открыть")
        Loop
        If (hParent) Then
            sText = Path & "\" & RepName
            Do Until hEditFileName > 0
                hEditFileName = GetDlgItem(hParent, 1152)
            Loop
        End If
        For Me.i = 0 To 100
            SendMessage(hEditFileName, WM_SETTEXT, 0, sText)
        Next i

        hButtonOK = GetDlgItem(hParent, 1) ' нажатие кнопки "Открыть". Ее CtrlID = 1
       PostMessage(hButtonOK, BM_CLICK, 0, 0)

Я это делал на .NET, но работа с API не должна сильно отличаться. Может быть придется уточнить объявление функций.
Изменено: VSerg - 26.03.2017 11:45:47
 
Итак, на свой один вопрос я ответил: Чтобы диалоговое окно Internet Explorera не блокировало дальнейшее выполнение кода нужно
Код
Doc.getelementsbytagname("label")(i).Click  'после клика появляется диалоговое окно выбора файла для загрузки
заменить на :
Код
Call SetCursorPos(446, 922)
mouse_event MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
то есть мы маускликаем кнопку, получаем тоже самое, но код продолжает работать!!!

А вот кнопку окна(зная hwnd окна) у меня пока что не получилось нажать.(программа ругается на Sendmessage и/или PostMessage) (Compile error: syntax error) (Declare Function прописал)
Код
SendMessage (hwnd,  BM_CLICK , 0 , 0)
пробовал и так и так
Код
 PostMessage(hwnd, BM_CLICK, 0, 0)
BM_CLICK уменя прописан: Const BM_CLICK = &HF5.

А еще хочется прописать путь в этом диалоговом окне не через Sendkeys, а через hwnd строки окна. Подскажите, как это сделать?
 
Ves, попробовал набросать небольшой пример с установкой текста и нажатием на кнопку с помощью API функций. Для простоты выбрал окно Open в IE. Перед экспериментами IE должен быть запущен, и в меню нажата Open, что бы было как на картинке ниже. Сравните объявления функций, раз ругается на syntax error. Должно быть Public Declare Function и Long для хендлов, иначе будет переполнение.
 
VSerg, Спасибо большое! Просто SendKeys при появлении новых окон в программе иногда путает язык (раскладку клавиатуры), то есть новое окно появляется, но почему-то принудительная смена языка  (Call LoadKeyboardLayout("00000419", &H1)) не помогает, и путь прикрепляемого файла в окне выбора файла прописывается коряво. Поэтому, надеюсь, новый метод(нажатие по хендлу) будет работать стабильнее! Хочу уточнить, для строки ввода насколько автоматически(каким способом) Вы получаете ее Хендл? Я циклом прохожу по всем элементам окна и, в моем случае, 13й по счету хендл - строка ввода.(Вы также определяете?)
Еще раз спасибо!
Изменено: Ves - 16.04.2017 02:37:34
 
Цитата
Ves написал:
Вы также определяете?
Не совсем. По заголовку я определяю хендл окна-родителя, тут все как у вас. Хендл дочернего элемента я определяю через функцию
Код
Public Declare Function GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
, где hDlg - хендл родительского окна, а nIDDlgItem - ID нужного нам элемента. В данном случае, строки ввода. Хендлы будут всегда разные, при каждом вызове окна, но ID элемента будет всегда оставаться одним и тем же.
Я подсмотрел ID через утилиту Spy++, очень полезная штука для задач, подобных вашей, рекомендую. Показывает кучу информации об окнах, их структуру, хендлы, ID, ссылки на родителя и т.д. Выдает информацию в шестнадцатеричном виде, т.е. подсмотренный ID нужно конвертнуть в десятичный вид перед использованием в VBA.
Страницы: 1
Читают тему
Наверх