Войти

Показать полную графическую версию : Активное окно


beginer
10-12-2020, 20:22
Здравствуйте.

Подскажите, пожалуйста как изменить следующую функцию, чтобы "захват" производился только с активного окна?
Мне это нужно для дела(вредительством не занимаюсь). Нужно как-бы "просеять" все открытые окна-проводники и отделить от них только активное.
Да, могу выделить нужное содержимое ориентируясь на путь, но проблемы начинаются тогда, когда открыто сразу ДВА! (и более) проводника с одинаковым путём.
Вот здесь-то и нужно определиться с какого из них "захватывать" выделенные объекты.

Вот код:
Function GetSelectedFiles() 'Returns paths as array of strings
Dim FileList, Window, SelectedItem
'avoid duplicates by storing paths in dictionary keys
Set FileList = CreateObject("Scripting.Dictionary")

With CreateObject("Shell.Application")
For Each Window In .Windows
' Document type IShellFolderViewDual3
If InStr(1, typename(Window.Document),"IShellFolderView", 1) > 0 Then
For Each SelectedItem In Window.Document.SelectedItems
FileList(SelectedItem.Path) = Null
Next
End If
Next
End With

GetSelectedFiles = FileList.Keys 'array of paths
End FunctionИ ещё один вопрос, если позволите. Тоже по теме, но это скорее вопрос к ОС.
Есть такая замечательная комбинация клавиш как Alt+Esc (активация предыдущего приложения). К сожалению, такого же антипода не нашёл(альтернатива - только Alt+TAB). Хорошо, допустим. Но почему игнорируются окна c флагом "поверх остальных"? Например, я запустил "Диспетчер задач" и выставил ему(его окну) этот флаг. Далее переключился, например, на Total Commander. А вот теперь начинается самое интересное. Почему по нажатию вышеуказанной комбинации клавиш я не попадаю на окно "Диспетчера задач", а на какое-то др. окно?

Очень надеюсь на вашу помощь.
Данное сообщение было отредактировано в связи с замечанием администратора

Vadikan
12-12-2020, 16:39
Тоже по теме, но это скорее вопрос к ОС. »
Не разводите оффтоп (ответы будут удалены). Одна проблема/вопрос - одна тема. Вопросы по ОС задавайте в осевых форумах.

beginer
15-12-2020, 14:18
Vadikan, хорошо. Вас понял. Тогда может ли кто-нибудь помочь мне с первой частью?
Как в вышеприведённой функции отфильтровать все остальные окна, кроме целевого (если мне известен заголовок целевого окна) ?


Добавлено:
Дополнительное условие, типа:
If Window.Visible = True Thenне подходит, так как все открытые окна проводника являются видимыми. И те, которые нужно отсеять и целевое окно.

Iska
15-12-2020, 16:27
beginer, в чём исполняется код?

beginer
15-12-2020, 19:16
Iska, в том-то и дело, что не через w(с)script.
Код выполняется в PureBasic'е. Там через такие дебри производится пуск, что самое простое для меня это поправить сам скрипт (по-возможности).
Единственный вариант, который могу выполнить - это перед выполнением закрыть окно проводника с идентичным путём или временно скрыть его, чтобы сработало условие выше. Но это некрасиво. И хотелось более элегантного решения. Спрашивал здесь как читать заголовок каждого окна во время перебора(в уже существующем цикле) и соответственно сравнивать его с определённой строкой каждую итерацию. В этом и заключалась суть вопроса. Если из vbs можно вызывать API ОС, то это бы решило/существенно упростило задачу. "Я так думаю" (С). Не скрою, что пример скрипта взял уже готовый. Он потребовался дабы выяснить отмеченные объекты. Иных решений данного вопроса увы не встречал. Неудобство данного варианта заключается в том, что скрипт "хватает" всё что "видит". Повторюсь, что отсеять проводники с уникальными путями не составляет особого труда. НО с идентичным путём(ями) - это проблема!


Добавлено:
Пожалуйста не беспокойтесь о случаях, когда в настройках ОС (св-ва папки) не выставлено показывать полный путь. Сейчас говорю про вариации с одинаковыми папками на различных разделах и расположенных на одинаковых уровнях(к примеру, "C:\Test"; "D:\Test"; "E:\Test" и т.д.). Ну и соответственно про одинаковые для такого случая заголовки окон. Это проблема решаема.
В PB прочитать title совсем не сложно (неужели vbs'у это не под силу?). Категорически нужен этот скрипт (без него никак не обойтись).

Iska
15-12-2020, 20:12
О, боже ж ты мой :( …

https://i.imgur.com/oat0msS.png

Iska
15-12-2020, 21:22
Код выполняется в PureBasic'е. »
У меня в нём ошибка прямо на строке:
Function GetSelectedFiles() 'Returns paths as array of strings

Попробуйте это:
Остановлюсь на п.2. В документации говорится, что вызов ShellWindows.Item() без параметров возвращает то же, что и ShellWindows.Item(0). Однако, как я убедился, это не соответствует действительности: стабильно возвращается последнее активное окно в коллекции ShellWindows. Хотя, может быть, это верно не на всех системах…

Отсюда: WSH(+ Реестр): «Найти объект...» в контекстном меню ярлыков (Страница 1) — Windows Script Host, HTA (VBScript, JScript) — Общение — Серый форум (http://forum.script-coding.com/viewtopic.php?id=2228).

Iska
15-12-2020, 21:54
У меня, увы, не сработало — под Windows 7 SP1 x64:
CreateObject("Shell.Application").Windows().Item(3).document.Folder.self.Path
стабильно возвращает не последнее активное окно, а тупо Desktop текущего пользователя.

beginer
15-12-2020, 21:58
Iska, спасибо за желание помочь. Но этот код не запустить "напрямую"(с ходу/в лоб). Нужна ещё довольно весомая и мудрёная обвёртка. Так что тот кусочек кода, что выше - это только вершина айсберга. Однако сделана обвёртка достойно/добротно. По всем канонам(всё по-взрослому). Очень много работы с памятью(указателями). Немец постарался и поделился своим титаническим трудом с остальными/общественностью.
К тому же в модуле используются вызовы API-функций. Смотрю, что Вы "качаете" демо-версию, а в ней для вызова API нужно действовать немного по-другому. То есть сначала нужно открыть библиотеку и т.д. В полной же версии эти функции являются как бы "нативные" и не требуют дополнительных телодвижений для их вызова. Работать намного проще и удобней.
Не знаю запрещены ли здесь ссылки на сторонние сайты, но если что поправьте (по крайней мере это точно не варез, а вполне себе open source).
Вот сам модуль-обвёртка (https://www.purebasic.fr/english/viewtopic.php?f=12&t=71399), если интересно посмотреть. Но я бы туда без поллитры не лез :)
Шутка.

Вот чувствую, что не в то русло опять зашёл разговор. Заругают админы(наверное нужно завязывать). Поэтому и просил подправить непосредственно vbscript.


P.S. Когда-то начинал знакомство со скриптами, но это было недолго(довольно быстро перешёл на PB). Поэтому и задаю здесь возможно детский вопрос. + знаю, что на этом форуме обитает/прописано много профессионалов, причём русскоговорящих.

Iska
15-12-2020, 22:43
К тому же в модуле используются вызовы API-функций. »
beginer, в приведённом Вами коде нет вызовов WinAPI. Чистый COM/Automation.

Поэтому и просил подправить непосредственно vbscript. »
Так нечего поправлять. Я не вижу способов найти средствами Automation «активное окно Проводника». Как бы мы их не тасовали — они возвращаются в порядке создания окон, а не в порядке Z-order. А вот Вы можете, взяв WinAPI наперевес, попробовать пройтись по списку полученных окон.

beginer
16-12-2020, 21:43
Iska, говорил про модуль(вызовы WinAPI).
Ну нет, так нет. Видимо прийдётся закрывать одинаковые. Получить Z-Order - не проблема. Недопонял только что это даст? Хэндл активного окна мне и так известен(причём заранее и достоверно). То есть его не нужно искать непосредственно в скрипте. Если бы его теперь сравнивать с каждым найденным окном(цикл скрипта), тогда да. Будет толк. Или даже не хэндл, а заголовок окна. Повторюсь, что мне не нужно искать активное окно проводника! Я спрашивал совсем не об этом. А о возможности добавить в скрипт дополнительное условие(в момент перебора окон). Представьте, что у Вас есть ещё одна переменная(естественно в поле зрения скрипта), в которой находится хэндл или заголовок активного окна проводника(как угодно). Как эту переменную сделать видимой самим скриптом - тоже не есть вопрос данной темы.

Iska
16-12-2020, 22:15
Хэндл активного окна мне и так известен

Если бы его теперь сравнивать с каждым найденным окном(цикл скрипта), тогда да. Будет толк. Или даже не хэндл, а заголовок окна. »
Именно хэндл. Заголовок не годится — он не уникален.

WSH:
Option Explicit

Dim objWebBrowser

For Each objWebBrowser In WScript.CreateObject("Shell.Application").Windows()
With objWebBrowser
If InStr(1, TypeName(.document), "ShellFolderViewDual", vbTextCompare) > 0 Then
WScript.Echo .hwnd, vbTab, .document.Folder.self.Path
End If
End With
Next

WScript.Quit 0

Сравнивайте:
If InStr(1, TypeName(.document), "ShellFolderViewDual", vbTextCompare) > 0 Then
WScript.Echo .hwnd, vbTab, .document.Folder.self.Path

If .hwnd = ... Then
...
End If
End If

Serguei Kouzmine
19-12-2020, 03:57
@beginer VB языку трудно с получением

поэтому часто советуют запустить повершелл обертку win32 API которая даст вам
ответ
например

param(
[int]$sleep = 10
)
start-sleep -second $sleep
# based on https://social.technet.microsoft.com/Forums/en-US/4d257c80-557a-4625-aad3-f2aac6e9a1bd/get-active-window-info?forum=winserverpowershell
add-type -name Utils -namespace Win32 -memberdefinition @'
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
'@
$windowHandle = [Win32.Utils]::GetForegroundWindow()
Get-Process | where-Object { $_.mainWindowHandle -eq $windowHandle } |
select-Object -property processName, MainWindowTItle, MainWindowHandle





PS C:\Users\Serguei> . .\get_window_has_focus.ps1 -sleep 4

ProcessName MainWindowTitle MainWindowHandle
----------- --------------- ----------------
vivaldi Get Active Window Info - Vivaldi 67038

в вашем скрипте эту информацию прочитаете и найдете которое активное

кстати если будете гуглить то ищите по английски это назваетется
Window has Focus

напр

find which window has focus

https://social.technet.microsoft.com/Forums/en-US/4d257c80-557a-4625-aad3-f2aac6e9a1bd/get-active-window-info?forum=winserverpowershell - то что я привел выше (добавил задержку чтобы тестировать было время поднять другое окно

beginer
19-12-2020, 10:54
Serguei Kouzmine, спасибо большое за желание помочь, но PS не подходит. Да и запускается он откровенно/неприлично долго. Хотел только подстроиться под уже готовый vbscript, так как он благополучно "прикручен" к основной программе. И в принципе, работа скрипта вполне устраивает, за исключением этой небольшой оказии. И, да, конечная цель заключалась совсем не в поиске активного окна. Почему изначально сделал акцент на это и тему так назвал, так это для того, чтобы задавая вопрос объяснить/сразу дать понять, что ищу способ сепарации/разделения. Скрипт этот захватывает выделенные объекты из открытых окон-проводников. Если у Вас на ПК, допустим, открыты проводники с путями "С:\TEST" и "D:\TEST" + в обоих что-то выбрано, то этот случай просто решается. А вот если открыто два окна(две копии проводника) с "С:\TEST"(сейчас не важно что там покажет title, полный путь или нет) и допустим, что у вас в этом каталоге есть след. файлы: "1.txt", "2.txt", "3.txt", "4.txt" и "5.txt". Допустим в одном окне вы выбрали файлы 1, 3, 5, а во втором 2 и 4. Так вот в этом случае в результат будут включены все пять файлов. И это есть нехорошо и неправильно. И обойти это не представляется возможным, кроме как закрыть или временно скрыть идентичный проводник(и). Надеюсь, что доходчиво объяснил суть задачи. Естественно, случай с двумя идентичными проводниками, но когда объекты выделены только в одном из них - тоже не представляет опасности.

Iska, Вам тоже спасибо за участие.

Как уже говорил выше, тут мне видится разве что вариант с закрытием окон проводников с идентичными путями(не трогая при этом уникальные, если таковые имеются/открыты). Правда это может раздражать пользователя (мелькающие окна). Будем считать этот случай большой редкостью и что нужно очень постараться/сделать это умышленно, чтобы его достичь.

Всем спасибо!

Iska
19-12-2020, 20:21
beginer, да зачем закрывать-то? Получили хэндл «верхнего» окна Проводника — WinAPI. Перечислили все окна Проводника, отобрали из них только то, которое имеет ранее полученный хэндл, получили из этого окна перечень выделенных объектов Проводника (необязательно файлов или папок) — COM/Automation.




© OSzone.net 2001-2012