Что нового

GUICtrlSendToDummy для скрытых окон возможна замена на GUICtrlSendMsg?

Yashied

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

Создайте глобальную переменную-счетчик. После прихода сообщения WM_COPYDATA функция-обработчик увеличивает счетчик сообщений на 1 и записывает данные сообщения куда-нибудь в очередь (если нужно). В основном цикле программы проверяется значение счетчика сообщений, и если оно не равно 0, то считывается (удаляется) сообщение из очереди и уменьшается значение счетчика на 1. Чтобы не заморачиваться с массивами, можно хранить сообщения в одной строке с разделителем, например, "|". Почему в строке? Потому что так намного проще и быстрее удалять из очереди первые сообщения. В случае массива пришлось бы передвигать все ячейки вверх после каждого удаления. Ну и естественно, удалять из очереди сообщения и изменять счетчик вне функции-обработчика нужно как можно быстрее. Вся обработка должна осуществляться уже после. Все это прекрасно работает в нескольких моих программах и библиотеках.

И еще один серьезный недостаток Dummy - отсутствие внутренней очереди и ограничение на передаваемые данные (вроде бы DWORD, но нужно проверить в справке). Таким образом, если вы собираетесь передавать бесконтрольные сообщения, то счетчик Dummy будет хранить все вызовы, а вот сами данные будут перезаписываться последним вызовом.

Если не хотите заморачиваться с организацией очереди (хотя, тут нет ничего сложного), то можно организовать передачу WM_COPYDATA с обратной связью, т.е. одна программа послала сообщение другой программе и ожидает от нее ответа для продолжения работы (следующего сообщения). Это избавляет от очереди и гарантирует обработку всех сообщений в реальном времени. Такой вариант хорошо подходит для визуализации прогресса работы другого процесса.

Вообщем, все зависит от конкретных задач.
 
Автор
inververs

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Yashied
Выяснилась другая особенность, если основной цикл занят обработкой какой ни будь функции, например копированием большого файла, то никакие другие функции параллельно не вызываются, и соответственно передатчик, в моем случае это GUI окошко, отсылая sendmessage, приостанавливается в ожидании.
А вся суть, сводилась к тому, что бы GUI не зависал ни при каких обстоятельствах.
Я думал сделать передачу через postmessage но тогда не срабатывают функции приемника WM_COPYDATA, я предполагаю, что бы отлавливать postmessage нужно в цикле прогонять GUIGetMsg(), но если так, и для этого дела нужен цикл, то это нарушает саму идею onevent сообщений. А это нужно для того, что бы, например, при нажатии в GUI стоп, выйти из какого нибудь внутреннего цикла.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Нет ничего невозможного. Распиши более подробно то, что будет делать твое чудо? :smile: Если же файл будет копироваться с помощью AutoIt'овских функций, то никакой onevent здесь не поможет. А для отлова сообщений от WM_COPYDATA можно использовать AdlibRegister(). Да и вообще, что именно должно передоваться посредством WM_COPYDATA? Да и нужно ли это вообще?

Копирование можно сделать с помощью этой библиотеки. Она позволяет копировать файлы и папки в отдельном потоке.
 
Автор
inververs

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Yashied
Есть два екзешника, первый это сам код, второй это графическая оболочка.
Соответственно нужна между ними связь. Подумалось, что первый екзешник, выполняя код, может "отвлекаться" от своей задачи словив windows сообщение, тут и подумалось насчет WM_COPYDATA. Нарисовал для первого екзешника скрытое окошко, повесил опцию
Opt('GUIOnEventMode', 1) и зарегистрировал GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')
Казалось бы, все отлично, GUI отсылает нашему скрипту сообщения, которые автоматически отлавливаются в функции WM_COPYDATA, всем хорошо, GUI никогда не зависнет. НО. Если первый екзешник выполняет тяжелые функции, или например вызывает функции в какой либо библиотеке, то GUI окно, не получив ответ на sendmessage продолжит висеть в ожидании ответа, а нужно этого избежать.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А что значит тяжелая функция? В любом случае, либо избавляйся от "тяжелых" функций (я так понимаю, что зависание происходит в момент выполнения функции из DLL), либо используй PostMessage().
 
Автор
inververs

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
не знаю как "отловить" postmessage
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
inververs сказал(а):
не знаю как "отловить" postmessage
Оно ничем не отличается от SendMessage(), только не требует ответа. Если сообщение посылается с помощью SendMessage(), то программу, которая посылает сообщение, не "отпустит" до тех пор, пока на другой стороне не завершится выполнение функции-обработчика. PostMessage() не ждет ответа и, соответственно, не возвращает результата. Сама функция реализована в WinAPI.au3.
 
Автор
inververs

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Код:
$Ret = DllCall('user32.dll', 'lparam', 'SendMessage', 'hwnd', $hWnd, 'int', $WM_COPYDATA, 'wparam', 0, 'lparam', DllStructGetPtr($tCOPYDATA))

Так сообщения отправляются/принимаются
А так нет
Код:
$Ret = DllCall("user32.dll", "bool", "PostMessage", "hwnd", $hWnd, "uint", $WM_COPYDATA, "wparam", 0, "lparam", DllStructGetPtr($tCOPYDATA))

всё отличие только в этих строчках


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

Приемник:
Код:
#include <WindowsConstants.au3>
Opt('GUIOnEventMode', 1)
Global Const $TITLE_RECEIVER = '#Reseiver'
GUICreate($TITLE_RECEIVER, 0, 0, -300, -300, -1, BitOR($WS_EX_TOOLWINDOW,$WS_EX_TRANSPARENT,$WS_EX_LAYERED)) ;524448
GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')
Func _WM_COPYDATA($hWnd, $msgID, $wParam, $lParam)
	Local $tCOPYDATA = DllStructCreate('dword;dword;ptr', $lParam)
	Local $tMsg = DllStructCreate('char[' & DllStructGetData($tCOPYDATA, 2) & ']', DllStructGetData($tCOPYDATA, 3))
	Local $sMsg = DllStructGetData($tMsg, 1)
	MsgBox(0,0,$sMsg,1)
EndFunc
While 1
	Sleep(250)
WEnd

Передатчик:
Код:
Global Const $WM_COPYDATA = 0x004A
Global Const $TITLE_RECEIVER = '#Reseiver'
Global $hWnd = WinGetHandle($TITLE_RECEIVER)
_SendData($hWnd, 'ТЕСТ')
Func _SendData($hWnd, $sData)
	Local $tCOPYDATA, $tMsg
	$tMsg = DllStructCreate('char[' & StringLen($sData) + 1 & ']')
	DllStructSetData($tMsg, 1, $sData)
	$tCOPYDATA = DllStructCreate('dword;dword;ptr')
	DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
	DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
	Local $Ret = DllCall('user32.dll', 'lparam', 'SendMessage', 'hwnd', $hWnd, 'int', $WM_COPYDATA, 'wparam', 0, 'lparam', DllStructGetPtr($tCOPYDATA))
;~ 	Local $Ret = DllCall("user32.dll", "bool", "PostMessage", "hwnd", $hWnd, "uint", $WM_COPYDATA, "wparam", 0, "lparam", DllStructGetPtr($tCOPYDATA))
	If (@error) Or ($Ret[0] = -1) Then
		Return 0
	EndIf
	Return 1
EndFunc   ;==>_SendData
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Да, действительно. Сейчас порылся в MSDN, и оказывается, что WM_COPYDATA нельзя передать посредством PostMessage(). Тогда остается только SendMessage().
 
Автор
inververs

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Через postmessage можно передавать WM_USER + , но тогда нельзя передать "строку" как сообщение... может есть идеи? :smile:
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
Это число, если строку передавать кодами букв то уместится несколько букв.
 
Верх