AutoHotkey Community

It is currently May 26th, 2012, 4:42 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 25 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: February 15th, 2008, 11:22 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
@daaonlyfreez:

In the revised COM_InvokeDeep function you posted, should there be a COM_Release(res) just before returning the res value?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 16th, 2008, 12:29 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
If the pointer was released, the value returned to the caller would not be valid. However, pointers retrieved by the function should be released if not returned. (The returned value should be released by the caller when it is no longer needed.)
Code:
COM_InvokeDeep( obj, path )
{
   res := obj
   COM_AddRef(res) ; compensate for loop's Release()
   Loop, Parse, Path, ., ]
   {
         prop := A_LoopField
      value =
      StringGetPos, i, A_LoopField, [
      IfEqual, ErrorLevel, 0 ; contains index
      {
            StringLeft, prop, A_LoopField, %i%
         StringMid, value, A_LoopField, % i+2
      }
         If (value != "") ; contains index
         {
            propobj := COM_Invoke( res, prop )
            itemobj := COM_Invoke( propobj, "Item", value )
            COM_Release(res)
            COM_Release(propobj)

            res := itemobj
         }
         Else
         {
            propobj := COM_Invoke( res, prop )
            COM_Release(res)
            res := propobj
         }
   }
   Return res
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 17th, 2008, 1:20 am 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
@ lexikos,

Thanks for the clarification and code fix. Works perfectly for repeatedly drilling into DOM properties now. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 1st, 2008, 11:13 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
I made a few mods to the versions of COM_InvokeDeep above:
    1) Distinguishes between method calls - for example, document.getElementsByTagName[span] - and element[item] calls - for example, document.childNodes[1]
    2) For the last loop (the element after the last period), one now can pass up to 8 additional arguments to the COM_Invoke command (Note: one can pass up to 10 arguments to a COM object with COM_Invoke, but this function will consume up to two of those arguments).
Rules for use:
    a) If there's a period in an element's name, don't use it. Instead, refer to it by its element ordinal. So, for example, one will occasionally find frames in web pages that are named like the following: this.isanoddly.named.frame . Since COM_InvokeDeep (obviously) parses on the periods, returned pointers will be invalid. Instead, identify the frame by its ordinal: document.frames[0] (for first frame in the document)
    b) don't put quotes (single or double) inside the brackets when passing a parameter to a COM object's method:
      bad: document.getElementsByTagName["span"] or document.getElementsByTagName['span']
      good: document.getElementsByTagName[span]
Beat up on it. It ain't very elegant....
Code:
; Usage:
;   res := COM_InvokeDeep(res, dotted-path, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
; Example:
;   pBody2 := COM_InvokeDeep(pweb, "document.frames[1].document.body")
;   (returns pointer to the body portion of the HTML document located in the second frame on the
;   loaded web page, where pweb is a pointer to the parent IID_IHTMLWindow2.
COM_InvokeDeep(obj, path, arg1="vT_NoNe", arg2="vT_NoNe", arg3="vT_NoNe", arg4="vT_NoNe", arg5="vT_NoNe", arg6="vT_NoNe", arg7="vT_NoNe", arg8="vT_NoNe")
{
   res := obj
   COM_AddRef(res) ; compensate for loop's Release()
   PathCt := 0
   Loop, Parse, Path, .
   {
      PathCt++
   }
   Loop, Parse, Path, ., ]
   {
      prop := A_LoopField
      value =
      StringGetPos, i, A_LoopField, [
      IfEqual, ErrorLevel, 0 ; contains index
      {
         StringLeft, prop, A_LoopField, %i%
         StringMid, value, A_LoopField, % i+2
      }
      If (value != "") ; contains index or parameter passed to a method, enclosed in "[]"
      {
         If (prop = "item") or (RegExMatch(value, "^[0-9]+$") = false) ; "item" already specified, or method call
         {
            If (A_Index < PathCt)
               propobj := COM_Invoke(res, prop, value)
            Else
               propobj := COM_Invoke(res, prop, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
            COM_Release(res)
            res := propobj
         }
         Else
         {
            propobj := COM_Invoke(res, prop)
            If (A_Index < PathCt)
               itemobj := COM_Invoke(propobj, "Item", value)
            Else
               itemobj := COM_Invoke(propobj, "Item", value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
            COM_Release(res)
            COM_Release(propobj)
            res := itemobj
         }
      }
      Else
      {
         If (A_Index < PathCt)
            propobj := COM_Invoke(res, prop)
         Else
            propobj := COM_Invoke(res, prop, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
         COM_Release(res)
         res := propobj
      }
      if !res ; no sense in continuing - object not found (returns 0 or null)
         break
   }
   Return res
}


Last edited by paulwarr on March 20th, 2008, 12:45 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 2nd, 2008, 3:16 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
This is very very wrong: ;)
Code:
propobj := COM_Invoke(res, prop, value, arg1="vT_NoNe", arg2="vT_NoNe", arg3="vT_NoNe", arg4="vT_NoNe", arg5="vT_NoNe", arg6="vT_NoNe", arg7="vT_NoNe", arg8="vT_NoNe")
For each arg, you are passing 1 if the arg was omitted (or explicitly "vT_NoNe"), or 0 otherwise. Too much copy-pasting? :P

Btw, that's getting close to ez_invoke, but with none of its problematic pointer caching...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 2nd, 2008, 2:36 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
lexiKos wrote:
Quote:
Too much copy-pasting?

LOL - I knew that I shouldn't have let my evil twin :twisted: help with this! It's not that I did too much copy-pasting - just the wrong copy-pasting. Original is edited - I think I fixed it. Thanks!
Quote:
Btw, that's getting close to ez_invoke, but with none of its problematic pointer caching...

Yes. I like EZ_Invoke's concept. I just lacked sufficient experience with regular expressions to (among other things) make it release intermediate COM pointer handles that are no longer required, or to prevent it from reusing outdated pointers.

Then, too - for me, at least, the best use for functions like this is to quickly obtain the appropriate pointer for a COM node from its tree, then use the functions of COM_Invoke, COM_ConnectObject, DispatchObj ... to interact directly with that pointer. So I wanted to retain the same function syntax of COM_Invoke et al. A matter of taste.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 15th, 2008, 12:49 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
I thought I'd give paulwarr's COM_InvokeDeep a try... and I found another bug:
Code:
If A_Index < PathCt ; Compares A_Index to the literal text "PathCt".
It should be one of:
Code:
If A_Index < %PathCt%
If (A_Index < PathCt)

Edit: Also, under If (prop = "item")..., it seems res := itemobj should be res := propobj.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 19th, 2008, 7:22 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
Lexikos wrote:
...and I found another bug ... should be one of:
Code:
If A_Index < %PathCt%
If (A_Index < PathCt)
:oops: Fixed now - in both places.
Lexikos wrote:
Also, under If (prop = "item")..., it seems res := itemobj should be res := propobj.
Fixed as well.
In this latest edit, I also added a break to the loop whenever res points to a null.
Thanks, Lexikos! :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 20th, 2008, 6:28 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
You missed the one in the inner-most else. :)
Code:
If A_Index < PathCt


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 20th, 2008, 12:51 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
Lexikos wrote:
You missed the one in the inner-most else. :)
Argh! My evil twin :twisted: is getting quite out of hand.... Fixed now - and again, thanks for the catch! :)


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google [Bot] and 12 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