OnMessage() called function in Library?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

OnMessage() called function in Library?

15 May 2015, 12:14

Hey, all

Short version:
I'm not having luck using OnMessage() to call a function from a function library. It only works if it's included in the script, either explicitly or via an #Include.

Is that something that's simply not going to happen, or is there some "glue" missing somewhere?

Example, using the example code from the documentation for OnMessage().

This works as expected:

Code: Select all

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam, lParam)
{
    X := lParam & 0xFFFF
    Y := lParam >> 16
    if A_GuiControl
        Control := "`n(in control " . A_GuiControl . ")"
    ToolTip You left-clicked in Gui window #%A_Gui% at client coordinates %X%x%Y%.%Control%
}

GuiClose:
ExitApp
This also works as expected, assuming the WM_LBUTTONDOWN function is in the named #Include file.

Code: Select all

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

#Include WM_LBUTTONDOWN.ahk

GuiClose:
ExitApp
However, if you remove the #Include and put WM_LBUTTONDOWN.ahk into \Lib, it does not work.

Code: Select all

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

; WM_LBUTTONDOWN.ahk is in \Lib

GuiClose:
ExitApp
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: OnMessage() called function in Library?

15 May 2015, 16:49

Yes that's correct you have to #Include the script. Without #Include there is no association of the main script to the script with the event handler WM_LBUTTONDOWN()
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

15 May 2015, 17:13

Just to clarify then, this is something particular to the way OnMessage() operates then?
Because, for all other functions, the method explained here in the documentation for libraries works. https://www.autohotkey.com/docs/Functions.htm#lib
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: OnMessage() called function in Library?

15 May 2015, 18:19

yea its kinda weird cause I've never been able to get a script to be called from the lib directory without using #include
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

15 May 2015, 18:35

Okay, we're not talking about the same thing then. Let me try to explain in more detail ...

If I have a function "foo()",
... and it is the sole content of a file named "foo.ahk",
... and that file is in one of the library locations specified in the documentation (linked above),
... that *ordinarily* works just fine.

However, ...

If the file "\lib\foo.ahk" contains only the following:

Code: Select all

foo()
{
     MsgBox, Works
     Return
}
While "bar.ahk" contains only this:

Code: Select all

OnMessage(0x200,"foo")
#w::
foo()
return
Then moving the mouse does nothing while pressing Win+w launches the message box. That's my problem.

The function works when called normally, but does not work when called as part of an OnMessage().
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: OnMessage() called function in Library?

15 May 2015, 18:41

You are correct though, as wm functions aren't detected in the lib folders the same way as normal functions.
I find if I save the wm script as init.ahk with a dummy int() function ( with just a return in it at ),
and call it at the top from the current script,
the wm function is seen in the lib script.

Code: Select all

init()
Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

GuiClose:
ExitApp
init.ahk

Code: Select all

Init()
{
    return
}

WM_LBUTTONDOWN()
{
    msgbox clicked
}
At the end of the day, its kind of like using #include
Interestingly enough, there is no "Call to nonexistent function." error thrown if the init() isn't in the current script.
So it my be have to do with the way ahk interprets how functions are defined.
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: OnMessage() called function in Library?

15 May 2015, 18:55

hrm if you wrap the OnMessage() function in another function it works without init()

Code: Select all

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
WM_LBUTTONDOWN()
return

GuiClose:
ExitApp
WM_LBUTTONDOWN.ahk

Code: Select all

WM_LBUTTONDOWN()
{
    OnMessage(0x201, "WMLBUTTONDOWN")
}

WMLBUTTONDOWN()
{
    msgbox clicked
}
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

15 May 2015, 19:03

Dang! I'm sure that seemed quite simple to you, but I really appreciate it. That makes life a ton easier.

Yes, it's sort of like using #include, except that you can't dynamically change the #Include at run time, whereas \lib directories can be in different locations on different machines with different directory structures full of scripts. The ability to be able to do this *consistently*, regardless of the location of the script, itself, is a huge win for me.
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: OnMessage() called function in Library?

15 May 2015, 19:09

No problems, this is even closer I guess

Code: Select all

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage_( 0x201, "WM_LBUTTONDOWN")
return

GuiClose:
ExitApp
OnMessage_.ahk

Code: Select all

OnMessage_( MsgNumber, Function, MaxThreads = "" )
{
    if ( MaxThreads != "" ) ; ternary doesn't work here
        OnMessage( MsgNumber, Function, MaxThreads )
    else
        OnMessage( MsgNumber, Function )
}

WM_LBUTTONDOWN()
{
    msgbox clicked
}
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

15 May 2015, 19:14

Yep, you lost me there ... maybe someday.

For now, I can get by with something like this.

\lib\FooInclude.ahk

Code: Select all

FooInclude()
{
     Return
}
Foo()
{
     MsgBox, This is what I really wanted in the first place.
     Return
}
Bar.ahk

Code: Select all

FooInclude()
OnMessage(0x200,"Foo")
Coco-guest

Re: OnMessage() called function in Library?

15 May 2015, 21:05

Auto-inclusion will only work if you explicitly call the function (given that it either has the same name as the file name or it follows correct prefix naming). Dynamic function calls such as FuncRef := Func("func_in_lib"), FuncRef.Call() won't work. Same goes for OnMessage(nMsg, "func_in_lib").
What's the difference between FooInclude() and #Include <LibName>? The latter is more readable and tells the user that this script is using this lib.
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

16 May 2015, 16:41

Fair point, and I'm sure I'll find a happy medium somewhere in between.

The issue I'm trying to fix is that my #Include files will need to be in different locations on different machines and, since #Include statements can't be conditional (e.g. On this machine point here, but on that machine point there) I need to find another solution that lets my scripts "just work" no matter which machine I run them on. The nice thing about libraries is that they're automatically "relative."

So if I have:
c:/yadda/Autohotkey/autohotkey.exe
c:/yadda/Autohotkey/lib/foo.ahk
c:/yadda/Autohotkey/lib/bar.ahk
c:/yadda/Autohotkey/whatever.ahk
c:/yadda/Somwhere/blahblah.ahk

Now both whatever.ahk and blahblah.ahk can both use foo.ahk and bar.ahk, because they're in a library directory ... even if I move whatever.ahk and blahblah.ahk around.

However, if I had "#Include ./lib/foo.ahk" in whatever.ahk, it would work just fine *until* I move whatever.ahk to some other (non-sibling) directory.

Likewise, if I had "#Include c:/yadda/Autohotkey/lib/foo.ahk and #Include c:/yadda/Autohotkey/lib/bar.ahk" in whatever.ahk, it would work just fine until I run whatever.ahk on some other machine that may not have the same directory structure.

But in both cases, so long as I have /lib alongside autohotkey.ahk on *every* machine, the library works every time.

The only other alternative I've tried is to have "#Include c:/yadda/autohotkey/lib" and then "#Include foo.ahk" and "#Include bar.ahk" on subsequent lines. In that case I'd only need to update the first #Include on any new machine ... or any time the location of a given script changes on the same machine. Less to update, but still requiring updates that aren't necessary if I can leverage what libraries give me.

I explain that, not because I think it's the best solution, but in case you have another solution that you think would work better for me.
lexikos
Posts: 9621
Joined: 30 Sep 2013, 04:07
Contact:

Re: OnMessage() called function in Library?

16 May 2015, 18:51

You may have missed this point:
Coco-guest wrote:What's the difference between FooInclude() and #Include <LibName>?
Either one will include a file from any of the Lib directories. LibName is just a name, like FooInclude, without file extension. Where x_y() can include x_y.ahk or x.ahk, so can #Include <x_y>.
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

17 May 2015, 11:06

Sorry, yes, ... I read that as a rhetorical question setting up his point about readability. If #include will actually "include" any file in a Lib *without* having to have "#Include [path to lib]" before it, that would -- indeed -- solve my problem.

I'll give that a shot when I get a moment. Thanks in advance.
ed1chandler
Posts: 15
Joined: 15 May 2015, 11:18

Re: OnMessage() called function in Library?

17 May 2015, 12:53

Okay, I'm not getting it to work as proposed in Lexicos' comment. Please show me where my misunderstanding lies.
(Short version, if I can get an #Include directive to include an ahk file in a library, just by saying "#Include [filename]" without having to do "#Include [filepath][filename]" then I'm golden.

My testing uses three files:
  • LibTest.ahk, in the same directory as autohotkey.exe
  • LibFunc.ahk, and LibInclude.ahk, both of which are in /lib, immediately below the directory with autohotkey.exe.
The code for all three is below.

The following is "LibTest.ahk"

Code: Select all

/*
	Run this to test libraries and includes.
	Follow the setup steps shown for each step.
*/

/*
  Setup
  - This script is in the same directory as autohotkey.exe.
  - There is a /lib folder in the same directory as autohotkey.exe.
  - The /lib folder contains two files:
    - LibFunc.ahk, which contains functions LibFunc() and LibFunc2().
	- LibInclude.ahk, which contains function LibIncludeFile()
*/

/*
  Test #1
  
  Setup: Lines 28 and 82 are NOT commented.
         Lines 41, 56, 68, and 84 ARE commented.
  
  A function contained in a library file with a DIFFERENT name
  will not NORMALLY fire, unless called AFTER a function in that
  library file with the SAME name.
  i.e. The library file is LibFunc.ahk and, since I have not yet
       called LibFunc(), this calle to LibFunc2() will not work.
	   You get - "Error: Call to nonexistent function."
*/

LibFunc2()

/*
  Test #2
  
  Setup: Comment out line 29.
  
  A function contained in a library file of the SAME name
  should fire when called.  This is the classic use of
  a library file.
*/

;LibFunc()

/*
  Test #3
  
  Setup: Uncomment line 56, but leave line 41 uncommented.
	
  This is the same function as in Test #1.
  Even though it does not have the same name as the library file
  containing it, the function will still fire becuase it's called
  AFTER calling a function that DOES have the same name.
  
  i.e. I just called LibFunc() a moment ago, so now this will work.
*/

;LibFunc2()

/*
  Test #4
    
  Setup: Comment out lines 29 and 41.  Uncomment line 68.
	
  This function is located in LibInclude.ahk.
  It works because the #Include directive on line 55 points DIRECTLY
  at LibInclude.ahk.
*/

;LibIncludeFile()

/*
  Test #5
    
  Setup: Comment out line 83 and uncomment line 84.
	
  The implication in the post at the url below, was that #Include "will
  include a file from any of the Lib directories", but if that were true
  then LibIncludeFile() on line 65 WOULD fire with the #Include directive
  on line 81, but it does not. You get - "#Include file "LibInclude.ahk"
  cannot be opened."
  http://ahkscript.org/boards/viewtopic.php?p=45714&sid=a7e84d3c507107877955cba76da4fbf4#p45714
*/

#Include ./Lib/LibInclude.ahk
;#Include LibInclude.ahk
This is "LibFunc.ahk"

Code: Select all

LibFunc()
{
	MsgBox, Test #2`n`nThis function is in LibFunc.ahk, which has the same name as the function.
	Return
}

LibFunc2()
{
	MsgBox, Test #1 and #3`n`nThis function is in LibFunc.ahk, which does NOT have the same name as the function, so it will not work unless called AFTER calling the function that does have the same name as the libary file.`n`n i.e. Test #1 fails, but Test #3 works.
	Return
}
This is "LibInclude.ahk"

Code: Select all

LibIncludeFile()
{
	MsgBox, Test #4`n`nThis function is in LibInclude.ahk, which is in the /lib directory.
	Return
}
lexikos
Posts: 9621
Joined: 30 Sep 2013, 04:07
Contact:

Re: OnMessage() called function in Library?

17 May 2015, 16:16

#Include <LibName>, not #Include LibName, not #Include LibName.ahk.
#Include FileOrDirName
#Include <LibName>
#IncludeAgain FileOrDirName
...
LibName
[v1.0.90+]: A library file or function name. For example, #include <lib> and #include <lib_func> would both include lib.ahk from one of the function library folders.
Source: #Include

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: OrangeCat and 303 guests