AHK에서 가능한 COM 인터넷 익스플로러 및 GUI 브라우저
IE and Gui Browser Com Tutorial Goto page 1, 2, 3, 4, 5 Next |
Basic understanding of COM Pointer
AHK COM Internet Explorer and Gui Browser documentation
First if you have not done so an understanding of basic AHK is required
see the quick-start tutorial.
I will simply ignore basic syntax questions like when to or not to use %
Using Seans COM library to automate web tasks takes some learning how but
removes the need to use some other clumbsy tactics like sending javascript thru address bar or using image search etc.
Many will find this tutorial over there head and that is fine. take your time to learn the lessons in this tutorial and soon you will know some very usefull skills.
this tutorial will make use of HTML DOM
DHTML
as well as JavaScript
you can also check out this post some time ago by daononlyfreeze
http://www.autohotkey.com/forum/viewtopic.php?t=6597&start=0
I will not be giving a tutorial on these but the links included should adequetely cover these topics from a learining perspective
I also want to make it clear you will not find any nice wrapper functions. Nor did COM or am the origional conceiver of the subject matter.
What I have done is taken posts of questions and answers and tidbits from all over the forum and Created a tutorial from it.
- If you want to thank someone thank the following
Chris Malet Autohotkey creator
Sean who created the COM functions
Lexikos whose in dept understanding and hand holding has given me the understanding necesary to do this
ahklerner whom Posted the first well written function to push javascritp to a webpage via ahk that I had found
First and foremost I am like you the benificiery of these Genious
Learning I beleive takes a real life example.
lets define our automation job
I like Logging into Gmail
our other progressively more robust learning will come in the version of
selecting an looking up a word on dictionary .com
recording data from a web result and reacting to those results
For the most part the COM library is based on actual C++ so i will include the relavent MSDN but will not go into to much detail as they are documented in the MSDN quite adequetly
it is not entirely necesary that you fully grasp these. I put the links here for those who want to broaden there depth of understanding. It is however necesary to have even the most highlevel understanding of there purpose
Goals
- Basic understanding of COM Pointer
Understanding of COM_CreateObject MSDN
- MSDN does a fine job explaining this i wont re hash it just remember creates a parent object for use with our invoke calls
Understanding of COM_AtlAxGetControl MSDN
Understanding of COM_AtlAxCreateContainer MSDN
- we will be using COM_AtlAxCreateContainer and COM_AtlAxGetControl in our examples just remember this is a way of getting a control pointer from a window control that we are in our case creating
Understanding of COM_Invoke MSDN
- Sean gives us a Basic Example. Basically this is an execution function. if you need to get or set a value execute a method of move from a parent object to a member object you can do so from COM_Invoke
Understanding of COM_Release MSDN
- In the interest of trying to dumb this down here goes.
everytime you create a pointer to an object or interface you should release it for each time you create it you do not release strings just object and interface pointers. Its a way of freeing memory and its good for your program but well if you dont do it the worst that can happen on most beginner scripts is some semi slow performance
Understanding of COM_QueryService MSDN
- In our examples we will use this function to get one object pointer from another using CLSID. there are instances when getting pwin can bypass some security zone settings which can cause scripts to fail at times
Understanding of COM_QueryInterface MSDN
- Returns a pointer to a specified interface on an object to which a client currently holds an interface pointer.
Understanding of COM_ConnectObject MSDN
- Just remember this is how we can setup ahk access to events. Gonna be a much later before I cover events but be patient
It is also imperitive that we have an understanding of the following
Basic Understanding of IE architecture MSDN
Basic understanding of the webrowser object for Gui MSDN [url=http://msdn.microsoft.com/en-us/library/aa741312(VS.85).aspx]MSDN[/url]
For our automation tasks we will be aquireing and interface pointer to iWebrowser2 through out my examples you will see this reflected as pwb
- First I want to remind all please have COM in the standard libraries such as c:\program files\autohotkey\lib
- Always initialize COM once per script
If you will not be using a GUI object
Code: |
COM_Init() |
- With GUI
Code: |
COM_AtlAxWinInit() |
- there is no need to do it more than once. Nor is there any need to do both when in dowbt use COM_AtlAxWinInit()
There are quite a few ways to create this interface pointer I will try cover the most common usefull ones
For our, or really any purpose we can use a GUI browser or an instance of IE
- New instance of IE
Code: |
pwb := COM_CreateObject("InternetExplorer.Application") |
Code: |
COM_Invoke(pwb , "Visible=", "True") ;"False" ;"True" ; |
Code: |
COM_Init() pwb := COM_CreateObject("InternetExplorer.Application") COM_Invoke(pwb , "Visible=", "True") ;"False" ;"True" ; |
Firstly the MSDN and then the code
Code: |
url:="http://www.google.com" COM_Invoke(pwb, "Navigate", url) |
Code: |
COM_Init() pwb := COM_CreateObject("InternetExplorer.Application") COM_Invoke(pwb , "Visible=", "True") ;"False" ;"True" ; url:="http://www.google.com" COM_Invoke(pwb, "Navigate", url) url:="http://www.Yahoo.com" COM_Invoke(pwb, "Navigate", url) |
Certainly we could
Code: |
Sleep,10000 ; 10 second pause |
Code: |
rdy:=COM_Invoke(pwb,"readyState") |
Code: |
loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break |
OK put it all together now
Code (Expand): |
COM_Init() pwb := COM_CreateObject("InternetExplorer.Application") COM_Invoke(pwb , "Visible=", "True") ;"False" ;"True" ; url:="http://www.google.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break url:="http://www.Yahoo.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break MsgBox, 262208, Done, Goodbye,5 COM_Invoke(pwb, "Quit") COM_Term() |
- Lets Focus on a GUI version of what we have done above
- First you guessed it we need to create a pwb.
Code: |
Gui, +LastFound +Resize ;pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),top,left,width,height, "Shell.Explorer") ) ;left these here just for reference of the parameters pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),0,0,510,600, "Shell.Explorer") ) |
Code: |
gui,show, w510 h600 ,Gui Browser |
Lets put this together with the navigation we had from the instance of IE dont forget we use the COM_AtlAxWinInit() to initialize com since we are using a GUI control COM_AtlAxWinInit()
Code (Expand): |
COM_AtlAxWinInit() Gui, +LastFound +Resize ;pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),top,left,width,height, "Shell.Explorer") ) ;left these here just for reference of the parameters pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),0,0,510,600, "Shell.Explorer") ) gui,show, w510 h600 ,Gui Browser ;take from the IE example url:="http://www.google.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break url:="http://www.Yahoo.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break MsgBox, 262208, Done, Goodbye,5 Gui, Destroy COM_AtlAxWinTerm() ExitApp |
There are some differences in our Gui Browser
We cant do any of the follwoing
- Keyboard navigation
use shortcut keys like ctrl + m to submit a form
send tab keystrokes
resize our browser with the window
For all but the resize problem we use the following code
This will be our first exposure to the COM_QueryInterface MSDN
We use this to gain access to the IOleInPlaceActiveObject_Interface MSDN based on CLSID. which Enables a top-level container to manipulate an in-place object.(ie send keystrokes wehn normally only the gui control could receive them
Code (Expand): |
;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.ole.interop.ioleinplaceactiveobject(VS.80).aspx IOleInPlaceActiveObject_Interface:="{00000117-0000-0000-C000-000000000046}" pipa := COM_QueryInterface(pwb, IOleInPlaceActiveObject_Interface) OnMessage(WM_KEYDOWN:=0x0100, "WM_KEYDOWN") OnMessage(WM_KEYUP:=0x0101, "WM_KEYDOWN") WM_KEYDOWN(wParam, lParam, nMsg, hWnd) { ; Critical 20 ;tooltip % wparam If (wParam = 0x09 || wParam = 0x0D || wParam = 0x2E || wParam = 0x26 || wParam = 0x28) ; tab enter delete up down ;If (wParam = 9 || wParam = 13 || wParam = 46 || wParam = 38 || wParam = 40) ; tab enter delete up down { WinGetClass, Class, ahk_id %hWnd% ;tooltip % class If (Class = "Internet Explorer_Server") { Global pipa VarSetCapacity(Msg, 28) NumPut(hWnd,Msg), NumPut(nMsg,Msg,4), NumPut(wParam,Msg,8), NumPut(lParam,Msg,12) NumPut(A_EventInfo,Msg,16), NumPut(A_GuiX,Msg,20), NumPut(A_GuiY,Msg,24) DllCall(NumGet(NumGet(1*pipa)+20), "Uint", pipa, "Uint", &Msg) Return 0 } } } |
Code: |
GuiSize: WinMove, % "ahk_id " . COM_AtlAxGetContainer(pwb), , 0,0, A_GuiWidth, A_GuiHeight return |
Code (Expand): |
COM_AtlAxWinInit() Gui, +LastFound +Resize ;pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),top,left,width,height, "Shell.Explorer") ) ;left these here just for reference of the parameters pwb := COM_AtlAxGetControl(COM_AtlAxCreateContainer(WinExist(),0,0,510,600, "Shell.Explorer") ) ;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.ole.interop.ioleinplaceactiveobject(VS.80).aspx IOleInPlaceActiveObject_Interface:="{00000117-0000-0000-C000-000000000046}" pipa := COM_QueryInterface(pwb, IOleInPlaceActiveObject_Interface) OnMessage(WM_KEYDOWN:=0x0100, "WM_KEYDOWN") OnMessage(WM_KEYUP:=0x0101, "WM_KEYDOWN") gui,show, w510 h600 ,Gui Browser ;take from the IE example url:="http://www.google.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break url:="http://www.Yahoo.com" COM_Invoke(pwb, "Navigate", url) loop If (rdy:=COM_Invoke(pwb,"readyState") = 4) break return GuiClose: Gui, Destroy COM_CoUninitialize() COM_AtlAxWinTerm() ExitApp GuiSize: WinMove, % "ahk_id " . COM_AtlAxGetContainer(pwb), , 0,0, A_GuiWidth, A_GuiHeight return WM_KEYDOWN(wParam, lParam, nMsg, hWnd) { ; Critical 20 ;tooltip % wparam If (wParam = 0x09 || wParam = 0x0D || wParam = 0x2E || wParam = 0x26 || wParam = 0x28) ; tab enter delete up down ;If (wParam = 9 || wParam = 13 || wParam = 46 || wParam = 38 || wParam = 40) ; tab enter delete up down { WinGetClass, Class, ahk_id %hWnd% ;tooltip % class If (Class = "Internet Explorer_Server") { Global pipa VarSetCapacity(Msg, 28) NumPut(hWnd,Msg), NumPut(nMsg,Msg,4), NumPut(wParam,Msg,8), NumPut(lParam,Msg,12) NumPut(A_EventInfo,Msg,16), NumPut(A_GuiX,Msg,20), NumPut(A_GuiY,Msg,24) DllCall(NumGet(NumGet(1*pipa)+20), "Uint", pipa, "Uint", &Msg) Return 0 } } } |
Yes it is the choice of method is yours to make I am giving you tools but there are benifets to both you will have to discover these in your own time and based on projects you endeavor
We will endeavor some other GUI excersizes later for breivity im moving us back to IE
Before we go on there is one more method of getting a pwb
- Re-using exisitng instances of IE
The Shell.Application has a collection of windows. Be warned this will include windows explorer and IE. But best of all each instance of IE or a tab within is a separate instance of iWebrowser2. So this approach is ideal for itenerating all of those tabs and windows
The windows collection like almost everything in Microsofts world is 0 based meaning first object is 0 second is 1 .... etc
Code: |
psw := COM_Invoke(psh:=COM_CreateObject("Shell.Application"), "Windows"), |
Code: |
COM_Invoke(psw := COM_Invoke(psh:=COM_CreateObject("Shell.Application"), "Windows"), "Count") |
Much ias a despise using window titles to distinguish windows its still one of the best ways
Code: |
pageSearched:="Google" Loop, % COM_Invoke(psw := COM_Invoke(psh:=COM_CreateObject("Shell.Application"), "Windows"), "Count") { LocationName:=COM_Invoke(pwb:=COM_Invoke(psw, "Item", A_Index-1), "LocationName") IfInString,LocationName,%pageSearched% Break COM_Release(pwb) ;didnt break so release the one we didnt use } |
Code: |
pageSearched:="google" Loop, % COM_Invoke(psw := COM_Invoke(psh:=COM_CreateObject("Shell.Application"), "Windows"), "Count") { LocationName:=COM_Invoke(pwb%a_index%:=COM_Invoke(psw, "Item", A_Index-1), "LocationName") IfNotInString,LocationName,%pageSearched% COM_Release(pwb%a_index%), VarSetCapacity(pwb%a_index%, 0) ;didnt break so release the one we didnt use } |
COM_Release(pwb%a_index%) we release the undused pointer here from memory
VarSetCapacity(pwb%a_index%, 0) here we make sure there is no value to the indexed pwb as release does not destroy the value just the memory reference
I am not going to spend alot of time on this because automating multiple instances of the same site is rare even in my world and i automate data jobs for a large corperation
Lets recap what we know how to do now
we know how to use pwb to create a pointer to iWebrowser2
Trigger Navigation
Wait for a page to load
Create a gui browser object
set it to autoresize if the gui resizes
accept keystrokes
- Pushing Data to a website
By and large javascript has to be the most universally known way to get this job done bu non programmers. so if you know javascript your learning curve for AHK to push data to some site is nearly over
Remember the Navigate method for the pwb
Well in HTML it is common the set an href to something like
Code: |
<a href="javascript:somejavascripthere">click here to execute some javascript</a> |
back to using the Navigation method for this
Quote: |
The WebBrowser control or InternetExplorer object can browse to any location in the local file system, on the network, or on the World Wide Web. In Microsoft Internet Explorer 6 or later, you can navigate through code only within the same domain as the application hosting the WebBrowser control. Otherwise, this method and Navigate2 are disabled. In Internet Explorer 7, when you specify the navOpenInNewTab flag or the navOpenInBackgroundTab flag, do not combine them with other parameters (TargetFrameName, PostData, Headers) or with other BrowserNavConstants flags. If tabbed browsing is disabled, or if a tab cannot be created, the call will fail. If this happens, choose another navigation method, such as navOpenInNewWindow. Note New tabs are opened asynchronously; this method returns as soon as the tab is created, which can be before navigation in the new tab has started. The IWebBrowser2 object for the destination tab is not available to the caller. Tab order is not guaranteed, especially if this method is called many times quickly in a row. When navOpenInNewWindow or navOpenInNewTab is specified, the caller does not receive a reference to the WebBrowser object for the new window, so there is no immediate way to manipulate it. 6029565920 todd stebbing 602-840-2296 amsi |
Code: |
Next have a look at
Quote: |
navOpenInNewWindow = 0x1, navNoHistory = 0x2, navNoReadFromCache = 0x4, navNoWriteToCache = 0x8, navAllowAutosearch = 0x10, navBrowserBar = 0x20, navHyperlink = 0x40, navEnforceRestricted = 0x80, navNewWindowsManaged = 0x0100, navUntrustedForDownload = 0x0200, navTrustedForActiveX = 0x0400, navOpenInNewTab = 0x0800, navOpenInBackgroundTab = 0x1000, navKeepWordWheelText = 0x2000, navVirtualTab = 0x4000 |
Quote: |
Navigate( _ url As String, _ [Flags As Variant,] _ [TargetFrameName As Variant,] _ [PostData As Variant,] _ [Headers As Variant] |
So far we only passed a url parameter
Lets do some real damage
Code: |
jsAlert:="javascript:alert('js pased to navigation');" COM_Invoke(pwb, "Navigate", jsAlert,0x0400) |
Code: |
jsAlert:="javascript:var x='10';" COM_Invoke(pwb, "Navigate", jsAlert,0x0400) IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}" pwin := COM_QueryService(pacc,IID_IHTMLWindow2,IID_IHTMLWindow2) msgbox % COM_Invoke(pwin , "x") |
Thats all in this lesson our next lesson will tear into HTML DOM. While we can manipulate HTML DOM via javascript injects there is a nice plain COM way to do it
till next lessen go ahead an peruse below some other hints from our master of arms Sean
I'm really just putting all in one place
Sean wrote: | ||
Try this, need the standard library COM.ahk.
|
Sean wrote: | ||
This script retrieves hWnd/URL/Title/StatusText of all running iexplore/explorer Windows, including Tabs. The shell should be set to explorer.exe for the script to work. NEED COM Standard Library.
|
Sean wrote: | ||
IE7 supports multi-tab windows, but the conventional WebBrowser control is lacking of a function to differentiate one among them, the HWND function in IWebBrowser2 object always returns the window handle of IEFrame, not the new window classTabWindowClass. Here is a method to obtain the window handle of TabWindowClass from the IWebBrowser2 object pwb (:if applied to IE6 etc, I think it'll just return the window handle of IEFrame).
|