 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Do you think this tutorial is beneficial to the AHK Community? |
| Yeah, I think this tutorial is a great value-add to the Community. |
|
86% |
[ 91 ] |
| Nope - I think this tutorial is a waste of web space. |
|
0% |
[ 1 ] |
| I think this tutorial would be better if it incorporated AHK_L & COM_L. |
|
12% |
[ 13 ] |
|
| Total Votes : 105 |
|
| Author |
Message |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sat Nov 14, 2009 6:33 am Post subject: |
|
|
I suggest to refer to Internet Explorer Architecture.
And, yes, tank's code will work. If already obtained pwb, however, it's a bit pointless to go through that step, IMO. My suggestion was to demonstrate the means to obtain directly Window or Document objects and start from them. Obtaining Document object has been used many times in the forum, but obtaining Window object has been used little.
http://www.autohotkey.com/forum/viewtopic.php?t=19256&start=28
| Code: | pacc := COM_AccessibleObjectFromWindow(hIESrv) ; window handle of Internet Explorer_Server
pwin := COM_QueryService(pacc, "{332C4427-26CB-11D0-B483-00C04FD90119}")
COM_Release(pacc) |
|
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Sat Nov 14, 2009 6:39 am Post subject: |
|
|
@Sean the reason I avoid this method is because it requires the tab to be the active one. Obtaining the pwb avoids this and allows multiple tabs within a single browser to be automated without regard to being selected or not
However you are correct if it doesn’t matter if the tab is the active one yours is more direct to the point.
I might also suggest that in my own production environment with 300’ish users that this (MSAA) method can fail (not often and not consistently). I have yet to identify why. This is the other reason checking the shellWindows collection is my preferred choice
I will point out i hadnt seen AccessibleObjectFromPoint demonstrated any where else and my knowledge of MSAA is very weak
The iweb functions are the effort of 2 years attempting to get the best stability with ahk to automate on clients spread across 3 physical sites wehre the end user can also mess things up in browser settings. They are not full proof by any means but i Saw a 60+ percent drop in automation failure reports when I moved accessability out of the equation _________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sat Nov 14, 2009 7:44 am Post subject: |
|
|
| tank wrote: | | @Sean the reason I avoid this method is because it requires the tab to be the active one. | This method doesn't require the tab to be the active one. It just needs to obtain the correct window handle of the corresponding Internet Explorer_Server which I agree may sometimes be hard to identify in practice though.
| Quote: | I might also suggest that in my own production environment with 300’ish users that this (MSAA) method can fail (not often and not consistently). I have yet to identify why. This is the other reason checking the shellWindows collection is my preferred choice
 | Yes, MSAA is too old, I also found it awkward often. Anyway, I didn't suggest to replace already established methods with this, just demonstration that it's possible when mentioning conceptually Window object is the top level one in DOM.
| Quote: | | I will point out i hadnt seen AccessibleObjectFromPoint demonstrated any where else | IIRC, I used it many times in the posted scripts. Anyway it may be useful to obtain directly IHTMLElement in DOM. As a matter of fact, my first plan for IE HTML Element Spy was utilizing it, however, it didn't provide the fine granularity needed, so I took a different/current route.
| Quote: | | The iweb functions are the effort of 2 years attempting to get the best stability with ahk to automate on clients spread across 3 physical sites wehre the end user can also mess things up in browser settings. They are not full proof by any means but i Saw a 60+ percent drop in automation failure reports when I moved accessability out of the equation | Oh I see. Thanks for valuable info that I can't possibly gain myself. |
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Sat Nov 14, 2009 8:29 am Post subject: |
|
|
| Sean wrote: | | Yes, MSAA is too old, I also found it awkward often. Anyway, I didn't suggest to replace already established methods with this, just demonstration that it's possible when mentioning conceptually Window object is the top level one in DOM. | I am glad you did i forgot about it since I abandoned ahklerners injectJS function
| Sean wrote: | | This method doesn't require the tab to be the active one. It just needs to obtain the correct window handle of the corresponding Internet Explorer_Server which I agree may sometimes be hard to identify in practice though. | Can you think of any that don’t require it to be the top most tab?
FYI though I wrote them I have yet to widely use iWeb_clickHref iWeb_clickValue Mostly I use the iWeb_getwin and the iWeb_setDomObj and iWeb_getDomObj functions. so the others aren’t well tested
| Sean wrote: | | Anyway it may be useful to obtain directly IHTMLElement in DOM. | At any rate I see how its useful to retrieve info with this but am unsure how one would go about using it in a larger script that uses multiple pages and or sites.
The reason for iWeb_DomWin is because there are in limited cases sites where there are script permissions and doing this bypass that security restriction I believe its related to the security zone setting allow websites to use restricted protocols for active content But I cant prove it
It seems we mainly agree on the point of using the pwb might be the most effective way to go even if it isn’t the only way
Another way to grab an element would be to try and find unique text and possibly request an offset of elements using the find method. Since this method traverses frames if unique text is avail it may be the easiest for users to use with minimal understanding of DOM and no understanding of JavaScript
There have been members of our team new to scripting that rely on this for the automation jobs
| Code: | element:=IE_Find("Some unique text")
Com_invoke(element,"click")
IE_Find(needle,win="A",property="",offset=0)
{
If (win=="A")
WinGetTitle,win,%win% ahk_class IEFrame
StringSplit,wins,win,-
_autotrim:=A_AutoTrim
AutoTrim,On
wins1=%wins1%
AutoTrim,%_autotrim%
If psh := COM_CreateObject("Shell.Application") {
If psw := COM_Invoke(psh, "Windows") {
Loop, % COM_Invoke(psw, "Count")
If pwb := (InStr(COM_Invoke(psw,"Item[" A_Index-1 "].LocationName"),wins1) && InStr(COM_Invoke(psw,"Item[" A_Index-1 "].FullName"), "iexplore.exe")) ? COM_Invoke(psw,"Item", A_Index-1) :
Break
COM_Release(psw)
}
COM_Release(psh)
}
If !pwb
Return
If !pWin:=COM_QueryService(pwb, "{332C4427-26CB-11D0-B483-00C04FD90119}", "{332C4427-26CB-11D0-B483-00C04FD90119}")
{
COM_Release(pwb)
Return
}
If oRange:=COM_Invoke(pWin,"document.body.createTextRange")
{
COM_Invoke(oRange,"findText",needle)
_res:=property ? COM_Invoke(pWin,"Document.all.item[" COM_Invoke(oRange,"parentElement.sourceIndex")+offset "]." property) : COM_Invoke(pWin,"Document.all.item", COM_Invoke(oRange,"parentElement.sourceIndex")+offset)
COM_Release(oRange)
}
COM_Release(pWin)
COM_Release(pwb)
Return _res
} |
_________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sat Nov 14, 2009 12:35 pm Post subject: |
|
|
| tank wrote: | | Can you think of any that don’t require it to be the top most tab? | It can be used sort of as the replacement of ShellWindows whose cons is that it requires Explorer shell. As I switched to 64bit Win7 a few days ago, I became curious and tested it also on 64bit IE8 on 64bit Win7, it still worked flawlessly.
| Code: | DetectHiddenWindows, On
WinGet, ControlList, ControlList, ahk_class IEFrame
RegExMatch(ControlList, "(?<=Internet Explorer_Server)\d+(?!.*Internet Explorer_Server)", nCount)
Loop, % nCount
{
ControlGet, hWnd, hWnd,, Internet Explorer_Server%A_Index%, ahk_class IEFrame
window := COM_Enwrap(COM_QueryService(COM_AccessibleObjectFromWindow(hWnd), "{332C4427-26CB-11D0-B483-00C04FD90119}"))
; oWeb := COM_Enwrap(COM_QueryService(window, "{0002DF05-0000-0000-C000-000000000046}"))
MsgBox % window.document.url
}
|
OK, I see your point. I also had to do the similar for cross domains across frames in IE HTML Element Spy script. |
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Sat Nov 14, 2009 6:32 pm Post subject: |
|
|
Very interesting Sean i learned something from you that i previously hadnt known (as usual) For the sake of learing im gonna play with the code you have as it relates to IE 7(i hope) as well _________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Mon Nov 16, 2009 3:06 am Post subject: |
|
|
Jethrow given some recent questions since I have used these methods on all of the OS's and browsers including Vista and 7
COM DOM and HTML are Industry Standards They are supported in IE versions 4.0 and up and I have tested AHK and Sean's COM library on Windows 2k XP Vista and 7 as well as each of the versions of IE(I had 4.0 on a Bart PE implementation for a while) Obviously tabs were only introduced as of IE7. If COM does not work for your web automation needs it is not specifically related to the browser version or OS. It could perhaps be due to BHO's common in my workplace as a problem or specific security settings in a corp. environment.
BHO’s by far make up the majority of the items that cause COM to fail to automate a browser when the code is correct. Usually the interference is in the form of creating hidden framesets. The most common I encounter in a secure environment is OWS which comes with office and is a BHO for SharePoint. Some Antivirus install BHO's as well but as of yet I have not seen those create such a problem _________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Tue Nov 17, 2009 3:21 am Post subject: |
|
|
the iWebBrowser2 Learner has been updated to give example iWeb function calls with frame references
the iWeb functions have been updated to allow frame references and bypass cross domain restrictions I made this update only because Sinkfaze put so much effort himself into trying
I also noticed a bug and corrected it with identifying the page title _________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
UncleScrooge
Joined: 14 Apr 2009 Posts: 75 Location: Italy
|
Posted: Mon Nov 30, 2009 1:04 pm Post subject: |
|
|
Hi all
and compliments for the job done, even though I often understand less tan 30% of it... but it had been very stimulating: spent a couple of evenings surfing through HTML DOM learning pages at W3Schools.
wouldnt bother anybody with stupid questions but I'm stuck in this:
I got the Sean function IE_DocumentComplete working flawlessly to get my particular URL open
| Code: | sUrl := "http://127.0.0.1:81/Upload.html"
COM_Init()
pweb := COM_CreateObject("InternetExplorer.Application")
sink := COM_ConnectObject(pweb, "IE_")
bComplete := False
COM_Invoke(pweb, "Navigate", sUrl)
While !bComplete
Sleep, 500
MsgBox, 36, , Do you want it visible?
IfMsgBox, Yes
COM_Invoke(pweb, "Visible", True)
|
I work in industrial automation - process control and our controllers' network exchange informations thru a MODBUS and interface with the outer world via a WEB server (each controller owns one).
Here the address h t t p :// 127.0.0.1:81/ refers to a controller simulator running on my PC. The "Upload.html" document is the user interface to handle files back and forth:
now, before I start doing anything at all, as Sean'function tells me that the url loading procedures has terminated, I want to make it sure the document is showing me the expected things. This will also tell me that I'm really communicating to a controller (each controller owns a document such as http:\\xxx.xxx.xxx.xxx\Upload.html, if the document doesn't load up correctly we might have a network problem -cabling or else).
So I thought the easiest way was to check if the browser can return the document header contents (<h1>) that I know to be:
File management
(see fig)
As shown earlier in this post I imagined it would had been easy to ask the IE object to retrieve it, and in fact when I try to inject javascript through the URL address control like this:
| Code: | | javascript:alert(document.getElementsByTagName("h1")[0].innerHTML) |
I got the message box beeping me: "File management"
wow: I figured it was a piece o'cake to push it in my AHK as suggested like this:
| Code: | | MsgBox % COM_Invoke(pwb, "document.getElementsByTagName([h1]).item[0].innerHTML") |
no such luck... all I got is a barrage of messages from COM telling that all the components (functions) of the COM_Invoke param (document getElementsByTagName item and innerHTML cannot be found:
what am I doing wrong?
thnx for any answer
Ps: I've tried all the variants:
| Code: | document.getElementsByTagName[h1].item[0].innerHTML
document.getElementsByTagName[h1][0].innerHTML
|
with no better results: all I got is a higher or lower number of error messages from COM
Last edited by UncleScrooge on Mon Nov 30, 2009 5:46 pm; edited 2 times in total |
|
| Back to top |
|
 |
sinkfaze
Joined: 18 Mar 2008 Posts: 5044 Location: the tunnel(?=light)
|
|
| Back to top |
|
 |
tank
Joined: 21 Dec 2007 Posts: 3700 Location: Louisville KY USA
|
Posted: Mon Nov 30, 2009 1:52 pm Post subject: |
|
|
| sinkfaze wrote: | Try this:
| Code: | | COM_Invoke(pwb,"document.all[h1].innerHTML") |
| um h1 is a tag not an id so that shouldnt work
| Code: | | COM_Invoke(pwb,"document.all.tags[h1].item[0].innerHTML") |
| Code: | | COM_Invoke(pwb,"document.getElementsByTagName[h1].item[0].innerHTML") | should simlarly work but havent tested it _________________
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed; |
|
| Back to top |
|
 |
sinkfaze
Joined: 18 Mar 2008 Posts: 5044 Location: the tunnel(?=light)
|
Posted: Mon Nov 30, 2009 2:01 pm Post subject: |
|
|
| tank wrote: | | um h1 is a tag not an id so that shouldnt work |
Ugh...and I read that before I answered, too...sorry. _________________ Try Quick Search for Autohotkey or see the tutorial for newbies. |
|
| Back to top |
|
 |
jethrow
Joined: 24 May 2009 Posts: 1907 Location: Iowa, USA
|
Posted: Mon Nov 30, 2009 2:09 pm Post subject: |
|
|
| UncleScrooge wrote: | all I got is a barrage of messages from COM telling that all the components (functions) of the COM_Invoke param (document getElementsByTagName item and innerHTML cannot be found
... Ps: I've tried all the variants:
| Code: | document.getElementsByTagName[h1].item[0].innerHTML
document.getElementsByTagName[h1][0].innerHTML
|
with no better results: all I got is a higher or lower number of error messages from COM | If you are getting a COM Error when trying to invoke the document object, the document isn't accessible (perhaps not loaded).
| UncleScrooge wrote: | | Code: | sUrl := "http://127.0.0.1:81/Upload.html"
COM_Init()
pweb := COM_CreateObject("InternetExplorer.Application")
sink := COM_ConnectObject(pweb, "IE_")
bComplete := False
COM_Invoke(pweb, "Navigate", sUrl)
While !bComplete
Sleep, 500
MsgBox, 36, , Do you want it visible?
IfMsgBox, Yes
COM_Invoke(pweb, "Visible", True) |
| If this is all your code, you aren't using Sean's DocumentComplete method correctly. Please post all your code (or at least all your code that is relevant - ie. How is your While-loop breaking?). _________________
- in case I forgot to smile
Basic Webpage Controls
COM Object Reference |
|
| Back to top |
|
 |
UncleScrooge
Joined: 14 Apr 2009 Posts: 75 Location: Italy
|
Posted: Mon Nov 30, 2009 5:07 pm Post subject: |
|
|
| jethrow wrote: | ...........
If this is all your code, you aren't using Sean's method correctly. Please post all your code (or at least all your code that is relevant - ie. How is your While-loop breaking?). |
no, obviuosly not. sorry my mistake, here is the complete thing.
| Code: |
#Persistent
sUrl := "http://127.0.0.1:81/Upload.html"
COM_Init()
pweb := COM_CreateObject("InternetExplorer.Application")
sink := COM_ConnectObject(pweb, "IE_")
bComplete := False
COM_Invoke(pweb, "Navigate", sUrl)
While !bComplete
Sleep, 500
MsgBox, 36, , Do you want it visible?
IfMsgBox, Yes
COM_Invoke(pweb, "Visible", True)
;MsgBox % COM_Invoke(pwb, "document.getElementsByTagName[h1][0].innerHTML")
;MsgBox % COM_Invoke(pwb,"document.all.tags[h1].item[0].innerHTML")
MsgBox % COM_Invoke(pwb,"document.getElementsByTagName[h1].item[0].innerHTML")
MsgBox, 36, , Do you want to close it?
IfMsgBox, Yes
COM_Invoke(pweb, "Quit")
COM_DisconnectObject(sink)
COM_Release(pweb)
COM_Term()
#q::ExitApp ;WIN key + q to terminate this script
Return
OnComplete:
bComplete := True
Return
IE_DocumentComplete(prms, sink)
{
If NumGet(NumGet(prms+0)+24) = NumGet(sink+12)
SetTimer, OnComplete, -10
/* more rigorous way
COM_Release(punk1:=COM_QueryInterface(NumGet(NumGet(prms+0)+24),0))
COM_Release(punk2:=COM_QueryInterface(NumGet(sink+12),0))
If (punk1 = punk2)
SetTimer, OnComplete, -10
*/
}
IEReady(hIESvr = 0)
{
If Not hIESvr
{
Loop, 50
{
ControlGet, hIESvr, hWnd, , Internet Explorer_Server1, A ; ahk_class IEFrame
If hIESvr
Break
Else Sleep 100
}
If Not hIESvr
Return """Internet Explorer_Server"" Not Found."
}
Else
{
WinGetClass, sClass, ahk_id %hIESvr%
If Not sClass == "Internet Explorer_Server"
Return "The specified control is not ""Internet Explorer_Server""."
}
COM_Init()
If DllCall("SendMessageTimeout", "Uint", hIESvr, "Uint", DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT"), "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 1000, "UintP", lResult)
&& DllCall("oleacc\ObjectFromLresult", "Uint", lResult, "Uint", COM_GUID4String(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}"), "int", 0, "UintP", pdoc)=0
&& pdoc && pweb:=COM_QueryService(pdoc,IID_IWebBrowserApp:="{0002DF05-0000-0000-C000-000000000046}")
{
While, COM_Invoke(pweb, "ReadyState") <> 4
Sleep, 500
While, COM_Invoke(pweb, "document.readyState") <> "complete"
Sleep, 500
COM_Release(pweb)
}
COM_Release(pdoc)
COM_Term()
Return pweb ? "DONE!" : False
}
|
that line in red is actually quitting the browser session so I guess the pwb object is open and responding correctly... not when I try to access the document though. and as you can see by the commented lines not even tank's suggestions work (btw I love that pissed off Yoda. just great)
the code on top (autoexec section) is of course just a bunch of lines to test functionalities so to manipulate IE (the finished code shouldn't even make IE object visible).
I've tried these and they work wonders (of-bloody-course):
| Code: |
;js_Snippet = javascript`:document`.getElementsByTagName`(`"h1`"`)`[0`]`.innerHTML`;
js_Snippet = javascript`:alert`(document`.getElementsByTagName`(`"h1`"`)`[0`]`.innerHTML`)`;
COM_Invoke(pweb, "Navigate", js_Snippet)
|
which I seem to understand means that, since pweb (the IE object) works fine, I need another handle to reference the document object to start using its exposed functions (properties and methods).
Am I getting it right?... _________________ Intel Centrino @ 2.8GHz
4 GB RAM
WIN XP SP3 |
|
| Back to top |
|
 |
jethrow
Joined: 24 May 2009 Posts: 1907 Location: Iowa, USA
|
Posted: Mon Nov 30, 2009 5:18 pm Post subject: |
|
|
- Why are you using pweb & pwb? Should be: | Code: | | MsgBox % COM_Invoke(pweb,"document.getElementsByTagName[h1].item[0].innerHTML") |
On a side-note, this might be a little simpler for your javascript: | Code: | | js_Snippet := "javascript:alert(document.getElementsByTagName('h1')[0].innerHTML)" |
_________________
- in case I forgot to smile
Basic Webpage Controls
COM Object Reference |
|
| 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
|