Автор Тема: Как найти дескриптор предыдущего активного окна  (Прочитано 4888 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Эта тема содержит сообщение, помеченное как лучший ответ. Кликните здесь для перехода к этому сообщению.

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
При запуске скрипта нужно узнать какое приложение было активно. Уже всю голову поломал себе. Помогите, пожалуйста.

Русское сообщество AutoIt


Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 4093
  • Репутация: 1083
    • Награды
  • Версия AutoIt: 3.3.14.0

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36

  • Автор темы
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Оказывается не до конца локализовал проблему.
Запуск программы происходит из панели задач (закрепленной ссылкой, Windows 7).
Код: AutoIt [Выделить]
WinGetHandle("[active]")

возвращает 0x0000000000000000

Русское сообщество AutoIt

Re: Как найти дескриптор предыдущего активного окна
« Ответ #2 Отправлен: Июнь 08, 2015, 11:59:34 »

Помечен как лучший ответ пользователем Cornet Отправлен Июнь 08, 2015, 13:35:15

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 4093
  • Репутация: 1083
    • Награды
  • Версия AutoIt: 3.3.14.0
См. пример в справке к функции
Код: AutoIt [Выделить]
Первой будет кнопка "Пуск", а все следующие окна будут перечислены в порядке их предыдущей активности.

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36

  • Автор темы
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Спасибо, InnI.
Переписал пример из справки, вдруг кому ни будь понадобится
Код: AutoIt [Выделить]
#include <MsgBoxConstants.au3>

Local $hWnd = LastActiveWindow()
MsgBox($MB_SYSTEMMODAL, "", "Title: " & WinGetTitle($hWnd) & @CRLF & "Handle: " & $hWnd)

Func LastActiveWindow()
    Local $aList = WinList()
    For $i = 1 To $aList[0][0]
        If $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 2) And $aList[$i][0] <> "Пуск" Then Return $aList[$i][1]
    Next
EndFunc


Внимание! Если запущены какие ни будь процессы "Always On Top" — будет выдавать дескриптор верхнего из них. Мне не критично. Но если есть идеи как правильнее определять последнее активное, с удовольствием послушаю.
« Последнее редактирование: Июнь 08, 2015, 15:19:21 от Cornet, Причина: Добавлено замечание по работе кода »

Русское сообщество AutoIt

Re: Как найти дескриптор предыдущего активного окна
« Ответ #4 Отправлен: Июнь 08, 2015, 13:39:30 »

Оффлайн firex [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 943
  • Репутация: 203
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Cornet
В вашем случае идет перечисление по Z-Order от большего к меньшему(или правильнее сказать от меньшего к большему). Все окна в системе - последовательно связанные структуры, которые меняют свои поля Prev/Next в зависимости от своего положения по Z. "Always On Top" имеют приоритет при выполнении этой процедуры, поэтому они и располагаются в самом начале.

Если вы собираетесь игнорировать подобные окна, то можете банально "пропускать" их:
Код: AutoIt [Выделить]
#include <MsgBoxConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Local $hWnd = LastActiveWindow()
MsgBox($MB_SYSTEMMODAL, "", "Title: " & WinGetTitle($hWnd) & @CRLF & "Handle: " & $hWnd)

Func LastActiveWindow()
    Local $aList = WinList()
    For $i = 1 To $aList[0][0]
        If _
            $aList[$i][0] <> "" And _
            BitAND(WinGetState($aList[$i][1]), 2) And _
            Not BitAND(_WinAPI_GetWindowLong($aList[$i][1], $GWL_EXSTYLE), $WS_EX_TOPMOST) _
        Then
        ; ---
            Return $aList[$i][1]
        EndIf
    Next
EndFunc

« Последнее редактирование: Июнь 08, 2015, 18:23:32 от firex »

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36

  • Автор темы
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
До Z-Order я еще через _WinAPI_GetWindow добирался, только от перегрузки мозгов не хватило исключить скрытые окна и окна без заголовка.
Но ведь <Alt+Tab> прекрасно помнит порядок последних окон, несмотря на флаг $WS_EX_TOPMOST и несмотря на то откуда было запущено приложение.
Значит есть где-то более правильное решение)

Оффлайн firex [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 943
  • Репутация: 203
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Cornet  [?]
Цитировать
Но ведь <Alt+Tab> прекрасно помнит порядок последних окон, несмотря на флаг $WS_EX_TOPMOST
У меня, как и следовало ожидать, порядок идентичен положению в Z-Order.

P.S. Не думаю, что искомый вами "порядок" вообще где-либо имеется в подсистеме win32k, по крайней мере я такого не наблюдал. Может быть вы путаете активность с фокусом?

Русское сообщество AutoIt

Re: Как найти дескриптор предыдущего активного окна
« Ответ #7 Отправлен: Июнь 08, 2015, 22:11:09 »

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36

  • Автор темы
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Может быть и путаю.
Но тогда я не понимаю функции WinActivate. Вот пример:
Код: AutoIt [Выделить]
#include <MsgBoxConstants.au3>
#include <GUIConstantsEx.au3>

Run("notepad.exe")
Run("Au3Info_x64.exe")
$hWndN = WinWait("[CLASS:Notepad]", "", 10)

WinActivate($hWndN)

Local $hWnd = LastActiveWindow()
ConsoleWrite(WinGetTitle($hWnd) & @CRLF & "Handle: " & $hWnd)

Local $hGUI = GUICreate("Example", 400, 100)
GUISetState()
While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd
GUIDelete($hGUI)

Func LastActiveWindow()
    Local $aList = WinList()
    For $i = 1 To $aList[0][0]
        If $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 2) And $aList[$i][0] <> "Пуск" Then Return $aList[$i][1]
    Next
EndFunc

В консоль попадает «(Frozen) AutoIt v3 Window Info», а <Alt+Tab> переключает на Блокнот.
если же убрать WinActivate($hWndN) в консоль все равно попадает «(Frozen) AutoIt v3 Window Info», но и <Alt+Tab> переключает на «(Frozen) AutoIt v3 Window Info».

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 4093
  • Репутация: 1083
    • Награды
  • Версия AutoIt: 3.3.14.0
Cornet
Описанное вами поведение наблюдается на Win81. На Win7 и WinXP порядок окон в панели переключения Alt+Tab полностью соответствует Z-буферу, т.е. сначала идут topmost-окна, затем все остальные. Возможно, на Win8 происходит дополнительное отслеживание порядка активности окон, что и приводит к последовательному переключению не зависимо от наличия стиля WS_EX_TOPMOST. Кстати, альтернативное переключение по Alt+ESC вообще не затрагивает topmost-окна ни на Win7 ни на Win8.

Оффлайн Cornet [?]

  • Новичок
  • *
  • Сообщений: 36

  • Автор темы
  • Репутация: 6
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Вы правы, поведение на Win81 и Win7 различно.
Ну что ж, я больше поднимать эту тему не буду, пока она для меня решена. Начнутся проблемы topmost-окнами — вернусь.
Спасибо за еще большую локализацию проблемы.

Оффлайн madmasles [?]

  • Глобальный модератор
  • *
  • Сообщений: 7790
  • Репутация: 2317
  • Пол: Мужской
  • Награды За модерирование форума
    • Награды
  • Версия AutoIt: 3.3.x.x
Cornet,
На Win8(1) проверить не могу, но на Win7 32 у меня работает такая функция.
Код: AutoIt [Выделить]
#include <WinAPI.au3>
#include <Constants.au3>

$hPrevious = _GetPreviousActiveWindow()
If Not $hPrevious Then Exit ConsoleWrite('Error' & @LF)
ConsoleWrite('Title: ' & _WinAPI_GetWindowText($hPrevious) & @LF)
ConsoleWrite('Class: ' & _WinAPI_GetClassName($hPrevious) & @LF)

Func _GetPreviousActiveWindow($h_Active = 0)
    If Not $h_Active Then $h_Active = WinGetHandle('[ACTIVE]')
    If Not $h_Active Then Return 0
    Do
        $h_Active = _WinAPI_GetWindow($h_Active, $GW_HWNDNEXT)
        If Not $h_Active Then Return 0
    Until _WinAPI_IsWindowVisible($h_Active)
    Return $h_Active
EndFunc   ;==>_GetPreviousActiveWindow


Оффлайн firex [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 943
  • Репутация: 203
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
madmasles
Тот же принцип Z-Order, пробуйте на примере TopMost.


Добавлено: Июнь 10, 2015, 13:31:56
InnI  [?]
Цитировать
Кстати, альтернативное переключение по Alt+ESC вообще не затрагивает topmost-окна ни на Win7 ни на Win8.
Оно их попросту игнорирует. Переключение происходит только путем отправки на дно Z-Order активного окна.
« Последнее редактирование: Июнь 10, 2015, 13:31:56 от firex, Причина: Объединение сообщений »

Оффлайн madmasles [?]

  • Глобальный модератор
  • *
  • Сообщений: 7790
  • Репутация: 2317
  • Пол: Мужской
  • Награды За модерирование форума
    • Награды
  • Версия AutoIt: 3.3.x.x
firex  [?]
Цитировать
Тот же принцип Z-Order, пробуйте на примере TopMost.
Интересно, если в скрипте не создавать окно с $WS_EX_TOPMOST, то функция отрабатывает правильно.
Сначала запускаю отдельный код
Код: AutoIt [Выделить]
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

GUICreate('Test', 300, 300, -1, -1, -1, $WS_EX_TOPMOST)
GUISetState()
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Потом из SciTE этот
Код: AutoIt [Выделить]
#include <WinAPI.au3>
#include <Constants.au3>

GUICreate('Test1')
GUISetState()
Sleep(1000)

$hPrevious = _GetPreviousActiveWindow()
If Not $hPrevious Then Exit ConsoleWrite('Error' & @LF)
ConsoleWrite('Title: ' & _WinAPI_GetWindowText($hPrevious) & @LF)
ConsoleWrite('Class: ' & _WinAPI_GetClassName($hPrevious) & @LF)

Func _GetPreviousActiveWindow($h_Active = 0)
    If Not $h_Active Then $h_Active = WinGetHandle('[ACTIVE]')
    If Not $h_Active Then Return 0
    Do
        $h_Active = _WinAPI_GetWindow($h_Active, $GW_HWNDNEXT)
        If Not $h_Active Then Return 0
    Until _WinAPI_IsWindowVisible($h_Active)
    Return $h_Active
EndFunc   ;==>_GetPreviousActiveWindow

Правильно возвращает SciTE.
Но если добавить в создаваемое окно $WS_EX_TOPMOST, то у меня возвращаетTitle: Пуск
Class: Button
Не зависимо от того, какое окно было ранее активным. Почему так, не понимаю.  :stars:

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 4093
  • Репутация: 1083
    • Награды
  • Версия AutoIt: 3.3.14.0
madmasles
Цитировать
Почему так, не понимаю
Потому что в z-буфере сначала идут topmost-окна, затем обычные окна. Если ваше окно обычное, то оно будет помещено первым после topmost-окон и GW_HWNDNEXT вернёт следующее "обычное" окно. Если ваше окно имеет стиль WS_EX_TOPMOST, то оно будет помещено в самое начало z-буфера и для него следующим будет topmost-окно, т.е. кнопка "Пуск". http://www.transl-gunsmoker.ru/2012/04/windows.html#zorder

Русское сообщество AutoIt

Re: Как найти дескриптор предыдущего активного окна
« Ответ #14 Отправлен: Июнь 10, 2015, 16:15:41 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
2 Ответов
3094 Просмотров
Последний ответ Ноябрь 16, 2009, 13:58:03
от Suppir
48 Ответов
19537 Просмотров
Последний ответ Февраль 09, 2012, 01:02:52
от CreatoR
0 Ответов
1938 Просмотров
Последний ответ Июль 13, 2012, 16:58:47
от nu3dell
0 Ответов
2473 Просмотров
Последний ответ Январь 07, 2013, 16:14:03
от Акомыш
4 Ответов
2705 Просмотров
Последний ответ Февраль 02, 2013, 23:20:45
от Zaramot
8 Ответов
3237 Просмотров
Последний ответ Июнь 02, 2014, 18:09:32
от bistriy
14 Ответов
9721 Просмотров
Последний ответ Август 12, 2015, 13:27:07
от InnI
4 Ответов
1452 Просмотров
Последний ответ Июнь 20, 2016, 17:38:36
от Anna
7 Ответов
1178 Просмотров
Последний ответ Июнь 02, 2017, 06:38:45
от pvnn
4 Ответов
1013 Просмотров
Последний ответ Август 28, 2017, 11:06:05
от Zmy