 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
ahklerner
Joined: 26 Jun 2006 Posts: 1317 Location: USA
|
Posted: Fri Aug 28, 2009 4:14 am Post subject: |
|
|
Wow thanks alot for the demonstration! very good. sorry for being impatient, i just got excited using this stuff _________________
ʞɔпɟ əɥʇ ʇɐɥʍ |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 4469 Location: Qld, Australia
|
Posted: Fri Aug 28, 2009 6:29 am Post subject: |
|
|
Here's another demonstration: how to insert a single line without breaking when the target is the single-line body of an if/else/loop/while. It also serves as a means to determine the active OnExit subroutine, with the limitation that the function must be called at least once before OnExit. It does this by replacing OnExit <arg> with sOnExit:=<arg> .. OnExit %sOnExit% (where <arg> may be a variable, text, expression or omitted; and braces are inserted if necessary).
| Code: | ErrorLevel=0 ; Without this, insert_line_before fails for the line below.
OnExit Undetected ; With it, insert succeeds but the inserted line never runs.
MsgBox % GetCurrentOnExitRoutine()
OnExit Foo1
MsgBox % GetCurrentOnExitRoutine()
if 0 = 0
OnExit Foo2
MsgBox % GetCurrentOnExitRoutine()
if 0 = 0
{
OnExit
}
MsgBox % GetCurrentOnExitRoutine()
ListLines
Pause
Foo1:
Foo2:
Undetected:
ExitApp
GetCurrentOnExitRoutine()
{
static ACT_ONEXIT, sOnExit
if !ACT_ONEXIT
{ ; Initialize. Must be done before the first time OnExit is called.
ACT_ASSIGNEXPR := 2
ACT_ONEXIT := 97
LowLevel_init()
cg := code_gen()
line_ptr := __getFirstLine()
while line_ptr
{
ActionType := NumGet(line_ptr+0, 0, "UChar")
if (ActionType = ACT_ONEXIT)
{
; Create an impossible assignment line with three args.
assn := code_line(cg, ACT_ASSIGNEXPR)
code_arg(cg, 2, __getVar(sOnExit)) ; Output var/target of assignment.
code_arg(cg, 0) ; Empty text arg, may be overwritten.
code_arg(cg, 1, __getVar(sOnExit)) ; Extra %sOnExit% arg for OnExit.
code_line_end(cg)
code_gen_reset(cg, false) ; Reset cg and "detach" line.
l_argc := NumGet(line_ptr+1, 0, "UChar")
l_args := NumGet(line_ptr+4)
a_args := NumGet(assn+4)
if l_argc ; OnExit had an arg.
{
NumPut(a_args+32, line_ptr+4) ; line_ptr->Arg = a_args+32 (third arg)
; Overwrite second arg of assn with first arg of OnExit.
DllCall("RtlMoveMemory", "uint", a_args+16, "uint", l_args, "uint", 16)
}
; else leave OnExit with no args and assn with an empty second arg.
NumPut(2, assn+1, 0, "UChar") ; assn->Argc = 2
if !insert_line_before(assn, line_ptr)
MsgBox % "Error inserting at line " NumGet(line_ptr+8) ": " ErrorLevel
}
line_ptr := NumGet(line_ptr+20, 0, "UInt")
}
code_gen_delete(cg) ; Code was already detached via code_gen_reset.
}
return sOnExit
}
; v1.0.48 +
; Insert a single line before target, automatically wrapping both lines in braces if required.
insert_line_before(to_insert, target)
{
if !(prev := NumGet(target+16))
return 0, ErrorLevel:="Bad target->PrevLine: insertion will have no effect"
if NumGet(target+0,0,"uchar") = 9
return 0, ErrorLevel:="Bad target->ActionType: ACT_ELSE"
action := NumGet(to_insert+0,0,"uchar") ; if/else/loop/while/{/} (not in that order):
if (action >= 10 && action <= 33) || action = 104 || action = 105 || action = 108 || action = 109 || action = 8
return 0, ErrorLevel:="Bad to_insert->ActionType"
; If the previous line is of a type which requires braces (if/else/loop/while):
action := NumGet(prev+0,0,"uchar")
if (action >= 10 && action <= 33) || action = 104 || action = 105 || action = 8
{
; Since target->PrevLine is an if/else/loop/while and target is not {,
; target must be the single-line body of the line preceding it.
bb := __lineAlloc()
be := __lineAlloc()
NumPut(108, bb+0, 0, "uchar") ; bb->ActionType = ACT_BLOCK_BEGIN
NumPut(109, be+0, 0, "uchar") ; be->ActionType = ACT_BLOCK_END
NumPut(NumGet(prev+24), bb+24) ; bb->RelatedLine = prev->RelatedLine
NumPut(prev, bb+28) ; bb->ParentLine = prev
NumPut(bb, target+28) ; target->ParentLine = bb
NumPut(bb, be+28) ; be->ParentLine = bb
NumPut(bb, prev+20) ; prev->NextLine = bb
NumPut(target, bb+20) ; bb->NextLine = target
NumPut(NumGet(target+20), be+20) ; be->NextLine = target->NextLine
NumPut(be, target+20) ; target->NextLine = be
prev := bb ; Now let below insert to_insert between bb and target.
}
NumPut(to_insert, prev+20) ; prev->NextLine = to_insert
NumPut(target, to_insert+20) ; to_insert->NextLine = target
NumPut(NumGet(target+28), to_insert+28) ; to_insert->ParentLine = target->ParentLine
return 1, ErrorLevel:=0
} |
This would be a lot easier to write, more maintainable, secure, reliable, readable, etc. etc. if we had struct support. I hope to include struct support and definitions of these structures in a future version of AutoHotkey_L.  |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 4469 Location: Qld, Australia
|
Posted: Thu Feb 18, 2010 1:25 pm Post subject: |
|
|
Since AutoHotkey_L introduced objects and this required additional "symbol" types for the expression evaluator, some of the existing symbol types have different values to mainstream AutoHotkey. Call, which demonstrates dynamically calling a function, must therefore be updated to work in recent revisions of AutoHotkey_L:
| Code: | , SYM_INVALID:=56, SYM_VAR:=3, SYM_FUNC:=55, SYM_OPERAND:=4, VAR_ALIAS:=0
, SYM_INVALID:=62, SYM_VAR:=3, SYM_FUNC:=59, SYM_OPERAND:=4, VAR_ALIAS:=0
|
Note that Call usually has no advantages over dynamic function calls, but there is one: the actual number of parameters passed to the function is calculated based on the parameter values. For instance, if the code needs to pass between zero and four parameters, it is tempting to do this:
| Code: | fn := "MyFunc", %fn%(prm1, prm2, prm3, prm4)
| However, all parameters are passed even if some are not meaningful. So for instance, if MyFunc defines parameter 4 as optional, it will be overwritten even if prm4 has no meaningful value. Call can work around this issue:
| Code: | prm1 := "one", prm2 := "two", prm3 := "three"
prm4 := "__deFault__"
Call("MyFunc", prm1, prm2, prm3, prm4)
| In this case, only the first three parameters are passed. If MyFunc required four parameters, an empty string would be passed in place of "__deFault__". This behaviour can also be important for DllCall, where passing empty parameters is different from not passing parameters.
| Code: | prm1 := "GetCommandLine"
prm2 := "str"
prm3 := "__deFault__" ; prm3 and on will not be passed.
MsgBox % Call("DllCall", prm1, prm2, prm3, prm4) |
This post inspired by recent discussion with majkinetor. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|