Что нового

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

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 607
Репутация
2 437
Viktor1703 [?]
в чём минусы подключения второго обработчика сообщений окна
Хотя бы в том, что нельзя особо задерживаться в функций сообщения.
 
Автор
V

Viktor1703

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


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

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


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

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

CreatoR

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

Viktor1703

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

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 714
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 607
Репутация
2 437
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 714
Вопрос - зачем? И можно взглянуть на Dll?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 714
Ну да.
 
Автор
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 714
Я так и думал. Любой обработчик сообщений должен анализировать возвращаемые значения. Как вы думаете, для чего в AutoIt существует $GUI_RUNDEFMSG...
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1 535
Репутация
413
Малость не понял, в чём минус?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 714
Viktor1703 сказал(а):
Малость не понял, в чём минус?
Когда я получаю WM-сообщение, то у меня должен всегда быть выбор: либо вызвать умолчальный обработчик для данного окна, т.е. возвращаю $GUI_RUNDEFMSG, либо возвращаю любое другое значение, согласно MSDN для данного сообщения. У вас же всегда вызывается CallWindowProc() и не анализируется то значение, которое возвращает пользовательская функция.
 
Автор
V

Viktor1703

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

Yashied

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