AutoHotkey Community

It is currently May 26th, 2012, 3:04 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: March 21st, 2008, 9:58 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
COM_InvokeDeep(res, dotted-path, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
(COM Standard Library required)

The COM Standard Library allows us to drill deeply into COM objects. The function below may make that a bit easier for you to use. It parses the "dotted-path" of a COM object (using COM_Invoke to obtain the appropriate pointer to each parent, where objects in a hierarchy are separated by "."). In this example,
    pBody2 := COM_InvokeDeep(pweb, "document.frames[1].document.body")
pBody2 returns a pointer to the body portion of the HTML document located in the second frame of the loaded web page, where pweb is a pointer to the parent IID_IHTMLWindow2.

COM_InvokeDeep can make both method calls - for example, document.getElementsByTagName[span] - and element[item] calls - for example, document.childNodes[1]

For the last loop (the element after the last period), one 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 COM_InvokeDeep 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 that name. 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 use parentheses () inside the "dotted-path" - use square brackets [] instead.

    c) 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]
Sean's COM_Invoke runs the guts of this function. COM_InvokeDeep was developed by lots of folks in the AHK community in this thread (wOxxOm, daonlyfreez, Lexikos, me). Hope it's helpful to you. :)
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
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 22nd, 2008, 1:45 pm 
Offline

Joined: March 16th, 2005, 10:33 pm
Posts: 968
Location: Frisia
Thank you very much for this!

8)

_________________
Image mirror 1mirror 2mirror 3ahk4.me • PM or Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 22nd, 2008, 3:01 pm 
Offline

Joined: September 21st, 2006, 10:04 pm
Posts: 32
Thanks! But all I did was tweak what you and wOxxOm had already posted. And thankfully, Lexikos has a much better eye for code than I do! :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 10th, 2008, 11:30 am 
Offline

Joined: November 14th, 2006, 7:49 pm
Posts: 15
The standard library should have this included, very nice!

_________________
I recommend AutoIt instead of AHK.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 15th, 2008, 10:11 pm 
Offline
User avatar

Joined: December 21st, 2007, 3:14 pm
Posts: 3826
Location: Louisville KY USA
I have modified my copy of this as such
the reason is because when sending a 64 bit integer (Common with account numbers) the value became truncated. very nice by the way :lol: 8) :D
Code:
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),   VarSetCapacity(res,      0)
            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),   VarSetCapacity(res,      0)
            COM_Release(propobj),   VarSetCapacity(propobj,      0)
            res := itemobj
         }
      }
      Else
      {
         If (A_Index < PathCt)
            propobj := COM_Invoke(res, prop)
         Else
         {
         sParams   := 12345678
         int:=False
         Loop,   Parse,   sParams
            If   arg%A_LoopField% is Integer
            {
               int:=true
               Break
            }
         If int
         {   
            Loop,   Parse,   sParams
            {   
                  If   (arg%A_LoopField% == "vT_NoNe")
                  {   
                     arg%A_LoopField% := ""
                     VT_BSTR%A_LoopField%:=""
                  }
                  Else
                     VT_BSTR%A_LoopField%:=8
            }
            propobj := COM_Invoke_(res, prop, VT_BSTR1,arg1,VT_BSTR2,arg2, VT_BSTR3,arg3, VT_BSTR4,arg4, VT_BSTR5,arg5, VT_BSTR6,arg6, VT_BSTR7,arg7, VT_BSTR8,arg8)
         }
         Else
            propobj := COM_Invoke(res, prop, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
       }
         COM_Release(res),   VarSetCapacity(res,      0)
         res := propobj
      }
      if !res ; no sense in continuing - object not found (returns 0 or null)
         break
   }
   Return res
}

_________________
No matter what your oppinion Please join this discussion
Formal request to Polyethene
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 3rd, 2009, 12:24 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Inspired by this post, I wrote this. If there is no objection, I may combine this into COM_Invoke().
Code:
COM_InvokeDeep(pdsp, name,  arg0="vT_NoNe", arg1="vT_NoNe", arg2="vT_NoNe", arg3="vT_NoNe", arg4="vT_NoNe", arg5="vT_NoNe", arg6="vT_NoNe", arg7="vT_NoNe", arg8="vT_NoNe", arg9="vT_NoNe")
{
   If   InStr(name,".")
   {
      name .=   "[["
      COM_AddRef(pdsp)
      Loop,   Parse,   name, .
      {
         name :=   A_LoopField
         If   InStr(name,"[")
         Loop,   Parse,   name, [,'"]
         If   A_Index = 1
            name :=   A_LoopField
         Else If   A_Index = 2
            argn :=   A_LoopField
         Else   bend :=   True
         Else   argn :=   "vT_NoNe"
         If  Not   bend
            pobj :=   COM_Invoke(pdsp,name,argn)
         Else If   argn !=
            pobj :=   COM_Invoke(pdsp,name,argn,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
         Else   pobj :=   COM_Invoke(pdsp,name,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)
         COM_Release(pdsp)
         pdsp :=   pobj
      }
      Return   pdsp
   }
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 3rd, 2009, 9:01 pm 
Offline
User avatar

Joined: December 21st, 2007, 3:14 pm
Posts: 3826
Location: Louisville KY USA
Fabulously shorter and distinct.
Couple things come to mind
I for one and perhaps I am the only one :?
Use COM_InvokeDeep with excell and account numbers. As Invoke will truncate large numbers it might be good to allow BSTR
consider the following code that works untill we get a large number
Code:
COM_CoInitialize()
comoWB:=COM_InvokeDeep(oExcel:=COM_ActiveXObject("Excel.Application")
               ,"workbooks.add")
COM_Invoke(oExcel, "Visible=", true)
COM_Release(oExcel),oExcel:=0

;~ COM_InvokeDeep(oWB
;~                ,"worksheets.item[Name or sheetn style reference].cells.item[Column].item[Row].value"
;~                ,"Some Value to write")
loop 10 ; loop thru cells in a workbook
COM_InvokeDeep(oWB
               ,"worksheets.item[sheet1].cells.item[" A_Index "].item[2].value"
               ,A_Index)
COM_Release(oWB),oWB:=0
COM_CoUninitialize()

if i pass say a 16 digit integer it of course gets truncated
Now I could easily for my own private purposes test the arg0 to see if its an digits only and sub in COM_Invoke_() and use 8 to make it a string for the type
But I'm having some dificulty making it as short and clean as yours
My previous post in this thread describes the best tactic i could come up with

Ideas?

_________________
No matter what your oppinion Please join this discussion
Formal request to Polyethene
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 4th, 2009, 1:05 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
tank wrote:
As Invoke will truncate large numbers it might be good to allow BSTR
Code:
if  var is integer
may be rewritten in AHK as
Code:
if  var+0!="" && !InStr(var,".")

So, something like
Code:
if  var is int32
can be written as
Code:
if  var+0!="" && !InStr(var,".") && var<0x80000000 && var>=-0x80000000


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 4th, 2009, 2:21 am 
Offline
User avatar

Joined: December 21st, 2007, 3:14 pm
Posts: 3826
Location: Louisville KY USA
This is what i ended up with in the end it was shorter to just do this
Code:
COM_InvokeDeep(pdsp, name,  arg0="vT_NoNe", arg1="vT_NoNe", arg2="vT_NoNe", arg3="vT_NoNe", arg4="vT_NoNe", arg5="vT_NoNe", arg6="vT_NoNe", arg7="vT_NoNe", arg8="vT_NoNe", arg9="vT_NoNe")
{
   If   InStr(name,".")
   {
   name .=   "[["
   COM_AddRef(pdsp)
   Loop,   Parse,   name, .
   {
      name :=   A_LoopField
      If   InStr(name,"[")
         Loop,   Parse,   name, [,'"]
            If   A_Index = 1
               name :=   A_LoopField
            Else If   A_Index = 2
               argn :=   A_LoopField
            Else   bend :=   True
      Else   argn :=   "vT_NoNe"
      If  Not   bend
         pobj :=   COM_Invoke(pdsp,name,argn)
      Else If   argn !=
            pobj :=   COM_Invoke(pdsp,name,argn,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
      Else   pobj := COM_Invoke_(pdsp,name
                                 ,BSTR0:=(arg0!="vT_NoNe" ? 8 : ""),arg0
                                 ,BSTR1:=(arg1!="vT_NoNe" ? 8 : ""),arg1
                                 ,BSTR2:=(arg2!="vT_NoNe" ? 8 : ""),arg2
                                 ,BSTR3:=(arg3!="vT_NoNe" ? 8 : ""),arg3
                                 ,BSTR4:=(arg4!="vT_NoNe" ? 8 : ""),arg4
                                 ,BSTR4:=(arg5!="vT_NoNe" ? 8 : ""),arg5
                                 ,BSTR5:=(arg6!="vT_NoNe" ? 8 : ""),arg6
                                 ,BSTR6:=(arg7!="vT_NoNe" ? 8 : ""),arg7
                                 ,BSTR7:=(arg8!="vT_NoNe" ? 8 : ""),arg8
                                 ,BSTR8:=(arg9!="vT_NoNe" ? 8 : ""),arg9)

      COM_Release(pdsp)
      pdsp :=   pobj
   }
   Return   pdsp
   }
}
and it works pretty fast
I am certain that someone much smarter than me will resolve this in a short method using Sean's suggestions. But I dont seem equal to the task

Sean I(am i the only one?) have no objection to either this or any other version of Deep i have long been adding it any how

_________________
No matter what your oppinion Please join this discussion
Formal request to Polyethene
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 4th, 2009, 3:14 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
tank wrote:
This is what i ended up with in the end it was shorter to just do this
You don't need to use COM_Invoke_(). What I meant was to replace the following condition in COM_Invoke()
Code:
If   arg%A_LoopField% Is Not Integer
with
Code:
If   arg%A_LoopField%+0=="" || InStr(arg%A_LoopField%,".") || arg%A_LoopField%>=0x80000000 || arg%A_LoopField%<-0x80000000

Quote:
Sean I(am i the only one?) have no objection to either this or any other version of Deep i have long been adding it any how
I didn't try to incorporate it as I hadn't decided the level of support, should be full support or sufficient with limited support, and there already existed ones like ez_invoke() and/or COM_InvokeDeep(). Anyway, I added to COM.ahk the above condition after commenting out, so, you may just switch the two. I also incorporated the code so as to call COM_InvokeDeep() directly inside COM_Invoke(). You may download and experiment it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 4th, 2009, 3:26 am 
Offline
User avatar

Joined: December 21st, 2007, 3:14 pm
Posts: 3826
Location: Louisville KY USA
Doh i almost tried that but im pretty dumb thanks I Have Tested :D
I tested out with the alternate if statement and it works perfectly with my large integers
Thank you tons Sean :D
you are still my hero

_________________
No matter what your oppinion Please join this discussion
Formal request to Polyethene
Image


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC [ DST ]


Who is online

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