AutoHotkey Community

It is currently May 27th, 2012, 3:23 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 173 posts ]  Go to page Previous  1 ... 7, 8, 9, 10, 11, 12  Next
Author Message
 Post subject:
PostPosted: August 28th, 2009, 4:14 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
Wow thanks alot for the demonstration! very good. sorry for being impatient, i just got excited using this stuff

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 28th, 2009, 6:29 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
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. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 18th, 2010, 1:25 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 4th, 2010, 5:44 pm 
Offline

Joined: February 29th, 2008, 8:36 pm
Posts: 901
Location: Vault 7
weiterbilder wrote:
What can you do with it in general.

There is majkinetor's UTest

And I just finished updating my debug output library. It relies heavily on LowLevel.ahk, so I thought it would be relevant to mention here.

Lexikos wrote:
Quote:
the typical AutoHotkey user

...has nothing to do with this thread.

While normal users will still have nothing to do with this thread, good simple to use debug output functions can be useful to anyone! And the proper use of assert statements is a great skill for any programmer (professional or otherwise) to learn.

Anyways, thank you Lexikos for the great stuff!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 11th, 2010, 8:53 pm 
Offline

Joined: February 29th, 2008, 8:36 pm
Posts: 901
Location: Vault 7
I was playing around with LowLevel more this morning and came up with an interesting set of functions. The core of this example script is the merge function. Given 2 function names, it will take the local variables of one function and insert them into the other function (overwriting values where necessary). I also added a way to filter which variables are considered for the merge.

This script requires AutoHotkey_H (current version is 17). I tried to make
a version for AutoHotkey_L, but kept running into difficulties...

Code:
;==============================================================================
/*

Output will be three message boxes:
   1) 0x100
   2) 1-two-ASDF
   3) alpha-two-hello world
*/
#SingleInstance FORCE
   LowLevel_init()
   test()
return
;==============================================================================
test()
{
   ; a list of name:value pairs, separated by |s
   list =
   (Join LTrim
   FO_MOVE:0x1|FO_COPY:0x2|FO_DELETE:0x3|FO_RENAME:0x4|FOF_MULTIDESTFILES:0x1
   |FOF_MULTIDESTFILES:0x1|FOF_SILENT:0x4|FOF_RENAMEONCOLLISION:0x8
   |FOF_NOCONFIRMATION:0x10|FOF_ALLOWUNDO:0x40|FOF_FILESONLY:0x80
   |FOF_SIMPLEPROGRESS:0x100|FOF_NOCONFIRMMKDIR:0x200|FOF_NOERRORUI:0x400
   |FOF_NOCOPYSECURITYATTRIBS:0x800|FOF_NORECURSION:0x1000
   |FOF_NO_CONNECTED_ELEMENTS:0x2000|FOF_WANTNUKEWARNING:0x4000|
   )

   unpack_list(list,A_ThisFunc)
   MsgBox %FOF_SIMPLEPROGRESS%

   ; establish a box object for moving variables
   box := Object()
   box.a := ""
   box.b := ""
   box.c := ""
   
   ; use simple local variables
   a := 1
   b := "two"
   c := "ASDF"
   
   ; pack them up
   repack(box,A_ThisFunc)
   MsgBox % box.a . "-" . box.b . "-" . box.c
   
   ; send the box to another function
   test_helper(box)
   
   ; check out what that other function did with the box
   MsgBox % box.a . "-" . box.b . "-" . box.c
}

test_helper(ByRef box)
{
   ; unpack the box
   unpack(box, A_ThisFunc)
   
   ; play around with the contents of the box
   a := "alpha"
   c := "hello world"
   
   ; repack the box when finished
   repack(box, A_ThisFunc)
}
;==============================================================================
unpack_list(_unpack_list,_unpack_func)
{
   Loop Parse, _unpack_list, |
   {
      StringSplit _unpack_part, A_LoopField, :
      %_unpack_part1% := _unpack_part2
   }
   merge(_unpack_func,A_ThisFunc,"","_unpack_")
}
;==============================================================================
; Maybe a return would be better than using ByRef here?
repack(ByRef box, caller)
{
   merge(A_ThisFunc,caller,"enum,key,value,box,caller")
   
   enum := box._NewEnum()
   While enum[key,value]
      box[key] := %key%
}
;==============================================================================
unpack(box, caller)
{
   enum := box._NewEnum()
   While enum[key,value]
      %key% := value
   
   merge(caller, A_ThisFunc, "enum,key,value,box,caller")
}
;==============================================================================
; f1 gets overwritten where overlap occurs.
; have not yet attempted to handle the global scope
merge(f1,f2, not_in_list="", not_contains_list="", match_regex=".*")
{
   f1_ptr := FindFunc(f1)
   f2_ptr := FindFunc(f2)
   
   f1_var_array_ptr := NumGet(f1_ptr+20, 0, "UInt")
   f1_var_array_len := NumGet(f1_ptr+28, 0, "Int")
   
   
   var_array := object()
   Loop % f1_var_array_len
   {
      ptr_ptr := f1_var_array_ptr + (A_Index - 1) * 4
      ptr := NumGet(ptr_ptr+0)
      name := __str(NumGet(ptr+24, 0, "UInt"))
      var_array[name] := ptr
   }
   
   f2_var_array_ptr := NumGet(f2_ptr+20, 0, "UInt")
   f2_var_array_len := NumGet(f2_ptr+28, 0, "Int")

   Loop % f2_var_array_len
   {
      ptr_ptr := f2_var_array_ptr + (A_Index - 1) * 4
      ptr := NumGet(ptr_ptr+0)
      name := __str(NumGet(ptr+24, 0, "UInt"))
      
      if name in %not_in_list%
         continue
      if name contains %not_contains_list%
         continue
      if !RegExMatch(name,match_regex)
         continue
      
      Alias(source_var, ptr+0)
      
      target_ptr := var_array[name]
      if !target_ptr
      {   
         target_ptr := code_varW(name)
         Alias(target_var, target_ptr+0)
         target_var := source_var
         __addVar(target_ptr, f1_ptr)
      }
      else
      {
         Alias(target_var, target_ptr+0)
         target_var := source_var
      }
      Alias(target_var, 0)
      Alias(source_var, 0)
   }
}
;==============================================================================
; needed to use lstrcpyW for this to work (modified function from Lexikos' Code.ahk)
code_varW(name)
{
    static empty
    var_ptr := DllCall("GlobalAlloc","uint",0x40,"uint",28 + 2*StrLen(name) + 1)
    if !var_ptr
        return 0, ErrorLevel:="MEM"
    NumPut(DllCall("lstrcpyW","uint",var_ptr+28,"str",name), var_ptr+24)
    , NumPut(&empty, var_ptr+8)
    , NumPut(2, var_ptr+20, 0, "uchar")
    , NumPut(1, var_ptr+23, 0, "uchar")
    return var_ptr
}
;==============================================================================

[Moderator's note: Broke long line up to allow word wrap.]


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 23rd, 2010, 2:44 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
I've updated __getTokenValue() in the "v1.0.48" download to support objects in variables. However, I haven't updated LowLevel.chm - SymbolType is only accurate for the official AutoHotkey build, and some struct/union members used in AutoHotkey_L aren't documented there.

tinku99 wrote:
Variadic functions could be simulated by calling a variadic bif (such as "dllcall") with one bogus argument plus the arguments meant for the user variadic.
Source: DebugBIF thread

There's no need to use DebugBIF for this. Instead, flag the function as "built-in" and implement it via a callback.

[Note: All code snippets in this post require AutoHotkey_L or a build based on it.]

Code:
LowLevel_init()
if !(vf := __findFunc("variadic"))
|| !(cb := RegisterCallback("variadic_callback", "C F", 3))
{
    MsgBox FAIL
    ExitApp
}

NumPut(true, vf + 49, 0, "char") ; vf.IsBuiltIn := true
NumPut(cb, vf + 4)               ; vf.BIF := cb

; Example: Simulate Object(<initializers>).
foo := Object()
bar := variadic(foo, 1, "one", 2, "two")
e := bar._NewEnum()
while e[k, v]
    s .= k " = " v "`n"
MsgBox % s "`nfoo " (foo==bar ? "==" : "!=") " bar"

variadic(a=0,b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0
        ,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0)
{
    ; The body of this function is never executed.
}

variadic_impl(params)
{
    ; Example implementation of variadic function:
    ;   Accepts an object and a list of key/value pairs to set.
    e := params._NewEnum()
    if ! e[_, obj]
        return
    while e[_, k] && e[_, v]
        obj[k] := v
    return obj
}

variadic_callback(aResultToken, aParam, aParamCount)
{
    ; Build array of parameters.
    params := Object()
    Loop % aParamCount {
        params[A_Index] := __getTokenValue(NumGet(aParam+0))       
        aParam += A_PtrSize
    }
    ; Call implementation function (or do stuff here).
    result := variadic_impl(params)
    ; Store result in result token.
    __setResultToken(aResultToken, result)
}

In this example, the function variadic() must be defined with the maximum number of parameters that will be passed to it. Load-time validation will prevent scripts from passing more than this. Note that the default values are only used if a parameter in the middle of the list is omitted:
Code:
variadic(1, , 3)  ; (1, 0, 3)

Quote:
However, DebugBIF_DefaultHandler falls down on objects.
It relies on __getTokenResult to get a usable value from aParam, which is an array of pointers to ExprTokenType. Try the updated version of LowLevel.
Quote:
Also, how do you get the result of the DebugBIF_DefaultHandler back to the caller of the intentionally faulty bif ?
aResultToken points to an ExprTokenType structure which should hold the return value. Its use is rather involved, so I've written a function for it (used in the example above).
Code:
__setResultToken(rt, r)
{
    /* ; This section may cause loss of format, e.g. for r=0xBEEF.
    if r is integer
    {
        ; rt.symbol is SYM_INTEGER by default.
        NumPut(r, rt+0, 0, "int64")     ; rt.value_int64 := r
    }
    else if r is float
    {
        NumPut(2, rt+0, 8, "int")       ; rt.symbol := SYM_FLOAT
        NumPut(r, rt+0, 0, "double")    ; rt.value_double := r
    }
    else
    */
    if IsObject(r)
    {
        DllCall(NumGet(NumGet(&r)+4), "uint", &r) ; r.AddRef()
        NumPut(&r, rt+0)                ; rt.object := r
        NumPut(5, rt+0, 8, "int")       ; rt.symbol := SYM_OBJECT
    }
    else
    {
        ; See TokenSetResult() in script2.cpp for how this works.
        if StrLen(r) > 255 {
            p := __malloc((StrLen(r) + 1) * (A_IsUnicode ? 2:1))
            NumPut(p, rt+12)            ; rt.circuit_token := p
            NumPut(StrLen(r), rt+4)     ; rt.buf := StrLen(r)
        } else
            p := NumGet(rt+4)           ; p := rt.buf
        StrPut(r, p)
        NumPut(p, rt+0)                 ; rt.marker := p
        NumPut(0, rt+0, 8, "int")       ; rt.symbol := SYM_STRING
    }
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject: __getTokenValue()
PostPosted: June 23rd, 2010, 9:04 pm 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Lexikos wrote:
There's no need to use DebugBIF for this. Instead, flag the function as "built-in" and implement it via a callback... function variadic() must be defined with the maximum number of parameters that will be passed to [for] Load-time validation
That is neat. What do you think of optionally specifying number of parameters for the load time validation. Maybe with something like
Code:
func(10000){
; a registercallback with BIF prototype will handle upto 10000 parameters
}
...To avoid having to type a 100 dummy parameters.
Lexikos wrote:
I've updated __getTokenValue() in the "v1.0.48" download
Could you please post the updated c++ code for __getTokenValue() ?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 23rd, 2010, 11:11 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
tinku99 wrote:
That is neat. What do you think of optionally specifying number of parameters for the load time validation?
I will not be implementing any feature which is only useful in combination with LowLevel. In this particular case at least, I think it would be a waste of time. Variadic functions are already relatively high on my priority list.

Code:
BIF(__getTokenValue)
{
   ExprTokenType *token = aParam[0];
   
   if (token->symbol != SYM_INTEGER)
      return;
   
   token = (ExprTokenType*) token->value_int64;

    if (token->symbol == SYM_VAR)
    {
      Var &var = *token->var;

      VarAttribType cache_attrib = var.mAttrib & (VAR_ATTRIB_HAS_VALID_INT64 | VAR_ATTRIB_HAS_VALID_DOUBLE);
      if (cache_attrib)
      {
         aResultToken.symbol = (SymbolType) (cache_attrib >> 4);
         aResultToken.value_int64 = var.mContentsInt64;
      }
      //if (var.mAttrib & VAR_ATTRIB_HAS_VALID_INT64)
      //{
      //   aResultToken.symbol = SYM_INTEGER;
      //   aResultToken.value_int64 = var.mContentsInt64;
      //}
      //else if (var.mAttrib & VAR_ATTRIB_HAS_VALID_DOUBLE)
      //{
      //   aResultToken.symbol = SYM_FLOAT;
      //   aResultToken.value_double = var.mContentsDouble;
      //}
      else if (var.mAttrib & VAR_ATTRIB_OBJECT)
      {
         aResultToken.symbol = SYM_OBJECT;
         aResultToken.object = var.mObject;
      }

      else
      {
         aResultToken.symbol = SYM_OPERAND;
         aResultToken.marker = var.mContents;
      }
    }
    else
    {
        aResultToken.symbol = token->symbol;
        aResultToken.value_int64 = token->value_int64;
    }
    if (aResultToken.symbol == SYM_OBJECT)
        aResultToken.object->AddRef();

}


Btw, it's probably impossible to pass more than 254 parameters in a function call. Expressions are limited to 512 tokens, which includes commas, parentheses and function references in addition to the actual parameters. Supporting even 100 parameters would be overkill. Who would actually use that many parameters in a single function call?


Report this post
Top
 Profile  
Reply with quote  
 Post subject: loadtime validation
PostPosted: June 24th, 2010, 2:06 am 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Quote:
That is neat. What do you think of optionally specifying number of parameters for the load time validation?
Never mind.
Its easy enough to bypass load time validation of parameters using dynamic function call.
But its nice to know that default parameters can still be specified.

Its also nice to be able to forward the params to a builtin function as well.
Example: simulate objInsert()
Code:
LowLevel_init()
if !(vf := __findFunc("variadic"))
|| !(cb := RegisterCallback("variadic_callback", "C F", 3))
|| !(ppObjInsert := __findFunc("objInsert") + 4)
{
    MsgBox FAIL
    ExitApp
}
NumPut(true, vf + 49, 0, "char") ; vf.IsBuiltIn := true
NumPut(cb, vf + 4)               ; vf.BIF := cb
pObjInsert := numget(ppObjInsert+0)

; Example: Simulate objInsert
foo := Object()
foo.insert := "variadic"
foo.insert(foo, 1, "one", 2, "two")
e := foo._NewEnum()
while e[k, v]
    s .= k " = " v "`n"
MsgBox % s
return

variadic(){
; should only be called indirectly, to avoid load time validation
}

variadic_callback(aResultToken, aParam, aParamCount)
{
  global pObjInsert
  dllcall(pObjInsert + 0, "ptr", aResultToken, "ptr", aParam, "ptr", aParamCount, "cdecl")
}

Is there anything special about resultTokens? I was not able to use __SetResultToken to modify the param tokens before passing them onto objInsert...
Code:
variadic_callback(aResultToken, aParam, aParamCount)
{
  global pObjInsert
    offset := 0   
    Loop % aParamCount {
   __SetResultToken(NumGet(aParam + offset), "instrumented" . A_Index) ; fails
        offset += A_PtrSize
    }
  dllcall(pObjInsert + 0, "ptr", aResultToken, "ptr", aParam, "ptr", aParamCount, "cdecl")
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 24th, 2010, 9:14 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
__setResultToken is intended only for use with aResultToken, which has special use:
  • ExpandExpression uses 'buf' to pass the function a pointer to a buffer which may be used to return a value (<= 255 characters). __setResultToken relies on this, which is probably why your example fails.
  • If the function needs to allocate memory for its result, it can pass it back to ExpandExpression via 'circuit_token'. This memory is freed automatically when expression evaluation is complete.
  • If circuit_token is used for the function's result, 'buf' must be set to the string's length.
None of this applies to parameters, as they are only used to pass values to the function. You only need to set 'symbol' and the appropriate value field ('marker' for strings).


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 25th, 2010, 8:54 am 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Lexikos wrote:
__setResultToken is intended only for use with aResultToken
I got variadic custom object initializers to work in richObject.
Needed the following:
__getResultObject, __setParamToken.ahk

Hopefully, I am not leaking variables, objects, etc...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 25th, 2010, 9:45 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
tinku99 wrote:
Hopefully, I am not leaking variables, objects, etc...
You are allocating memory with __malloc which will not be freed. Also, there is no reason for the StrLen(r) > 255 check, nor the minimum 256 character allocation. It is used in __setResultToken so that a malloc can be avoided when the caller-provided buffer will suffice.

For string parameters, I see two options:
  • Explicitly allocate memory for parameters before you call the function and explicitly free it after the function returns.
  • Store the parameters' string values in variables and let AutoHotkey do all the work.
Why did you write __getResultObject rather than simply using __getTokenValue? Both functions will cause the object's reference count to be incremented but neither function will release the reference which is contained within aResultToken. You'll need to do that before overwriting it, as shown in the documentation.

Note that your __setParamToken does not support floating-point numbers... If you change "is number" to "is integer", they will at least be supported as strings.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: __setparamtoken
PostPosted: June 25th, 2010, 6:03 pm 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
@Lexikos, Thanks for the advice with memory management.
I have incorporated your suggestions in __setParamToken().
Lexikos wrote:
For string parameters, I see two options:
  • Explicitly allocate memory for parameters before you call the function and explicitly free it after the function returns.
  • Store the parameters' string values in variables and let AutoHotkey do all the work.

I chose the second route, sort of. Using a heap of variables.
Code:
__setParamToken(rt, r)
{
static heap, pointer
if !heap
{
heap := object()
heap._SetCapacity(256)
pointer := 1
}

        if IsObject(r)
    {
      if (NumGet(rt+0, 8, "int") == 5)       ; rt.symbol := SYM_OBJECT
      {
   oldObjectPointer :=  NumGet(rt+0)                ; rt.object := r
   DllCall(NumGet(NumGet(oldObjectPointer+0)+8), "uint", oldObjectPointer)
   ; decrement reference count
      }
      DllCall(NumGet(NumGet(&r)+4), "uint", &r) ; r.AddRef()
        NumPut(&r, rt+0)                ; rt.object := r
        NumPut(5, rt+0, 8, "int")       ; rt.symbol := SYM_OBJECT
    }

    else if r is integer
    {
      NumPut(1, rt+0, 8, "int")       ; rt.symbol := SYM_INTEGER
      NumPut(r, rt+0, 0, "Int64")       ; rt.symbol := SYM_INTEGER
     
    }
    Else if r is Float
    {
      NumPut(2, rt+0, 8, "int")       ; rt.symbol := SYM_FLOAT
      NumPut(r, rt+0, 0, "double")    ; rt.value_double := r
    }
    else    {
        ; See TokenSetResult() in script2.cpp for how this works.
        ; p := __malloc((StrLen(r) + 1) * (A_IsUnicode ? 2:1))
   heap[pointer] := r
   p := heap._GetAddress(pointer)
   StrPut(r, p)
        NumPut(p, rt+0)                 ; rt.marker := p
        NumPut(0, rt+0, 8, "int")       ; rt.symbol := SYM_STRING
   pointer :=  Mod(pointer + 1, 256)
    }
}

Lexikos wrote:
Why did you write __getResultObject rather than simply using __getTokenValue?
Because it didn't work.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Re: __setparamtoken
PostPosted: June 26th, 2010, 5:27 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
tinku99 wrote:
Because it didn't work.
...
; map := __getTokenValue(aResultToken) ; doesn' work
You were using it incorrectly. Please read the provided documentation for this function (in LowLevel.chm).

FYI, I don't like to see my code butchered the way you've done with __setResultToken -> __getResultObject. The majority of the text was /* obsolete/irrelevant code */, which would take only a few seconds of your time to delete. The comments were also irrelevant. Now you can just delete the function as it shouldn't be needed.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Re: __setparamtoken
PostPosted: June 26th, 2010, 4:26 pm 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Lexikos wrote:
tinku99 wrote:
; map := __getTokenValue(aResultToken) ; doesn' work
You were using it incorrectly.
The doc is clear. Wasn't thinking...
Code:
map := __getTokenValue(aResultToken + 0) ; works

Lexikos wrote:
FYI, I don't like to see my code butchered the way you've done with __setResultToken -> __getResultObject...
:oops: Sorry about that.
__getResultObject was sort of a work in progress, which I had a feeling was going down an unnecessary path anyway as you pointed out.
I have removed it.
I do need to write more readable code and present it in a nice way like Chris, you, and many others here do. Thanks for the wakeup call.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 173 posts ]  Go to page Previous  1 ... 7, 8, 9, 10, 11, 12  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google Feedfetcher, Stigg, tidbit and 11 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group