Что нового

Как обрабатывать события "своего" меню в чужом окне?

asdf8

Скриптер
Сообщения
564
Репутация
152
Вопрос в названии темы

Код:
#include <GuiMenu.au3>
Global $idExit, $idCut, $idCopy, $idPaste

Run("Notepad.exe")
WinWaitActive("[CLASS:Notepad]")

If WinExists("[CLASS:Notepad]") Then
	$handle = WinGetHandle("[CLASS:Notepad]")
	; Create Edit menu
	$hEdit = _GUICtrlMenu_CreateMenu ()
	_GUICtrlMenu_InsertMenuItem ($hEdit, 0, "&Cut", $idCut)
	_GUICtrlMenu_InsertMenuItem ($hEdit, 1, "C&opy", $idCopy)
	_GUICtrlMenu_InsertMenuItem ($hEdit, 2, "&Paste", $idPaste)
	_GUICtrlMenu_InsertMenuItem ($hEdit, 3, "", 0)
	_GUICtrlMenu_InsertMenuItem ($hEdit, 4, "E&xit", $idExit)
	; Get Main menu
	$hMain = _GUICtrlMenu_GetMenu($handle)
	$ItemCount = _GUICtrlMenu_GetItemCount($hMain)
	_GUICtrlMenu_InsertMenuItem ($hMain, $ItemCount, "&Insert", 0, $hEdit)
	; Set window menu
	_GUICtrlMenu_SetMenu ($handle, $hMain)

	While WinExists($handle)
		Sleep(10)
	WEnd
EndIf
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
По идее так:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIMenu.au3>

Opt("GUIOnEventMode", 1)

Run(@WindowsDir & "\Notepad.exe")
WinWaitActive("[REGEXPCLASS:.*Notepad.*]")

$hWindow = WinGetHandle("[REGEXPCLASS:.*Notepad.*]")

; The User IDs for the commands
Global Enum $iTaskMan = 1000, $iExit

$hMainMenu = _GUICtrlMenu_GetMenu($hWindow)

; Create menu
$hItemsMenu = _GUICtrlMenu_CreateMenu()

_GUICtrlMenu_InsertMenuItem($hItemsMenu, -1, "Task Manager", $iTaskMan)
_GUICtrlMenu_InsertMenuItem($hItemsMenu, -1, "")
_GUICtrlMenu_InsertMenuItem($hItemsMenu, -1, "Exit", $iExit)

_GUICtrlMenu_InsertMenuItem($hMainMenu, 2, "&AutoIt", 0, $hItemsMenu)
_GUICtrlMenu_DrawMenuBar($hWindow)

GUICreate("DummyGUI")
$DummyMenu = GUICtrlCreateDummy() ; Translates Command to action
GUICtrlSetOnEvent(-1, "_Main_Events")
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; receives Command

While WinExists($hWindow)
	Sleep(100)
WEnd

Func _Main_Events()
	Switch @GUI_CtrlId
		Case $GUI_EVENT_CLOSE
			Exit
		Case $DummyMenu
			_Menu_Events(GUICtrlRead($DummyMenu))
	EndSwitch
EndFunc

Func _Menu_Events($iBTN_ID)
	Switch $iBTN_ID
		Case $iExit
			MsgBox(64, '', "You clicked Exit, so... i will exit now :)", 3, $hWindow)
			Exit
		Case $iTaskMan
			Run("Taskmgr.exe")
	EndSwitch
EndFunc

Func WM_COMMAND($hWndGUI, $MsgID, $wParam, $lParam)
	If $wParam >= 0xF000 And $wParam < 0xF200 Then
		Return $GUI_RUNDEFMSG ; This are the normal commands
	EndIf
	
	GUICtrlSendToDummy($DummyMenu, $wParam)
	
	Return $GUI_RUNDEFMSG
EndFunc


Но оно видимо во внешних приложениях не работает :(.
 
Автор
A

asdf8

Скриптер
Сообщения
564
Репутация
152
Да, во внешних приложениях не очень работает.
Видимо придется изучать хуки.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
asdf8 сказал(а):
Да, во внешних приложениях не очень работает.
Видимо придется изучать хуки.

Здесь главное вовремя остановиться и хорошо подумать, а оно вообще надо... Если и попытаться что-то подобное сваять, то кода будет на целый вагон. Да и глючить будет не по детски.

;D
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
а оно вообще надо
Надо, например для реализаций плагинов для своего же приложения! я когда с этим столкнулся, пришлось извращаться с интеракцией и с внутренним обработчиком меню по запросу с внешнего модуля (плагина).

кода будет на целый вагон
Я бы не отказался посмотртеть на этот вагон :whistle:
 
Автор
A

asdf8

Скриптер
Сообщения
564
Репутация
152
[?]
Цитата сказал(а):
Я бы не отказался посмотртеть на этот вагон

нашел на оффоруме:

Код:
#include <GuiMenu.au3>
#include <WindowsConstants.au3>
#include "WinEventHook.au3"
HotKeySet('{ESC}', '_EXIT')
;~ If Not IsDeclared("WM_LBUTTONDOWN") Then Global Const $WM_LBUTTONDOWN = 0x0201

Global Const $tagMSLLHOOKSTRUCT = $tagPOINT & ";uint mouseData;uint flags;uint time;uint_ptr dwExtraInfo;"
Global Const $w00t = 0x8765
Global $hHookFunc, $hMouseFunc, $pFunc
Global $hWinHook, $hMouseHook
Global $hgMenu

$hMouseFunc = DllCallbackRegister("_MouseHook", "int", "int;wparam;lparam")
$pFunc = DllCallbackGetPtr($hMouseFunc)
$hMouseHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pFunc, _WinAPI_GetModuleHandle(0))

$hHookFunc = DllCallbackRegister('_WinEventProc', 'none', 'ptr;uint;hwnd;int;int;uint;uint')
$pFunc = DllCallbackGetPtr($hHookFunc)

$hWinHook = _SetWinEventHook($EVENT_MIN, $EVENT_MAX, 0, $pFunc, 0, 0, _
                BitOR($WINEVENT_SKIPOWNPROCESS, $WINEVENT_OUTOFCONTEXT))
                
If $hWinHook = 0 Then Exit MsgBox(0x10, 'Error', 'Could not register callback procedure')

While 1
    Sleep(20)
WEnd

Func _EXIT()
    Exit
EndFunc

Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hMouseHook)
    DllCallbackFree($hMouseFunc)
    _UnhookWinEvent($hWinHook)
    DllCallbackFree($hHookFunc)
EndFunc

Func _WinEventProc($hHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $imsEventTime)
    Local $hMenu
    
    If $iEvent =  $EVENT_SYSTEM_MENUPOPUPSTART Then
        $hMenu = _SendMessage($hWnd, 0x01E1)
        $hgMenu = $hMenu
        If _GUICtrlMenu_IsMenu($hMenu) Then
            _GUICtrlMenu_InsertMenuItem($hMenu, _GUICtrlMenu_GetItemCount($hMenu), "w00t", $w00t)
        EndIf
        
    ElseIf $iEvent = $EVENT_SYSTEM_MENUPOPUPEND Then
        $hgMenu = 0
    EndIf
EndFunc

Func _MouseHook($iCode, $iwParam, $ilParam)
    Local $tMouseInfo
    
    If $iCode >= 0 Then
        If $hgMenu And $iwParam = $WM_LBUTTONDOWN Then
            If _GUICtrlMenu_GetItemHighlighted($hgMenu, $w00t, False) Then ConsoleWrite("W00t :)" & @CRLF)
        EndIf
    EndIf

    Return _WinAPI_CallNextHookEx($hMouseHook, $iCode, $iwParam, $ilParam)
EndFunc


WinEventHook.au3:
Код:
Global Const $EVENT_MIN = 0x00000001
Global Const $EVENT_MAX = 0x7FFFFFFF

Global Const $WINEVENT_OUTOFCONTEXT = 0x0000
Global Const $WINEVENT_SKIPOWNTHREAD = 0x0001
Global Const $WINEVENT_SKIPOWNPROCESS = 0x0002
Global Const $WINEVENT_INCONTEXT = 0x0004

Global Const $EVENT_SYSTEM_SOUND = 0x0001
Global Const $EVENT_SYSTEM_ALERT = 0x0002
Global Const $EVENT_SYSTEM_FOREGROUND = 0x0003
Global Const $EVENT_SYSTEM_MENUSTART = 0x0004
Global Const $EVENT_SYSTEM_MENUEND = 0x0005
Global Const $EVENT_SYSTEM_MENUPOPUPSTART = 0x0006
Global Const $EVENT_SYSTEM_MENUPOPUPEND = 0x0007
Global Const $EVENT_SYSTEM_CAPTURESTART = 0x0008
Global Const $EVENT_SYSTEM_CAPTUREEND = 0x0009
Global Const $EVENT_SYSTEM_MOVESIZESTART = 0x000A
Global Const $EVENT_SYSTEM_MOVESIZEEND = 0x000B
Global Const $EVENT_SYSTEM_CONTEXTHELPSTART = 0x000C
Global Const $EVENT_SYSTEM_CONTEXTHELPEND = 0x000D
Global Const $EVENT_SYSTEM_DRAGDROPSTART = 0x000E
Global Const $EVENT_SYSTEM_DRAGDROPEND = 0x000F
Global Const $EVENT_SYSTEM_DIALOGSTART = 0x0010
Global Const $EVENT_SYSTEM_DIALOGEND = 0x0011
Global Const $EVENT_SYSTEM_SCROLLINGSTART = 0x0012
Global Const $EVENT_SYSTEM_SCROLLINGEND = 0x0013
Global Const $EVENT_SYSTEM_SWITCHSTART = 0x0014
Global Const $EVENT_SYSTEM_SWITCHEND = 0x0015
Global Const $EVENT_SYSTEM_MINIMIZESTART = 0x0016
Global Const $EVENT_SYSTEM_MINIMIZEEND = 0x0017
Global Const $EVENT_OBJECT_CREATE = 0x8000
Global Const $EVENT_OBJECT_DESTROY = 0x8001
Global Const $EVENT_OBJECT_SHOW = 0x8002
Global Const $EVENT_OBJECT_HIDE = 0x8003
Global Const $EVENT_OBJECT_REORDER = 0x8004
Global Const $EVENT_OBJECT_FOCUS = 0x8005
Global Const $EVENT_OBJECT_SELECTION = 0x8006
Global Const $EVENT_OBJECT_SELECTIONADD = 0x8007
Global Const $EVENT_OBJECT_SELECTIONREMOVE = 0x8008
Global Const $EVENT_OBJECT_SELECTIONWITHIN = 0x8009
Global Const $EVENT_OBJECT_STATECHANGE = 0x800A
Global Const $EVENT_OBJECT_LOCATIONCHANGE = 0x800B
Global Const $EVENT_OBJECT_NAMECHANGE = 0x800C
Global Const $EVENT_OBJECT_DESCRIPTIONCHANGE = 0x800D
Global Const $EVENT_OBJECT_VALUECHANGE = 0x800E
Global Const $EVENT_OBJECT_PARENTCHANGE = 0x800F
Global Const $EVENT_OBJECT_HELPCHANGE = 0x8010
Global Const $EVENT_OBJECT_DEFACTIONCHANGE = 0x8011
Global Const $EVENT_OBJECT_ACCELERATORCHANGE = 0x8012

Global Const $OBJID_WINDOW = 0
;~ Global Const $OBJID_SYSMENU = 0xFFFFFFFF
Global Const $OBJID_TITLEBAR = 0xFFFFFFFE
;~ Global Const $OBJID_MENU = 0xFFFFFFFD
Global Const $OBJID_CLIENT = 0xFFFFFFFC
Global Const $OBJID_VSCROLL = 0xFFFFFFFB
Global Const $OBJID_HSCROLL = 0xFFFFFFFA
Global Const $OBJID_SIZEGRIP = 0xFFFFFFF9
Global Const $OBJID_CARET = 0xFFFFFFF8
Global Const $OBJID_CURSOR = 0xFFFFFFF7
Global Const $OBJID_ALERT = 0xFFFFFFF6
Global Const $OBJID_SOUND = 0xFFFFFFF5
Global Const $OBJID_QUERYCLASSNAMEIDX = 0xFFFFFFF4
Global Const $OBJID_NATIVEOM = 0xFFFFFFF0


Func _SetWinEventHook($ieventMin, $ieventMax, $hMod, $pCallback, $iProcID, $iThreadID, $iFlags)
	Local $aRet
	
	$aRet = DllCall('user32.dll', 'ptr', 'SetWinEventHook', 'uint', $ieventMin, 'uint', $ieventMax, _
				'hwnd', $hMod, 'ptr', $pCallback, 'dword', $iProcID, 'dword', $iThreadID, 'uint', $iFlags)
	
	If @error Or $aRet[0] = 0 Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc

Func _UnhookWinEvent($hWinEventHook)
	Local $aRet
	
	$aRet = DllCall('user32.dll', 'int', 'UnhookWinEvent', 'ptr', $hWinEventHook)
	If @error Or $aRet[0] = 0 Then Return SetError(1, 0, 0)
	Return $aRet[0]
EndFunc


но, пока, ничего не пойму в этом
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Re: Как обрабатывать события \"своего\" меню в чужом окне?

Только сюда еще нужно добавить удаление созданного ранее пункта меню + хук на клавиатуру, на случай работы через оную. Итог: три хука (а может быть и больше) на "псевдо" dll через AutoIt.

:zorro:


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

CreatoR сказал(а):
Надо, например для реализаций плагинов для своего же приложения! я когда с этим столкнулся, пришлось извращаться с интеракцией и с внутренним обработчиком меню по запросу с внешнего модуля (плагина).

Это самый правильный вариант (я бы именно так и сделал). Через WM_COPYDATA это не проблема. Кстати, 3D Aixs использует это по полной (сообщения посылаются в обе стороны). И никаких глюков пока не было.

Например, "плагин" посылает в программу через WM_COPYDATA команду на создание дополнительного пункта меню + хендл своего окна, ответ - OK или не OK. При выборе этого пункта в основной программе, она посылает обратно команду, что пункт меню был активирован. Здесь еще удобно контролировать состояние обоих окон. А ставить хуки для своего собственного приложения, это IMHO полное извращение. В своей программе все должно реализовываться через WM_* сообщения. Исключением могут быть только UDF, которые обычно пишуться как универсальное средство.
 

HukpoFuJl

AццkuЙ HukpoFuJl
Сообщения
98
Репутация
38
Эмм, похожая ситуация, решил новую тему не создавать: Есть стороннее приложение, в приложении кнопка, нужно отлавливать и обрабатывать клик по этой кнопке. Это возможно? Если да - то как? В теории я понимаю как это сделать, т.е. отлавливать клики мыши, если клик = хэнду контрола - то обрабатывать... Но хотелось бы посмотреть на живой пример... Ну хотя бы например, код:
Код:
#include <GUIConstantsEx.au3>
$Form1 = GUICreate("Form1", 251, 117, 367, 124)
$Button1 = GUICtrlCreateButton("Button1", 64, 32, 137, 49)
GUISetState(@SW_SHOW)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
	Sleep(100)
WEnd
Компилим, получаем окошко с кнопкой, вот сделать отдельный скрипт, который будет отлавливать нажатие этой кнопки и высвечивать MsgBox

Зарание спасибо
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481

HukpoFuJl

AццkuЙ HukpoFuJl
Сообщения
98
Репутация
38
CreatoR сказал(а):
HukpoFuJl [?]
похожая ситуация, решил новую тему не создавать
Ни тему создавать не нужно, и тут писать не нужно. А нужно немного поискать: WinControlSetEvent - Обработка событии нажатия на элементы указанного окна
Спасиб =)) чесно, искать пытался, да вот видимо запрос писковой нормально сформулировать не смог =)
 
Верх