- edited description
OnMessage: Not working in Keysharp or syntax unknown.
Working AHK code, modified from non-working example on docs page:
MyGui := Gui(, "Example Window")
MyGui.Add("Text",, "Click anywhere in this window.")
MyGui.Add("Edit", "w200")
MyGui.Show
OnMessage(0x0201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wParam, lParam, msg, hwnd)
{
X := lParam & 0xFFFF
Y := lParam >> 16
Control := ""
thisGui := GuiFromHwnd(hwnd)
thisGuiControl := GuiCtrlFromHwnd(hwnd)
if thisGuiControl
{
thisGui := thisGuiControl.Gui
Control := "`n(in control " . thisGuiControl.ClassNN . ")"
}
ToolTip("You left-clicked in Gui window '" thisGui.Title "' at client coordinates " X "x" Y "." Control ". `nHwnd is " MyGui.Hwnd)
}
SetWorkingDir(A_ScriptDir)
In Keysharp, OnMessage() apparently takes (string number, string function, string maxThreads). This requires guessing as to what to put for maxThreads, but I chose “1”. The code below throws no errors, but the function WM_LBUTTTONDOWN is not called.
MyGui := Gui(, "Example Window")
MyGui.Add("Text",, "Click anywhere in this window.")
MyGui.Add("Edit", "w200")
MyGui.Show()
OnMessage("0x0201", "WM_LBUTTONDOWN", "2")
WM_LBUTTONDOWN(wParam, lParam, msg, hwnd)
{
X := lParam & 0xFFFF
Y := lParam >> 16
Control := ""
thisGui := GuiFromHwnd(hwnd)
thisGuiControl := GuiCtrlFromHwnd(hwnd)
if (thisGuiControl)
{
thisGui := thisGuiControl.Gui
Control := "`n(in control " . thisGuiControl.ClassNN . ")"
}
ToolTip("You left-clicked in Gui window '" thisGui.Title "' at client coordinates " X "x" Y "." Control ". `nHwnd is " MyGui.Hwnd)
}
SetWorkingDir(A_ScriptDir)
I have also tried the following code without success, to make sure that nothing going on inside the function was causing the error.
WM_LBUTTONDOWN(wParam, lParam, msg, hwnd)
{
MsgBox("Message Received")
}
SetWorkingDir(A_ScriptDir)
Comments (14)
-
reporter -
reporter Note: In Keysharp OnMessage takes three strings:
public static void OnMessage(string number, string function, string maxThreads) { }
But two of those parameters will never be strings. Intentional? At any rate, it is not working at the moment.
-
repo owner I’ve made an initial commit which implements this. There are likely bugs and missing functionality. But the sample code with button down works in my testing.
A few notes/caveats:
The functionality with threading mentioned in the AHK documentation is not supported. The handlers are just called inline.
That means the third parameter only specifies where the handler is added using the usual handler rules (-1, 0, 1), not anything to do with threading.
I am not exactly sure how we’d do this, since we’re using real threads. It makes way more sense to me to just call the handlers inline. I am tempted to just leave it unless someone complains. It seems like a very obscure area of functionality. I am hoping threaded calls of custom message handlers is not something people really depend on.
-
reporter Continued testing with some success following commit, some issues remain.
This example works.
MyGui := Gui(, "Example Window") MyGui.Add("Text",, "Click anywhere in this window.") MyGui.Add("Edit", "w200") MyGui.Show() OnMessage(0x0201, "WM_LBUTTONDOWN") WM_LBUTTONDOWN(wParam, lParam, msg, hwnd) { X := lParam & 0xFFFF Y := lParam >> 16 Control := "" thisGui := GuiFromHwnd(hwnd) thisGuiControl := GuiCtrlFromHwnd(hwnd) if thisGuiControl { thisGui := thisGuiControl.Gui Control := "`n(in control " . thisGuiControl.ClassNN . ")" } ToolTip("You left-clicked in Gui window '" thisGui.Title "' at client coordinates " X "x" Y "." Control) }
To my surprise, it also works when the message number is passed as a string, i.e. 'OnMessage(“0x0201”, “WM_LBUTTONDOWN”)
I haven’t been able to successfully test other examples due to a (possible) bug with DetectHiddenWindows.
-
reporter 9/26/22 - testing following latest commits, but nothing new to report.
-
repo owner So what is the status of this? Are we considering it fixed? If not, please specify what still doesn’t work and provide an example script to test.
-
reporter Not fixed. Send/Receive scripts below, taken basically from Ex. 3 on the docs page for OnMessage().
Receiver script:
OnMessage(0x0555, "MsgMonitor") OnMessage(0x0556, "MsgMonitor") Persistent(True) MyGui := Gui() MyGui.Add("Text", "w200 h50", "Placeholder to make not hidden.") OSDText := MyGui.Add("Text", "w200 h50 x10 y+10", "You can be replaced!") MyGui.Show() MsgMonitor(wParam, lParam, msg, *) { ; Since returning quickly is often important, it is better to use ToolTip than ; something like MsgBox that would prevent the function from finishing: ToolTip("Message " msg " arrived:`nWPARAM: " wParam "`nLPARAM: " lParam) ;ControlSetText("Got " msg, "The treasure map") OSDText.Text := "Got message " msg }
Sender script.
DetectHiddenWindows(True) ^!]:: { DetectHiddenWindows(True) if (WinExist("Receiver2KS.ahk")) { MsgBox("It exists") PostMessage("0xFF55", 11, 22) ; The message is sent to the "last found window" due to WinExist above. DetectHiddenWindows(False) ; Must not be turned off until after PostMessage. } else { MsgBox("Darn, I can't find the window to send a message to!") } }
First run receiver, then sender. Trigger sending with the hotkey shows that the receiver exists, but no tooltip displays.
-
reporter Larger and completely non-working send/receive w/OnMessage(). As we have discussed on Discord, the function called by receipt of OnMessage() takes 4 params, wparam, lparam, msg, hwnd, all of which can be omitted in the proper fashion with '*'. WPARAM and LPARAM are unsigned 32-bit integers. Keysharp does not have StrPtr to provide an address for a string, so the examples are both AHK.
Receiver:
#SingleInstance OnMessage(0x004A, "Receive_WM_COPYDATA") ; 0x004A is WM_COPYDATA Persistent(True) Receive_WM_COPYDATA(wParam, lParam, msg, hwnd) { StringAddress := NumGet(lParam, 2*A_PtrSize, "Ptr") ; Retrieves the CopyDataStruct's lpData member. CopyOfData := StrGet(StringAddress) ; Copy the string out of the structure. ; Show it with ToolTip vs. MsgBox so we can return in a timely fashion: ToolTip(A_ScriptName "`nReceived the following string:`n" CopyOfData) return True ; Returning 1 (true) is the traditional way to acknowledge this message. }
(Here I obviously can’t get a string address. Passing the string won’t work, wparam and lparam have to be integers.)
Sender:
TargetScriptTitle := "ReceiverKS.ahk ahk_class AutoHotkey" #space:: ; Win+Space hotkey. Press it to show an input box for entry of a message string. { ib := InputBox("Enter some text to Send:", "Send text via WM_COPYDATA") if (ib.Result = "Cancel") ; User pressed the Cancel button. return result := Send_WM_COPYDATA(ib.Value, TargetScriptTitle) MsgBox("result is " result) if (result = "") MsgBox("SendMessage failed or timed out. Does the following WinTitle exist?:`n" TargetScriptTitle) else if (result = 0) MsgBox("Message sent but the target window responded with 0, which may mean it ignored it.") else MsgBox("Nothing happened!") } Send_WM_COPYDATA(StringToSend, TargetScriptTitle) ; This function sends the specified string to the specified window and returns the reply. ; The reply is 1 if the target window processed the message, or 0 if it ignored it. { CopyDataStruct := Buffer(3*A_PtrSize) ; Set up the structure's memory area. ; First set the structure's cbData member to the size of the string, including its zero terminator: SizeInBytes := (StrLen(StringToSend) + 1) * 2 NumPut( "Ptr", SizeInBytes ; OS requires that this be done. , "Ptr", StrPtr(StringToSend) ; Set lpData to point to the string itself. , CopyDataStruct, A_PtrSize) Prev_DetectHiddenWindows := A_DetectHiddenWindows Prev_TitleMatchMode := A_TitleMatchMode DetectHiddenWindows(True) SetTitleMatchMode 2 TimeOutTime := 4000 ; Optional. Milliseconds to wait for response from receiver.ahk. Default is 5000 ; Must use SendMessage not PostMessage. RetValue := SendMessage(0x004A, 0, CopyDataStruct,, TargetScriptTitle,,,, TimeOutTime) ; 0x004A is WM_COPYDATA. DetectHiddenWindows(Prev_DetectHiddenWindows) ; Restore original setting for the caller. SetTitleMatchMode(Prev_TitleMatchMode) ; Same. return RetValue ; Return SendMessage's reply back to our caller. }
I don’t know how to convert the CopyDataStruct assignment and the NumPut call into something that will pass a string.
-
reporter This is not a GUI-only issue. OnMessage, PostMessage and SendMessage are often used when there is no AHK GUI created at all.
-
repo owner I’ve committed a fix, here are a few points.
- In PostMessage(), you are sending the value as a string. Send it as a number.
2. Also, you are trying to send 0xFF55, but you are listening to 0x0555 and 0x556. If those are what you are listening to, then at least one of those is what you should be sending.
To toggle between the two, try this function.
b := true
^!]::
{
global b
DetectHiddenWindows(True)
if (WinExist("assign.ahk")) {
MsgBox("It exists")
PostMessage(b ? 0x0555 : 0x0556, 11, 22) ; The message is sent to the "last found window" due to WinExist above.
DetectHiddenWindows(False) ; Must not be turned off until after PostMessage.
b := !b
}
else {
MsgBox("Darn, I can't find the window to send a message to!")
}
}
3) This appears not to work when the receiving window is minimized. Please verify you are experiencing the same, then let’s decide how it should be working.
4) I changed a very important function that is used when calling any events of methods on objects. So please do a good run through of your existing tests to make sure everything still works. My unit tests are still working fine on my end.
5) The fix included severe bugs in PostMessage() and SendMessage() which should be good now.
-
reporter Thanks very much. All the tests in guitest.ahk still work. Your code is a better test. For reference, here are what I have that work, as Sender2KS.ahk and Receiver2KS.ahk.
Sender2KS.ahk:
SetTitleMatchMode(2) DetectHiddenWindows(True) b := true ^!]:: { global b DetectHiddenWindows(True) if (WinExist("Receiver2KS.ahk")) { PostMessage(b ? 0x0555 : 0x0556, 11, 22) ; The message is sent to the "last found window" due to WinExist above. DetectHiddenWindows(False) ; Must not be turned off until after PostMessage. b := !b } else { MsgBox("Darn, I can't find the window to send a message to!") } }
Receiver2KS.ahk
OnMessage(0x0555, "MsgMonitor") OnMessage(0x0556, "MsgMonitor") Persistent(True) MyGui := Gui() MyGui.Add("Text", "w200 h50", "Placeholder to make not hidden.") OSDText := MyGui.Add("Text", "w200 h50 x10 y+10", "You can be replaced!") MyGui.Show() MsgMonitor(wParam, lParam, msg, *) { ToolTip("Message: 0x" Format("{1:X}", msg) " arrived:`nWPARAM: " wParam "`nLPARAM: " lParam) }
N.B: *As you indicated, this does not work when minimized, and the MsgBox for failure in SenderKS.ahk never shows.*
-
reporter Resolved - SendMessage() can now send text, thank you!
-
reporter - changed status to resolved
-
reporter - changed status to closed
- Log in to comment