PageRenderTime 52ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/AutoHotkey.docset/Contents/Resources/Documents/commands/OnMessage.htm

https://gitlab.com/ahkscript/Autohotkey.docset
HTML | 241 lines | 208 code | 33 blank | 0 comment | 0 complexity | ba8d5dc7ae1806d13c1a2d76771f1efa MD5 | raw file
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>OnMessage</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <link href="../static/theme.css" rel="stylesheet" type="text/css" />
  8. <script src="../static/content.js" type="text/javascript"></script>
  9. </head>
  10. <body>
  11. <h1>OnMessage()</h1>
  12. <p>Specifies a <a href="../Functions.htm">function</a> or <a href="../objects/Functor.htm">function object</a> to call automatically when the script receives the specified message.</p>
  13. <pre class="Syntax">OnMessage(MsgNumber [, Function, MaxThreads])</pre>
  14. <h3>Parameters</h3>
  15. <dl>
  16. <dt>MsgNumber</dt>
  17. <dd><p>The number of the message to monitor or query, which should be between 0 and 4294967295 (0xFFFFFFFF). If you do not wish to monitor a <a href="../misc/SendMessageList.htm">system message</a> (that is, one below 0x400), it is best to choose a number greater than 4096 (0x1000) to the extent you have a choice. This reduces the chance of interfering with messages used internally by current and future versions of AutoHotkey.</p></dd>
  18. <dt>Function</dt>
  19. <dd><p>A <a href="../Functions.htm">function</a>'s name or, in <span class="ver">[v1.1.20+]</span>, a <a href="../objects/Functor.htm">function object</a>. To pass a literal function name, it must be enclosed in quotes.</p>
  20. <p>How the function is registered and the return value of OnMessage depend on whether this parameter is a string or a function object. See <a href="#Name_v_Object">Function Name vs Object</a> for details.</p>
  21. </dd>
  22. <dt id="MaxThreads">MaxThreads <span class="ver">[v1.0.47+]</span></dt>
  23. <dd><p>This integer is normally omitted, in which case the monitor function is limited to one <a href="../misc/Threads.htm">thread</a> at a time. This is usually best because otherwise, the script would process messages out of chronological order whenever the monitor function interrupts itself. Therefore, as an alternative to <em>MaxThreads</em>, consider using <em>Critical</em> as described <a href="#Critical">below</a>.</p>
  24. <p><span class="ver">[v1.1.20+]:</span> By default, when multiple functions are registered for a single <em>MsgNumber</em>, they are called in the order that they were registered. To register a function to be called before any previously registered functions, specify a negative value for <em>MaxThreads</em>. For example, <code>OnMessage(Msg, Fn, -2)</code> registers <code>Fn</code> to be called before any other functions previously registered for <em>Msg</em>, and allows <em>Fn</em> a maximum of 2 threads. However, if the function is already registered, the order will not change unless it is unregistered and then re-registered.</p></dd>
  25. </dl>
  26. <h3 id="Name_v_Object">Function Name vs Object</h3>
  27. <p>OnMessage's return value and behavior depends on whether the <em>Function</em> parameter is a function name or an object.</p>
  28. <h4>Function Name</h4>
  29. <p>For backward compatibility, at most one function can be registered by name to monitor each unique <em>MsgNumber</em> -- this is referred to as the "legacy" monitor.</p>
  30. <p>When the legacy monitor is first registered, whether it is called before or after previously registered monitors depends on the <em>MaxThreads</em> parameter. Updating the monitor to call a different function does not affect the order unless the monitor is unregistered first.</p>
  31. <p>This registers or updates the current legacy monitor for <em>MsgNumber</em> (omit the quote marks if passing a variable):</p>
  32. <pre class="Syntax">Name := OnMessage(MsgNumber, "FunctionName")</pre>
  33. <p>The return value is one of the following:</p>
  34. <ul>
  35. <li>An empty string on <a href="#Failure">failure</a>.</li>
  36. <li>The name of the previous function, if there was one.</li>
  37. <li>Otherwise, the name of the new function.</li>
  38. </ul>
  39. <p>This unregisters the current legacy monitor for <em>MsgNumber</em> (if any) and returns its name (blank if none):</p>
  40. <pre class="Syntax">Name := OnMessage(MsgNumber, "")</pre>
  41. <p>This returns the name of the current legacy monitor for <em>MsgNumber</em> (blank if none):</p>
  42. <pre class="Syntax">Name := OnMessage(MsgNumber)</pre>
  43. <h4>Function Object</h4>
  44. <p>Any number of <a href="../objects/Functor.htm">function objects</a> (including <a href="../objects/Func.htm">normal functions</a>) can monitor a given <em>MsgNumber</em>.</p>
  45. <p>Either of these two lines registers a function object to be called <strong>after</strong> any previously registered functions:</p>
  46. <pre class="Syntax">
  47. OnMessage(MsgNumber, FuncObj) <em>; Option 1</em>
  48. OnMessage(MsgNumber, FuncObj, 1) <em>; Option 2 (MaxThreads = 1)</em>
  49. </pre>
  50. <p>This registers a function object to be called <strong>before</strong> any previously registered functions:</p>
  51. <pre class="Syntax">OnMessage(MsgNumber, FuncObj, -1)</pre>
  52. <p>To unregister a function object, specify 0 for <em>MaxThreads</em>:</p>
  53. <pre class="Syntax">OnMessage(MsgNumber, FuncObj, 0)</pre>
  54. <h3 id="Failure">Failure</h3>
  55. <p>Failure occurs when <em>Function</em>:</p>
  56. <ol>
  57. <li>is not an object, the name of a user-defined function, or an empty string;</li>
  58. <li>is known to require more than four parameters; or</li>
  59. <li>in v1.0.48.05 or older, has any <a href="../Functions.htm#ByRef">ByRef</a> or <a href="../Functions.htm#optional">optional</a> parameters.</li>
  60. </ol>
  61. <p>In v1.1.19.03 or older, failure also occurs if the script attempts to monitor a new message when there are already 500 messages being monitored.</p>
  62. <p>If <em>Function</em> is an object, an exception is thrown on failure. Otherwise, an empty string is returned.</p>
  63. <h3>The Function's Parameters</h3>
  64. <p>A <a href="../Functions.htm">function</a> assigned to monitor one or more messages can accept up to four parameters:</p>
  65. <pre>MyMessageMonitor(wParam, lParam, msg, hwnd)
  66. {
  67. ... body of function...
  68. }</pre>
  69. <p>Although the names you give the parameters do not matter, the following information is sequentially assigned to them:</p>
  70. <p>Parameter #1: The message's WPARAM value.<br>
  71. Parameter #2: The message's LPARAM value.<br>
  72. Parameter #3: The message number, which is useful in cases where a function monitors more than one message.<br>
  73. Parameter #4: The HWND (unique ID) of the window or control to which the message was sent. The HWND can be used with <a href="../misc/WinTitle.htm#ahk_id">ahk_id</a>.</p>
  74. <p>WPARAM and LPARAM are unsigned 32-bit integers (from 0 to 2<sup>32</sup>-1) or signed 64-bit integers (from -2<sup>63</sup> to 2<sup>63</sup>-1) depending on whether the exe running the script is 32-bit or 64-bit. For 32-bit scripts, if an incoming parameter is intended to be a signed integer, any negative numbers can be revealed by following this example:</p>
  75. <pre>if (A_PtrSize = 4 &amp;&amp; wParam &gt; 0x7FFFFFFF) <em>; Checking <a href="../Variables.htm#PtrSize">A_PtrSize</a> ensures the script is 32-bit.</em>
  76. wParam := -(~wParam) - 1</pre>
  77. <p>You can omit one or more parameters from the end of the list if the corresponding information is not needed. For example, a function defined as <code>MyMsgMonitor(wParam, lParam)</code> would receive only the first two parameters, and one defined as <code>MyMsgMonitor()</code> would receive none of them.</p>
  78. <h3>Additional Information Available to the Function</h3>
  79. <p>In addition to the parameters received above, the function may also consult the values in the following built-in variables:</p>
  80. <ul>
  81. <li><a href="../Variables.htm#Gui">A_Gui</a>: Blank unless the message was sent to a GUI window or control, in which case A_Gui is the <a href="Gui.htm#MultiWin">Gui Window number</a> (this window is also set as the function's <a href="Gui.htm#DefaultWin">default GUI window</a>).</li>
  82. <li><a href="../Variables.htm#GuiControl">A_GuiControl</a>: Blank unless the message was sent to a GUI control, in which case it contains the control's variable name or other value as described at <a href="../Variables.htm#GuiControl">A_GuiControl</a>. Some controls never receive certain types of messages. For example, when the user clicks a <a href="GuiControls.htm#Text">text control</a>, the operating system sends WM_LBUTTONDOWN to the parent window rather than the control; consequently, A_GuiControl is blank.</li>
  83. <li><a href="../Variables.htm#GuiX">A_GuiX</a> and <a href="../Variables.htm#GuiY">A_GuiY</a>: Both contain -2147483648 if the incoming message was sent via <a href="PostMessage.htm">SendMessage</a>. If it was sent via <a href="PostMessage.htm">PostMessage</a>, they contain the mouse cursor's coordinates (relative to the screen) at the time the message was posted.</li>
  84. <li><a href="../Variables.htm#EventInfo">A_EventInfo</a>: Contains 0 if the message was sent via SendMessage. If sent via PostMessage, it contains the <a href="../Variables.htm#TickCount">tick-count time</a> the message was posted.</li>
  85. </ul>
  86. <p>A monitor function's <a href="../misc/WinTitle.htm#LastFoundWindow">last found window</a> starts off as the parent window to which the message was sent (even if it was sent to a control). If the window is hidden but not a GUI window (such as the script's main window), turn on <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a> before using it. For example:</p>
  87. <pre>DetectHiddenWindows On
  88. MsgParentWindow := WinExist() <em>; This stores the unique ID of the window to which the message was sent.</em></pre>
  89. <h3>What the Function Should <em>Return</em></h3>
  90. <p>If a monitor function uses <a href="Return.htm">Return</a> without any parameters, or it specifies a blank value such as &quot;&quot; (or it never uses Return at all), the incoming message goes on to be processed normally when the function finishes. The same thing happens if the function <a href="Exit.htm">Exits</a> or causes a runtime error such as <a href="Run.htm">running</a> a nonexistent file. By contrast, returning an integer causes it to be sent immediately as a reply; that is, the program does not process the message any further. For example, a function monitoring WM_LBUTTONDOWN (0x201) may return an integer to prevent the target window from being notified that a mouse click has occurred. In many cases (such as a message arriving via <a href="PostMessage.htm">PostMessage</a>), it does not matter which integer is returned; but if in doubt, 0 is usually safest.</p>
  91. <p>The range of valid return values depends on whether the exe running the script is 32-bit or 64-bit. Non-empty return values must be between -2<sup>31</sup> and 2<sup>32</sup>-1 for 32-bit scripts (<code><a href="../Variables.htm#PtrSize">A_PtrSize</a> = 4</code>) and between -2<sup>63</sup> and 2<sup>63</sup>-1 for 64-bit scripts (<code><a href="../Variables.htm#PtrSize">A_PtrSize</a> = 8</code>).</p>
  92. <p><span class="ver">[v1.1.20+]:</span> If there are multiple functions monitoring a given message number, they are called one by one until one returns a non-empty value.</p>
  93. <h3 id="Remarks">General Remarks</h3>
  94. <p>Unlike a normal function-call, the arrival of a monitored message calls the function as a new <a href="../misc/Threads.htm">thread</a>. Because of this, the function starts off fresh with the default values for settings such as <a href="SendMode.htm">SendMode</a> and <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a>. These defaults can be changed in the <a href="../Scripts.htm#auto">auto-execute section</a>.</p>
  95. <p>Messages sent to a control (rather than being posted) are not monitored because the system routes them directly to the control behind the scenes. This is seldom an issue for system-generated messages because most of them are posted.</p>
  96. <p>Any script that calls OnMessage anywhere is automatically <a href="_Persistent.htm">persistent</a>. It is also single-instance unless <a href="_SingleInstance.htm">#SingleInstance</a> has been used to override that.</p>
  97. <p id="Critical">If a message arrives while its function is still running due to a previous arrival of the same message, the function will not be called again (except if <a href="#MaxThreads">MaxThreads</a> is greater than 1); instead, the message will be treated as unmonitored. If this is undesirable, a message greater than or equal to 0x312 can be buffered until its function completes by specifying <a href="Critical.htm">Critical</a> as the first line of the function. Alternatively, <a href="Thread.htm">Thread Interrupt</a> can achieve the same thing as long as it lasts long enough for the function to finish. By contrast, a message less than 0x312 cannot be buffered by Critical or Thread Interrupt (however, in v1.0.46+, Critical may help because it checks messages <a href="Critical.htm#Interval">less often</a>, which gives the function more time to finish). The only way to guarantee that no such messages are missed is to ensure the function finishes in under 6 milliseconds (though this limit can be raised via <a href="Critical.htm#Interval"><em>Critical 30</em></a>). One way to do this is to have it queue up a future thread by <a href="PostMessage.htm">posting</a> to its own script a monitored message number higher than 0x312. That message's function should use <a href="Critical.htm">Critical</a> as its first line to ensure that its messages are buffered.</p>
  98. <p>If a monitored message that is numerically less than 0x312 arrives while the script is absolutely uninterruptible -- such as while a <a href="Menu.htm">menu</a> is displayed, a <a href="SetKeyDelay.htm">KeyDelay</a>/<a href="SetMouseDelay.htm">MouseDelay</a> is in progress, or the clipboard is being <a href="_ClipboardTimeout.htm">opened</a> -- the message's function will not be called and the message will be treated as unmonitored. By contrast, a monitored message of 0x312 or higher will be buffered during these uninterruptible periods; that is, its function will be called when the script becomes interruptible.</p>
  99. <p>If a monitored message numerically less than 0x312 arrives while the script is uninterruptible merely due to the settings of <a href="Thread.htm">Thread Interrupt</a> or <a href="Critical.htm">Critical</a>, the current thread will be interrupted so that the function can be called. By contrast, a monitored message of 0x312 or higher will be buffered until the thread finishes or becomes interruptible.</p>
  100. <p>The <a href="../misc/Threads.htm">priority</a> of OnMessage threads is always 0. Consequently, no messages are monitored or buffered when the current thread's priority is higher than 0.</p>
  101. <p>Caution should be used when monitoring system messages (those below 0x400). For example, if a monitor function does not finish quickly, the response to the message might take longer than the system expects, which might cause side-effects. Unwanted behavior may also occur if a monitor function returns an integer to suppress further processing of a message, but the system expected different processing or a different response.</p>
  102. <p>When the script is displaying a system dialog such as <a href="MsgBox.htm">MsgBox</a>, any message posted to a control is not monitored. For example, if the script is displaying a MsgBox and the user clicks a button in a GUI window, the WM_LBUTTONDOWN message is sent directly to the button without calling the monitor function.</p>
  103. <p>Although an external program may post messages directly to a script's thread via PostThreadMessage() or other API call, this is not recommended because the messages would be lost if the script is displaying a system window such as a <a href="MsgBox.htm">MsgBox</a>. Instead, it is usually best to post or send the messages to the script's main window or one of its GUI windows.</p>
  104. <h3>Related</h3>
  105. <p><a href="RegisterCallback.htm">RegisterCallback()</a>, <a href="OnExit.htm">OnExit</a>, <a href="OnClipboardChange.htm">OnClipboardChange</a>, <a href="PostMessage.htm">Post/SendMessage</a>, <a href="../Functions.htm">Functions</a>, <a href="../misc/SendMessageList.htm">List of Windows Messages</a>, <a href="../misc/Threads.htm">Threads</a>, <a href="Critical.htm">Critical</a>, <a href="DllCall.htm">DllCall()</a></p>
  106. <h3>Examples</h3>
  107. <pre class="NoIndent"><em>; Example: The following is a working script that monitors mouse clicks in a GUI window.
  108. ; Related topic: <a href="Gui.htm#GuiContextMenu">GuiContextMenu</a></em>
  109. Gui, Add, Text,, Click anywhere in this window.
  110. Gui, Add, Edit, w200 vMyEdit
  111. Gui, Show
  112. OnMessage(0x201, &quot;WM_LBUTTONDOWN&quot;)
  113. return
  114. WM_LBUTTONDOWN(wParam, lParam)
  115. {
  116. X := lParam &amp; 0xFFFF
  117. Y := lParam &gt;&gt; 16
  118. if A_GuiControl
  119. Control := &quot;`n(in control &quot; . A_GuiControl . &quot;)&quot;
  120. ToolTip You left-clicked in Gui window #%A_Gui% at client coordinates %X%x%Y%.%Control%
  121. }
  122. GuiClose:
  123. ExitApp</pre>
  124. <pre class="NoIndent" id="shutdown"><em>; Example: The following script detects system shutdown/logoff and allows you to abort it (this is
  125. ; reported NOT to work on Windows Vista and later).
  126. ; Related topic: <a href="OnExit.htm">OnExit</a></em>
  127. <em>; The following DllCall is optional: it tells the OS to shut down this script <i>first</i> (prior to all other applications).</em>
  128. DllCall(&quot;kernel32.dll\SetProcessShutdownParameters&quot;, UInt, 0x4FF, UInt, 0)
  129. OnMessage(0x11, &quot;WM_QUERYENDSESSION&quot;)
  130. return
  131. WM_QUERYENDSESSION(wParam, lParam)
  132. {
  133. ENDSESSION_LOGOFF = 0x80000000
  134. if (lParam &amp; ENDSESSION_LOGOFF) <em>; User is logging off.</em>
  135. EventType = Logoff
  136. else <em>; System is either shutting down or restarting.</em>
  137. EventType = Shutdown
  138. MsgBox, 4,, %EventType% in progress. Allow it?
  139. IfMsgBox Yes
  140. return true <em>; Tell the OS to allow the shutdown/logoff to continue.</em>
  141. else
  142. return false <em>; Tell the OS to abort the shutdown/logoff.</em>
  143. }</pre>
  144. <pre class="NoIndent"><em>; Example: Have a script receive a custom message and up to two numbers from some other script or program
  145. ; (to send strings rather than numbers, see the example after this one).</em>
  146. OnMessage(0x5555, &quot;MsgMonitor&quot;)
  147. OnMessage(0x5556, &quot;MsgMonitor&quot;)
  148. MsgMonitor(wParam, lParam, msg)
  149. {
  150. <em>; Since returning quickly is often important, it is better to use a ToolTip than</em>
  151. <em>; something like MsgBox that would prevent the function from finishing:</em>
  152. ToolTip Message %msg% arrived:`nWPARAM: %wParam%`nLPARAM: %lParam%
  153. }
  154. <em>; The following could be used inside some other script to run the function inside the above script:</em>
  155. SetTitleMatchMode 2
  156. DetectHiddenWindows On
  157. if WinExist(&quot;Name of Receiving Script.ahk ahk_class AutoHotkey&quot;)
  158. PostMessage, 0x5555, 11, 22 <em>; The message is sent to the &quot;<a href="../misc/WinTitle.htm#LastFoundWindow">last found window</a>&quot; due to WinExist() above.</em>
  159. DetectHiddenWindows Off <em>; Must not be turned off until after PostMessage.</em></pre>
  160. <pre class="NoIndent" id="SendString"><em>; Example: Send a string of any length from one script to another. This is a working example.
  161. ; To use it, save and run both of the following scripts then press Win+Space to show an
  162. ; InputBox that will prompt you to type in a string.</em>
  163. <em>; Save the following script as &quot;<strong>Receiver.ahk</strong>&quot; then launch it:</em>
  164. #SingleInstance
  165. OnMessage(0x4a, &quot;Receive_WM_COPYDATA&quot;) <em>; 0x4a is WM_COPYDATA</em>
  166. return
  167. Receive_WM_COPYDATA(wParam, lParam)
  168. {
  169. StringAddress := NumGet(lParam + 2*A_PtrSize) <em>; Retrieves the CopyDataStruct's lpData member.</em>
  170. CopyOfData := StrGet(StringAddress) <em>; Copy the string out of the structure.</em>
  171. <em>; Show it with ToolTip vs. MsgBox so we can return in a timely fashion:</em>
  172. ToolTip %A_ScriptName%`nReceived the following string:`n%CopyOfData%
  173. return true <em>; Returning 1 (true) is the traditional way to acknowledge this message.</em>
  174. }
  175. <em>; Save the following script as &quot;<strong>Sender.ahk</strong>&quot; then launch it. After that, press the Win+Space hotkey.</em>
  176. TargetScriptTitle = Receiver.ahk ahk_class AutoHotkey
  177. #space:: <em>; Win+Space hotkey. Press it to show an InputBox for entry of a message string.</em>
  178. InputBox, StringToSend, Send text via WM_COPYDATA, Enter some text to Send:
  179. if ErrorLevel <em>; User pressed the Cancel button.</em>
  180. return
  181. result := Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
  182. if result = FAIL
  183. MsgBox SendMessage failed. Does the following WinTitle exist?:`n%TargetScriptTitle%
  184. else if result = 0
  185. MsgBox Message sent but the target window responded with 0, which may mean it ignored it.
  186. return
  187. Send_WM_COPYDATA(ByRef StringToSend, ByRef TargetScriptTitle) <em>; ByRef saves a little memory in this case.
  188. ; This function sends the specified string to the specified window and returns the reply.
  189. ; The reply is 1 if the target window processed the message, or 0 if it ignored it.</em>
  190. {
  191. VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0) <em>; Set up the structure's memory area.</em>
  192. <em>; First set the structure's cbData member to the size of the string, including its zero terminator:</em>
  193. SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
  194. NumPut(SizeInBytes, CopyDataStruct, A_PtrSize) <em>; OS requires that this be done.</em>
  195. NumPut(&amp;StringToSend, CopyDataStruct, 2*A_PtrSize) <em>; Set lpData to point to the string itself.</em>
  196. Prev_DetectHiddenWindows := A_DetectHiddenWindows
  197. Prev_TitleMatchMode := A_TitleMatchMode
  198. DetectHiddenWindows On
  199. SetTitleMatchMode 2
  200. SendMessage, 0x4a, 0, &amp;CopyDataStruct,, %TargetScriptTitle% <em>; 0x4a is WM_COPYDATA. Must use Send not Post.</em>
  201. DetectHiddenWindows %Prev_DetectHiddenWindows% <em>; Restore original setting for the caller.</em>
  202. SetTitleMatchMode %Prev_TitleMatchMode% <em>; Same.</em>
  203. return ErrorLevel <em>; Return SendMessage's reply back to our caller.</em>
  204. }</pre>
  205. <pre class="NoIndent"><em>; Example: See the <a href="../scripts/WinLIRC.htm">WinLIRC client script</a> for a demonstration of how to use OnMessage() to receive
  206. ; notification when data has arrived on a network connection.</em></pre>
  207. </body>
  208. </html>