Добрый день. Прошу помочь решить такую проблему: Есть макрос, который запускается из имеющейся книги, находит данные в двух других открытых книгах и копирует эти данные в соответствующие строки исходной книги. Проблема в том, что эти две книги являются выгрузками из учетной программы и открываются в новых экземплярах эксель. Запущенный макрос попросту не видит эти две книги, и приходится перед запуском макроса сперва их сохранять, потом заново открывать. А это дополнительные операции и время( Вопрос: можно ли сделать эти книги видимыми для макроса без их сохранения и переоткрывания?
Добрый день. Прошу помочь решить такую проблему: Есть макрос, который запускается из имеющейся книги, находит данные в двух других открытых книгах и копирует эти данные в соответствующие строки исходной книги. Проблема в том, что эти две книги являются выгрузками из учетной программы и открываются в новых экземплярах эксель. Запущенный макрос попросту не видит эти две книги, и приходится перед запуском макроса сперва их сохранять, потом заново открывать. А это дополнительные операции и время( Вопрос: можно ли сделать эти книги видимыми для макроса без их сохранения и переоткрывания?Sambo_
Option Explicit Private Declare Function GetDesktopWindow Lib "user32" () As Long Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Sub t_() ' если известно расположение файлов
' запускаемый экземпляр Dim MyXL1 As Object Set MyXL1 = GetObject(, "Excel.Application") Debug.Print MyXL1.hwnd
' экземпляр какой-то книги Dim MyXL2 As Object Set MyXL2 = GetObject(ThisWorkbook.Path & "\Книга3.xlsx").Application Debug.Print MyXL2.hwnd End Sub
Sub t__() ' поиск дескрипторов всех экземпляров Excel. Возможный вектор поиска решения... Dim alH() As Long FindAllHwnd GetDesktopWindow, alH, "XLMAIN"
Dim i As Integer For i = LBound(alH) To UBound(alH) Debug.Print alH(i) Debug.Print GetWindowText_(alH(i)) Next i End Sub
Sub FindAllHwnd(hWndParent As Long, _ ByRef alHwnd() As Long, _ Optional ByVal sClass As String = vbNullString, _ Optional ByVal sCaption As String = vbNullString)
Dim hwnd As Long Dim n As Integer: n = 0 Do hwnd = FindWindowEx(hWndParent, hwnd, sClass, sCaption) If hwnd <> 0 Then n = n + 1 ReDim Preserve alHwnd(1 To n) alHwnd(n) = hwnd End If Loop Until hwnd = 0 End Sub
Private Function GetWindowText_(hwnd As Long) Dim MyStr As String: MyStr = String(100, Chr$(0)) GetWindowText hwnd, MyStr, 100 GetWindowText_ = Left$(MyStr, InStr(MyStr, Chr$(0)) - 1) End Function
[/vba]
[vba]
Code
Option Explicit Private Declare Function GetDesktopWindow Lib "user32" () As Long Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Sub t_() ' если известно расположение файлов
' запускаемый экземпляр Dim MyXL1 As Object Set MyXL1 = GetObject(, "Excel.Application") Debug.Print MyXL1.hwnd
' экземпляр какой-то книги Dim MyXL2 As Object Set MyXL2 = GetObject(ThisWorkbook.Path & "\Книга3.xlsx").Application Debug.Print MyXL2.hwnd End Sub
Sub t__() ' поиск дескрипторов всех экземпляров Excel. Возможный вектор поиска решения... Dim alH() As Long FindAllHwnd GetDesktopWindow, alH, "XLMAIN"
Dim i As Integer For i = LBound(alH) To UBound(alH) Debug.Print alH(i) Debug.Print GetWindowText_(alH(i)) Next i End Sub
Sub FindAllHwnd(hWndParent As Long, _ ByRef alHwnd() As Long, _ Optional ByVal sClass As String = vbNullString, _ Optional ByVal sCaption As String = vbNullString)
Dim hwnd As Long Dim n As Integer: n = 0 Do hwnd = FindWindowEx(hWndParent, hwnd, sClass, sCaption) If hwnd <> 0 Then n = n + 1 ReDim Preserve alHwnd(1 To n) alHwnd(n) = hwnd End If Loop Until hwnd = 0 End Sub
Private Function GetWindowText_(hwnd As Long) Dim MyStr As String: MyStr = String(100, Chr$(0)) GetWindowText hwnd, MyStr, 100 GetWindowText_ = Left$(MyStr, InStr(MyStr, Chr$(0)) - 1) End Function
Боюсь, что самым простым будет - написать макрос, запускаемый НЕ из Excel (!), а из другого приложения (Word, Outlook или отдельно стоящий VB-скрипт).
Макрос будет делать примерно следующее: * последовательно закрывать все открытые экземпляры Excel - до полного отсутствия Excel в оперативной памяти компьютера, когда очередной оператор GetObject ничего не вернет; * если очередной экземпляр будет с одним из этих двух временных файлов, то сохранять его на диске и также закрывать; * заканчивать свою работу запуском в новом экземляре Excel существующей книги с макросом (т.е. фактически передавая ему управление), который и будет переносить информацию из файлов, полученных из учетной системы.
Исходя из этого, а также из кода, который привел Саня, может быть, дополнительные затраты времени и сил на ручное сохранение файлов уже не кажутся Вам такими уж затратными?
Боюсь, что самым простым будет - написать макрос, запускаемый НЕ из Excel (!), а из другого приложения (Word, Outlook или отдельно стоящий VB-скрипт).
Макрос будет делать примерно следующее: * последовательно закрывать все открытые экземпляры Excel - до полного отсутствия Excel в оперативной памяти компьютера, когда очередной оператор GetObject ничего не вернет; * если очередной экземпляр будет с одним из этих двух временных файлов, то сохранять его на диске и также закрывать; * заканчивать свою работу запуском в новом экземляре Excel существующей книги с макросом (т.е. фактически передавая ему управление), который и будет переносить информацию из файлов, полученных из учетной системы.
Исходя из этого, а также из кода, который привел Саня, может быть, дополнительные затраты времени и сил на ручное сохранение файлов уже не кажутся Вам такими уж затратными? Gustav
Учётную программу нельзя заставить доработать, чтоб открывала файлы в уже существующем Экселе, если он открыт? На vbs такое сделать не сложно, использую. Т.е. открыли файл с макросом, подгрузили туда отчёты - и работаете.
Учётную программу нельзя заставить доработать, чтоб открывала файлы в уже существующем Экселе, если он открыт? На vbs такое сделать не сложно, использую. Т.е. открыли файл с макросом, подгрузили туда отчёты - и работаете.Hugo
Да.., не думал, что эта задача такая гемор=я. Предполагал, что раз уж из Exel можно работать, например, с тем же Wordом, который запускается, уж наверняка в другом процессе, то как-то можно работать и с книгой запущенной в другом экземпляре. Теперь понятно почему за весь вчерашний вечер в инете не удалось найти по данному вопросу ничего толкового. Тем не менее, спасибо всем за советы. Hugo,заставить доработать программу, пожалуй, самый простой вариант, но увы, наша учетная программа не настраивается индивидуально под пользователя, так как ее используют несколько сот муниципальных образований. А если изменять код для всех, то кому-то это, конечно, покажется не удобным( Gustav, вы по сути предлагаете автоматизировать ручные операции по закрытию и открытию книг. Данный вариант для меня также не выход: дело в том, что книга с макросом каждый раз после обновления данных пересохраняется в другой папке и с несколько иным именем. Поэтому прописать в коде где находится книга, подлежащая открытию, и как она называется не получится. Саня, отдельное спасибо, но чтобы понять ваш код мне потребуется, наверное, несколько лет усиленных занятий по изучению ВБА :) Понимаю, что здесь не курсы изучения языков программирования, но просвятите хотя бы, что за функции такие GetDesktopWindow и FindWindowEx и что означает Lib "user32"?
Да.., не думал, что эта задача такая гемор=я. Предполагал, что раз уж из Exel можно работать, например, с тем же Wordом, который запускается, уж наверняка в другом процессе, то как-то можно работать и с книгой запущенной в другом экземпляре. Теперь понятно почему за весь вчерашний вечер в инете не удалось найти по данному вопросу ничего толкового. Тем не менее, спасибо всем за советы. Hugo,заставить доработать программу, пожалуй, самый простой вариант, но увы, наша учетная программа не настраивается индивидуально под пользователя, так как ее используют несколько сот муниципальных образований. А если изменять код для всех, то кому-то это, конечно, покажется не удобным( Gustav, вы по сути предлагаете автоматизировать ручные операции по закрытию и открытию книг. Данный вариант для меня также не выход: дело в том, что книга с макросом каждый раз после обновления данных пересохраняется в другой папке и с несколько иным именем. Поэтому прописать в коде где находится книга, подлежащая открытию, и как она называется не получится. Саня, отдельное спасибо, но чтобы понять ваш код мне потребуется, наверное, несколько лет усиленных занятий по изучению ВБА :) Понимаю, что здесь не курсы изучения языков программирования, но просвятите хотя бы, что за функции такие GetDesktopWindow и FindWindowEx и что означает Lib "user32"?Sambo_
Gustav, вы по сути предлагаете автоматизировать ручные операции по закрытию и открытию книг. Данный вариант для меня также не выход: дело в том, что книга с макросом каждый раз после обновления данных пересохраняется в другой папке и с несколько иным именем. Поэтому прописать в коде где находится книга, подлежащая открытию, и как она называется не получится.
Ого! Это у вас типа DocFlow такое, что книга переименовывается и путешествует по папкам? Но вручную-то когда запускаете, как-то же знаете, где она находится и как называется в момент запуска?
А если макрос из нее вынуть и включить его в самостоятельный VB-скрипт, который бы один всем рулил и никому не передавал управление?
Собственно, основной смысл моего предыдущего выступления был в том, что Getobject(,"Excel.Application") при нескольких открытых приложениях привязывается к одному из них непредсказуемо. И гарантированно побывать во всех из них по разу за один цикл можно лишь путем закрытия очередного, в который попали в текущий момент. И это объективная реальность, с которой вам придется считаться при разработке того или иного решения.
Quote (Sambo_)
Предполагал, что раз уж из Exel можно работать, например, с тем же Wordом, который запускается, уж наверняка в другом процессе, то как-то можно работать и с книгой запущенной в другом экземпляре.
Это можно. НО! Только в том случае, если другой экземпляр запущен из первого. Если же он запущен НЕЗАВИСИМО от первого, то - увы!..
Quote (Sambo_)
Gustav, вы по сути предлагаете автоматизировать ручные операции по закрытию и открытию книг. Данный вариант для меня также не выход: дело в том, что книга с макросом каждый раз после обновления данных пересохраняется в другой папке и с несколько иным именем. Поэтому прописать в коде где находится книга, подлежащая открытию, и как она называется не получится.
Ого! Это у вас типа DocFlow такое, что книга переименовывается и путешествует по папкам? Но вручную-то когда запускаете, как-то же знаете, где она находится и как называется в момент запуска?
А если макрос из нее вынуть и включить его в самостоятельный VB-скрипт, который бы один всем рулил и никому не передавал управление?
Собственно, основной смысл моего предыдущего выступления был в том, что Getobject(,"Excel.Application") при нескольких открытых приложениях привязывается к одному из них непредсказуемо. И гарантированно побывать во всех из них по разу за один цикл можно лишь путем закрытия очередного, в который попали в текущий момент. И это объективная реальность, с которой вам придется считаться при разработке того или иного решения.
Quote (Sambo_)
Предполагал, что раз уж из Exel можно работать, например, с тем же Wordом, который запускается, уж наверняка в другом процессе, то как-то можно работать и с книгой запущенной в другом экземпляре.
Это можно. НО! Только в том случае, если другой экземпляр запущен из первого. Если же он запущен НЕЗАВИСИМО от первого, то - увы!..Gustav
но чтобы понять ваш код мне потребуется, наверное, несколько лет усиленных занятий по изучению ВБА
в 2007 году я не знал что такое ВПР...
Quote (Sambo_)
Понимаю, что здесь не курсы изучения языков программирования, но просвятите хотя бы, что за функции такие GetDesktopWindow и FindWindowEx и что означает Lib "user32"?
все это функции Win API: GetDesktopWindow - получение манипулятора рабочего стола (это окно высшего уровня иерархии окон) FindWindowEx - эта функция циклически просматривает непосредственные дочерние окна - для рабочего стола это все запущенные приложения и "еще что-то", "отлов" основного окна Excel происходит по имени класса "XLMAIN". Если погружаться дальше, то можно дойти: ленты, строки состояния, адресной строки, всех окон рабочих книг (именно здесь я думал зацепиться за экземпляры приложения)
user32 - user32.dll - это имя библиотеки, где и находятся эти замечательные функции
Quote (Sambo_)
но чтобы понять ваш код мне потребуется, наверное, несколько лет усиленных занятий по изучению ВБА
в 2007 году я не знал что такое ВПР...
Quote (Sambo_)
Понимаю, что здесь не курсы изучения языков программирования, но просвятите хотя бы, что за функции такие GetDesktopWindow и FindWindowEx и что означает Lib "user32"?
все это функции Win API: GetDesktopWindow - получение манипулятора рабочего стола (это окно высшего уровня иерархии окон) FindWindowEx - эта функция циклически просматривает непосредственные дочерние окна - для рабочего стола это все запущенные приложения и "еще что-то", "отлов" основного окна Excel происходит по имени класса "XLMAIN". Если погружаться дальше, то можно дойти: ленты, строки состояния, адресной строки, всех окон рабочих книг (именно здесь я думал зацепиться за экземпляры приложения)
user32 - user32.dll - это имя библиотеки, где и находятся эти замечательные функцииСаня
То, что вчера я не нашел - возвращает объект из дескриптора окна [vba]
Code
Option Explicit Private Const OBJID_NATIVEOM = &HFFFFFFF0 Type GUID lD1 As Long iD2 As Integer iD3 As Integer abytD4(0 To 7) As Byte End Type Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _ ByVal hWnd As Long, _ ByVal dwId As Long, _ riid As GUID, _ ppvObject As Object) As Long '-------------------------------------------------------------------------------
Function AppFromHwnd(hWnd As Long) As Object ' GUID для IDispatch object {00020400-0000-0000-C000-000000000046} Dim id As GUID With id .lD1 = &H20400 .iD2 = &H0: .iD3 = &H0 .abytD4(0) = &HC0: .abytD4(1) = &H0 .abytD4(2) = &H0: .abytD4(3) = &H0 .abytD4(4) = &H0: .abytD4(5) = &H0 .abytD4(6) = &H0: .abytD4(7) = &H46 End With
Dim obj As Object AccessibleObjectFromWindow hWnd, OBJID_NATIVEOM, id, obj Set AppFromHwnd = obj.Application End Function
[/vba]
весь код во вложении - проц. GetAllXLApp кто хочет посмотреть оконные "потроха" Excel'я - проц. AllWindowsOfAllXLs
копай!
То, что вчера я не нашел - возвращает объект из дескриптора окна [vba]
Code
Option Explicit Private Const OBJID_NATIVEOM = &HFFFFFFF0 Type GUID lD1 As Long iD2 As Integer iD3 As Integer abytD4(0 To 7) As Byte End Type Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _ ByVal hWnd As Long, _ ByVal dwId As Long, _ riid As GUID, _ ppvObject As Object) As Long '-------------------------------------------------------------------------------
Function AppFromHwnd(hWnd As Long) As Object ' GUID для IDispatch object {00020400-0000-0000-C000-000000000046} Dim id As GUID With id .lD1 = &H20400 .iD2 = &H0: .iD3 = &H0 .abytD4(0) = &HC0: .abytD4(1) = &H0 .abytD4(2) = &H0: .abytD4(3) = &H0 .abytD4(4) = &H0: .abytD4(5) = &H0 .abytD4(6) = &H0: .abytD4(7) = &H46 End With
Dim obj As Object AccessibleObjectFromWindow hWnd, OBJID_NATIVEOM, id, obj Set AppFromHwnd = obj.Application End Function
[/vba]
весь код во вложении - проц. GetAllXLApp кто хочет посмотреть оконные "потроха" Excel'я - проц. AllWindowsOfAllXLs