Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

AutoHotkey.dll


  • Please log in to reply
1328 replies to this topic
tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007

AUTOHOTKEY.DLL, AUTOHOTKEY_H
* AutoHotkey.dll is a a shared library that allows the AutoHotkey interpreter to be embedded into another application or language. It provides AutoHotkey functionality that might be more difficult to implement in another language.

* AutoHotkey_H is HotkeyIt's custom build (most uptodate).
* AutoHotkey_N is tinku99's custom build, outdated now (link for history).

* Features:
- All features of AutoHotkey_L + others below
- dynamic #includes
- wildcards in #include
- subclass windows in host process
- COM support
- multi-threading with multiple embedded ahk interpreters
- builtin lowlevel functions (equivalent to the machine code functions in lowlevel.ahk by Lexikos.) ( compatible lowlevel.ahk)

* Maintainers: Naveen Garg, HotkeyIt

* License: GPLv2
* No Warranty. Like all free software, use at your own risk
wiki
Download:
AutoHotkey_H(recommended)
ahk2exe.exe,
Documentation ( Documentation AHK_H v2 )
source on github



Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
This looks wonderful, but nothing happens if I hit the hotkeys. What should we do to try the dll?

n-l-i-d
  • Guests
  • Last active:
  • Joined: --
Very cool indeed! 8)

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
After F1 and F3, you should see 2 script icons.
then try F5 and F6.
look at the script variables, are they what you expect?

anyways, I am uploading a more self testing version...
try redownloading.
just run ahkahk.ahk

I will be posting more complete framework for IPC for lisp that should be usable with anything else including ahk itself.

I know its ludicrous, but as a perversity this actually runs 1.0.48 code in the same process as 1.0.46 code. (untested)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
It works! Thanks!
I wonder, is it possible to use a pipe to feed the text of the second script to the dll, instead of reading it from a file?

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
Unfortunately, ahk reads and rewinds the file, and pipes are not seekable as far as i know.

Edit:
However, lexikos had a partial solution here:
http://www.autohotke...pt pipe dynamic

see if it works unmodified.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Interesting. :)

Laszlo, I think it should be relatively simple. Currently the loading process does two things that are not supported by pipes:
[*:1y7g2dw0]It tries to call GetFileAttributes(), in order to determine if a valid filename was specified. This would not be applicable to a file/pipe handle anyway.

[*:1y7g2dw0]It reads three bytes, then tries to seek if they do not equal the UTF-8 BOM. Currently it only does this to skip over the BOM and avoid interpreting it as part of the script. This could be left up to the caller. An "encoding" parameter could be reserved for future use, if it could become useful.(I see tinku99 posted while I continued this post; note that the point above is the only time AutoHotkey attempts to seek within the script file.)

tinku99, the current source code seems to be based on revision 14 of AutoHotkey_L, which is based on an old pre-v1.0.48 beta. There have since been numerous improvements to both AutoHotkey and AutoHotkey_L. Are you planning to update soon?

What is the reason ahkdll() creates a new thread? I think it might be the easiest way, given how involved AutoHotkey's current message loop is. However, it isn't a good idea to call ahkgetvar() from any thread other than the script's thread. If ahkdll() automatically starts a new thread, ahkgetvar() should automatically synchronise with it. The same goes for any other functions you make available.

It appears ahkclose() only release the script's thread handle - it does not terminate the thread or have any other effect. Additionally, the !q hotkey in ahkahk.ahk calls FreeLibrary, but passes the empty variable fredll. It does not matter since the !q hotkey in ahkclinit.ahk overrides it. Freeing the DLL is not sufficient anyway, since it does not do any cleanup. For instance, all windows created by AutoHotkey.dll still exist, but the window procedure code is unloaded. As soon as a message is sent to a window, the program crashes.

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
Laszlo and Lexikos: Thank you for trying out the autohotkey.dll
I appreciate the feedback.

the loading process does two things that are not supported by pipes:

It seems to reparse some parts of the script depending on if and where you have #directives, autoexecute sections and functions. If you limit yourself to #directives, you can probably have just one round.
	if (fgets(aBuf, aMaxCharsToRead, fp) == NULL) // end-of-file or error
 in script.cpp in function 
size_t Script::GetLine(char *aBuf, int aMaxCharsToRead, int aInContinuationSection, FILE *fp)

Are you planning to update soon?

I am working on my first release of ahklisp.
But soon, I will try to merge with the latest changes...
Have you considered using git?

it isn't a good idea to call ahkgetvar() from any thread other than the script's thread.
ahkgetvar() should automatically synchronise with it

ahkgetvar() isn't strictly necessary, because first contact is already made from the lisp side with ahkdll(file, callback). But I don't know how to synchronise threads...

ahkclose() only release the script's thread handle - it does not terminate the thread or have any other effect.

I know. I tried to do some cleanup, but everything i did also made the script crash. I was able to get another round of dll loads and unloads by using separate thread handles (its commented out in my code for now). Slash and burn is so much easier than cleanup... :evil:
For now, lets just say, unloading the dll is not recommended without exiting.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

It seems to reparse some parts of the script depending on if and where you have #directives, autoexecute sections and functions.

I was certain it parses the script line by line. I see only one instance of rewind(); can you point out any specific cases where it seeks? (The code in your previous post only uses fgets, which reads up to the first newline and does not seek.)

I have a few more observations and suggestions:

"Reloading" the script merely re-executes the auto-execute section. This would rarely be sufficient, so perhaps it should simply do nothing? On the other hand, I suppose a script could be specifically designed to "reload" itself if the auto-execute section is executed a second time. Reload essentially acts as gosub auto-execute; the auto-execute section re-executes, and when it finishes, the thread which called Reload resumes.

Also note that the DLL uses the command line arguments of the parent process (via __argv). For instance, if I launch the parent script with /ErrorStdOut, both scripts will output errors to stdout. If I launch the parent script with /Debug, both scripts will attempt to connect to the debugger (separately). This could be useful, but the command-line arguments passed to the parent process may not necessarily be meaningful. For instance, if the parent process accepts three arguments and none of them are recognised by AutoHotkey.dll as switches, the first is ignored and the others are assigned to variables. One solution would be to remove the loop which begins with:
for (int i = 1; i < __argc; ++i)
Perhaps it would be more appropriate to treat the second parameter of ahkdll() as the command line args? I think that the variable name sbclpointer is not very intuitive...

Is there a reason you restrict it to integer values?
sbclvar->Assign([color=red]atoi([/color]nameHinstanceP.sbclp[color=red])[/color]);
If you removed atoi(), it would simply copy the string value as is.

Have you considered using git?

For AutoHotkey_L? I had not seen git before today. I was using Subversion, but stopped (at revision 15) for a few reasons, not least of which was that it seemed unreasonably slow. Since AutoHotkey_L was never intended to be a collaborative project, I don't see much benefit to using Subversion (or git, from what little I've seen).

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
All good observations.
I had glossed over the command line processing...

the second parameter of ahkdll() as the command line args
If you removed atoi(), it would simply copy the string value as is.

That is reasonable.
I can change the variable name to argv or something.

I see only one instance of rewind();

I put a breakpoint and msgbox(aBuf) call right after that fgets()
and saw every line in my script come up one by one.
However, before the script launched. The autoexecute lines came up again one by one. It also depends on how the script is structured as far as where in the script the #directives are, on when the duplicate fgets() calls happen...
I tried changing what was in aBuf after the fgets() call, but got memory access violations...

I know there is only one rewind(), but there are other ways of going backward... I couldn't find them, but they must be happening, maybe in the precompiled code, or after some function name has been aliased...

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I put a breakpoint and msgbox(aBuf) call right after that fgets() and saw every line in my script come up one by one.
However, before the script launched. The autoexecute lines came up again one by one.

Can you post a script with which I may reproduce this? After adding MsgBox(aBuf), I see each line exactly once.
if (fgets(aBuf, aMaxCharsToRead, fp) == NULL) // end-of-file or error
{
	*aBuf = '\0';  // Reset since on error, contents added by fgets() are indeterminate.
	return -1;
}
MsgBox(aBuf);

I know there is only one rewind(), but there are other ways of going backward... I couldn't find them,

After searching thoroughly through every use of fp (the file pointer variable), I am confident the only file I/O functions which are used on it are: fgets, rewind (for BOM only), feof and fclose. Anyway, I haven't had any problems with my script-piping function. If it did attempt to seek within the file, the pipe would break...

Since the Release build in the project file is still set to output an EXE, I suppose you've only been using Debug builds? Release builds are much smaller and faster.

Btw, I'd like you to remove the file AutoHotkey_L.txt...

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
I have replaced the "AutoHotkey_L.txt" file with a README.

I will put out a release build in my next version.

I will also work on the cleanup issues on exiting the dllclient script.
I think being able to reload different scripts arbitrarily or run multiple scripts would be nice. Maybe start with a different global var on the main script structure...

I am confident the only file I/O functions which are used on it are: fgets, rewind (for BOM only), feof and fclose. Anyway, I haven't had any problems with my script-piping function.

Ok, sorry, my mistake. You were right. I started clean and confirm your observations.

I was even able to replace the line read by fgets in memory without problems.
But your piping methods seems to work largely unmodified, and should be sufficient.

; run script through pipe in autohotkey.dll
; based on run script through pipe by lexikos
;; http://www.autohotkey.com/forum/topic25867.html
#NoEnv

start:
ahkdll := DllCall("LoadLibrary", "str", "AutoHotkey.dll")

InputBox, Script, Script, Enter a line of script to execute.,,, 120,,,,, MsgBox :D

; To prevent "collision", pipe_name could be something mostly "unique", like:
;   pipe_name := A_TickCount
pipe_name := "testpipe"
fullpipe_name := "\\.\pipe\" . pipe_name
; Before reading the file, AutoHotkey calls GetFileAttributes(). This causes
; the pipe to close, so we must create a second pipe for the actual file contents.
; Open them both before starting AutoHotkey, or the second attempt to open the
; "file" will be very likely to fail. The first created instance of the pipe
; seems to reliably be "opened" first. Otherwise, WriteFile would fail.
pipe_ga := CreateNamedPipe(pipe_name, 2)
pipe    := CreateNamedPipe(pipe_name, 2)
if (pipe=-1 or pipe_ga=-1) {
    MsgBox CreateNamedPipe failed.
    ExitApp
}


DllCall("AutoHotkey\ahkdll", "str", fullpipe_name, "str"
, "1234567", "Cdecl Int")
sleep, 1000  
; Run, %A_AhkPath% "\\.\pipe\%pipe_name%"
; Wait for AutoHotkey to connect to pipe_ga via GetFileAttributes().
DllCall("ConnectNamedPipe","uint",pipe_ga,"uint",0)
; This pipe is not needed, so close it now. (The pipe instance will not be fully
; destroyed until AutoHotkey also closes its handle.)
DllCall("CloseHandle","uint",pipe_ga)
; Wait for AutoHotkey to connect to open the "file".
DllCall("ConnectNamedPipe","uint",pipe,"uint",0)

; AutoHotkey reads the first 3 bytes to check for the UTF-8 BOM "". If it is
; NOT present, AutoHotkey then attempts to "rewind", thus breaking the pipe.
Script := chr(239) chr(187) chr(191) Script
if !DllCall("WriteFile","uint",pipe,"str",Script,"uint",StrLen(Script)+1,"uint*",0,"uint",0)
    MsgBox WriteFile failed: %ErrorLevel%/%A_LastError%
DllCall("CloseHandle","uint",pipe)
CreateNamedPipe(Name, OpenMode=3, PipeMode=0, MaxInstances=255) {
    return DllCall("CreateNamedPipe","str","\\.\pipe\" Name,"uint",OpenMode
        ,"uint",PipeMode,"uint",MaxInstances,"uint",0,"uint",0,"uint",0,"uint",0)
}
!q::ExitApp



tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
Thanks to Lexikos for most of these suggestions
Version 2: Merged with AutoHotkey_1.0.48_L26
building release version as well as debug version as it is smaller
changed sbclPointer to argv.
any string can now be passed as the second var to hkdll(name, argv)

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
a single commandline option is simulated with the second argument to ahkdll(filename, option, parameter) now. /Debug is allowed and works with
https://ahknet.autoh...ng_Features.htm

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
new dll functions:
linePointer := createLine(line) ; eg. "click, 200, 200" or "StrLen(string)"
; (no control flow yet)
createFunction(prototype) ; eg. "func(param1, param2)"

example scripts:
<!-- m -->https://ahknet.autoh... ... onHost.ahk<!-- m -->
<!-- m -->https://ahknet.autoh... ... nction.ahk<!-- m -->

it may actually even be possible for the host and client scripts to share line structures. (untested)