Что нового

Как найти дескриптор предыдущего активного окна

Cornet

Знающий
Сообщения
41
Репутация
6
При запуске скрипта нужно узнать какое приложение было активно. Уже всю голову поломал себе. Помогите, пожалуйста.
 
Автор
C

Cornet

Знающий
Сообщения
41
Репутация
6
Оказывается не до конца локализовал проблему.
Запуск программы происходит из панели задач (закрепленной ссылкой, Windows 7).
Код:
WinGetHandle("[active]")
возвращает 0x0000000000000000
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
См. пример в справке к функции
Код:
WinList()
Первой будет кнопка "Пуск", а все следующие окна будут перечислены в порядке их предыдущей активности.
 
Автор
C

Cornet

Знающий
Сообщения
41
Репутация
6
Спасибо, InnI.
Переписал пример из справки, вдруг кому ни будь понадобится
Код:
#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" — будет выдавать дескриптор верхнего из них. Мне не критично. Но если есть идеи как правильнее определять последнее активное, с удовольствием послушаю.
 

firex

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

Если вы собираетесь игнорировать подобные окна, то можете банально "пропускать" их:
Код:
#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
 
Автор
C

Cornet

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

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Cornet [?]
Но ведь <Alt+Tab> прекрасно помнит порядок последних окон, несмотря на флаг $WS_EX_TOPMOST
У меня, как и следовало ожидать, порядок идентичен положению в Z-Order.

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

Cornet

Знающий
Сообщения
41
Репутация
6
Может быть и путаю.
Но тогда я не понимаю функции WinActivate. Вот пример:
Код:
#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 Гуру
Сообщения
4,912
Репутация
1,429
Cornet
Описанное вами поведение наблюдается на Win81. На Win7 и WinXP порядок окон в панели переключения Alt+Tab полностью соответствует Z-буферу, т.е. сначала идут topmost-окна, затем все остальные. Возможно, на Win8 происходит дополнительное отслеживание порядка активности окон, что и приводит к последовательному переключению не зависимо от наличия стиля WS_EX_TOPMOST. Кстати, альтернативное переключение по Alt+ESC вообще не затрагивает topmost-окна ни на Win7 ни на Win8.
 
Автор
C

Cornet

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

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Cornet,
На Win8(1) проверить не могу, но на Win7 32 у меня работает такая функция.
Код:
#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
Репутация
208
madmasles
Тот же принцип Z-Order, пробуйте на примере TopMost.


Добавлено:
Сообщение автоматически объединено:

InnI [?]
Кстати, альтернативное переключение по Alt+ESC вообще не затрагивает topmost-окна ни на Win7 ни на Win8.
Оно их попросту игнорирует. Переключение происходит только путем отправки на дно Z-Order активного окна.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
firex [?]
Тот же принцип Z-Order, пробуйте на примере TopMost.
Интересно, если в скрипте не создавать окно с $WS_EX_TOPMOST, то функция отрабатывает правильно.
Сначала запускаю отдельный код
Код:
#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 этот
Код:
#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 Гуру
Сообщения
4,912
Репутация
1,429
madmasles
Почему так, не понимаю
Потому что в z-буфере сначала идут topmost-окна, затем обычные окна. Если ваше окно обычное, то оно будет помещено первым после topmost-окон и GW_HWNDNEXT вернёт следующее "обычное" окно. Если ваше окно имеет стиль WS_EX_TOPMOST, то оно будет помещено в самое начало z-буфера и для него следующим будет topmost-окно, т.е. кнопка "Пуск". http://www.transl-gunsmoker.ru/2012/04/windows.html#zorder
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
madmasles
в первом примере возвращает SciTE
Я не совсем понял, чей первый пример вы имеете в виду.
Если свой, то для окна GUI предыдущим будет окно SciTE, т.к. скрипт из него запускался.
Если Cornet, то он кнопку пуск "не считает"
Код:
... And $aList[$i][0] <> "Пуск" Then ...
 
Верх