Что нового

Второй обработчик сообщений окна

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Хотелось бы знать в чём минусы подключения второго обработчика сообщений окна, и актуально ли его использование?

Кликаем по окну:
ПКМ - создает окно.
ЛКМ - удаляет окно.

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#Include <APIConstants.au3>

OnAutoItExitRegister("CloseMSG")

Global $hMenu

$hForm = GUICreate("", 300, 200, -1, -1)
GUISetState()

$pEvent = DllCallbackRegister("WinMSG", "ptr", "hwnd;uint;wparam;lparam")
$hProc = _WinAPI_SetWindowLong($hForm, $GWL_WNDPROC, DllCallbackGetPtr($pEvent))

While 1  
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit			
    EndSwitch
WEnd
	
Func WinMSG($hWnd, $iMsg, $wParam, $lParam)
	Switch $iMsg
		Case $WM_RBUTTONDOWN
			If $hMenu Then
				GUIDelete($hMenu)
			EndIf	
			$iMouse = MouseGetPos()
			$hMenu = GUICreate("", 150, 100, $iMouse[0], $iMouse[1], $WS_POPUP, -1, $hWnd)
			$Pic = GUICtrlCreatePic('', 0, 0, 150, 100)
            $hPic = GUICtrlGetHandle($Pic)
		    $hDC = _WinAPI_GetDC($hPic)
			$hDestDC = _WinAPI_CreateCompatibleDC($hDC)
            $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, 150, 100)
            $hDestSv = _WinAPI_SelectObject($hDestDC, $hBitmap)
			Dim $aVertex[2][3] = [[0, 0, 0x7FC9FF], [150, 100, 0x005C9E]]
			_WinAPI_GradientFill($hDestDC, $aVertex, 0, 2)
            _WinAPI_ReleaseDC($hPic, $hDC)
            _WinAPI_SelectObject($hDestDC, $hDestSv)
            _WinAPI_DeleteDC($hDestDC)
			_SendMessage($hPic, 0x0172, 0, $hBitmap)
            $hObj = _SendMessage($hPic, 0x0173)
            If $hObj <> $hBitmap Then
	            _WinAPI_DeleteObject($hBitmap)
            EndIf
			$Ret = DllCall("gdi32.dll", "long", "CreateRoundRectRgn", "long", 0, "long", 0, "long", 150, "long", 100, "long", 16, "long", 16) 
	        DllCall("user32.dll", "long", "SetWindowRgn", "hwnd", $hMenu, "long", $Ret[0], "int", 1)
			DllCall('User32.dll', 'long', 'AnimateWindow', 'hwnd', $hMenu, 'long', 1000, 'long', $AW_BLEND)
			GUISetState()	
			WinActivate($hWnd)
		Case $WM_LBUTTONDOWN
			GUIDelete($hMenu)	
	EndSwitch	
	Return _WinAPI_CallWindowProc($hProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc	

Func CloseMSG()
	_WinAPI_SetWindowLong($hForm, $GWL_WNDPROC, $hProc)
    DllCallbackFree($pEvent)
	GUIDelete()
EndFunc
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Разве ни кто не делал такие конструкции, или не сталкивался с ней?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,659
Репутация
2,457
Viktor1703 [?]
в чём минусы подключения второго обработчика сообщений окна
Хотя бы в том, что нельзя особо задерживаться в функций сообщения.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
нельзя особо задерживаться

В каком смысле? можно по подробнее?


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

Понял, протестировал с MsgBox'ами


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

Тогда придётся мою затею переносить на другой ЯП и делать в виде dll...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,659
Репутация
2,457
Viktor1703 [?]
Тогда придётся мою затею переносить на другой ЯП и делать в виде dll...
А в чём принципиальность использования обработчика сообщений?
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Хотел скиновое контекстное меню написать, да и не только контекстное
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Viktor1703, вы должны понять одно, AutoIt не является компилятором, и поэтому в нем нет прямой адресации, т.е. мы не можем написать

Код:
_WinAPI_SetWindowLong($hForm, $GWL_WNDPROC, @WinMSG)

DllCallbackRegister() является сама по себе довольно медленная, и ее нужно использовать с умом. В некоторых случаях я тоже пишу DLL на других ЯП, если DllCallbackRegister() совсем уж не подходит (например для subclassing'а ListView или TreeView). Кстати, я посоветовал бы вам использовать _WinAPI_SetWindowSubclass() вместо _WinAPI_SetWindowLong().

Да, конечно вы можете делать так, как сделали, но если окно будет не пустым, то непременно возникнут глюки. А использование MsgBox() в любом обработчике на любом ЯП противопоказано.
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,575
Репутация
335
Если мне не изменяет память, то MsgBox в любом ЯП приостанавливает программу, если оно конечно не запущено в отдельном потоке.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Всем спасибо, много полезной информации узнал. :smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,659
Репутация
2,457
Medic84 [?]
MsgBox в любом ЯП приостанавливает программу
Речь не о приостановке, а о зависании, т.е обработчик событий должен обработать сообщение и как можно быстрее завершить свою работу, без лишних нагрузок.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Решил попробывать сделать обработчик через dll

Код:
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#include <WinAPIEx.au3>

Global $Dll = DllOpen(@ScriptDir & '\MsgEvent.dll')

$hForm = GUICreate('', 300, 200)
$Button = GUICtrlCreateButton('', 20, 20, 80, 20)
GUISetState()

$pPoint = RegisterFunction('MsgEvent')
GetWindowMsg($hForm, $pPoint)
RegisterWindowMsg($WM_COMMAND)
RegisterWindowMsg($WM_PAINT)

While 1
    Switch GUIGetMsg()
		Case -3
			FreeFunction($pPoint)
			Exit
	EndSwitch
WEnd

Func MsgEvent($hWnd, $iMsg, $wParam, $lParam)
	Switch $iMsg
		Case $WM_PAINT
	        ConsoleWrite('PAINT' & @CRLF)
		Case $WM_COMMAND
			If $lParam = GUICtrlGetHandle($Button) Then
			    MsgBox(0, '', 'Нажали на кнопку')
			EndIf
	EndSwitch
EndFunc

Func RegisterFunction($Function)
	Return DllCallbackRegister($Function, 'lresult', 'hwnd;uint;wparam;lparam')
EndFunc

Func GetWindowMsg($hWnd, $pFunction)
    DllCall($Dll, 'none', 'GetWindowMsg', 'hwnd', $hWnd, 'ptr', DllCallbackGetPtr($pFunction))
EndFunc

Func RegisterWindowMsg($Message)
	DllCall($Dll, 'none', 'RegisterWindowMsg', 'uint', $Message)
EndFunc

Func FreeFunction($pFunction)
	DllCallbackFree($pFunction)
EndFunc


Если нужно могу продолжить развитие...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Вопрос - зачем? И можно взглянуть на Dll?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Код:
Global Func, Dim Message(1)

Procedure WindowCallback(hWnd, Msg, wParam, lParam) 
  Shared *WindowProc
  For i = 0 To ArraySize(Message())
    If Msg = Message(i)
       CallFunctionFast(Func, hWnd, Msg, wParam, lParam)
    EndIf 
  Next   
  ProcedureReturn CallWindowProc_(*WindowProc, hWnd, Msg, wParam, lParam) 
EndProcedure

ProcedureDLL GetWindowMsg(hWnd, *Pointer)
  Shared *WindowProc
  Func = *Pointer
  If *WindowProc=0
    *WindowProc = SetWindowLong_(hWnd, #GWL_WNDPROC, @WindowCallback())
  EndIf 
EndProcedure

ProcedureDLL RegisterWindowMsg(Msg)
  ReDim Message(ArraySize(Message()) + 1)
  Message(ArraySize(Message())) = Msg
EndProcedure
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Я так и думал. Любой обработчик сообщений должен анализировать возвращаемые значения. Как вы думаете, для чего в AutoIt существует $GUI_RUNDEFMSG...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Viktor1703 сказал(а):
Малость не понял, в чём минус?

Когда я получаю WM-сообщение, то у меня должен всегда быть выбор: либо вызвать умолчальный обработчик для данного окна, т.е. возвращаю $GUI_RUNDEFMSG, либо возвращаю любое другое значение, согласно MSDN для данного сообщения. У вас же всегда вызывается CallWindowProc() и не анализируется то значение, которое возвращает пользовательская функция.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Я думал как лучше сделать, но не нашёл решения, по этому сделал так, на форуме по PureBasic спрашивать не хотел как лучше это сделать, там не приветливые какие-то люди, ещё раз убеждаюсь что 'Русское сообщество AutoIt' лучше любого другого. Но как тогда быть? или оставить мысль на счёт 2го обработчика?
 

Yashied

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