Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[SOLVED] How to create new tabs in IExplorer


  • Please log in to reply
15 replies to this topic
jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
Hello,

by doing my script with built-in COM commands, i encounterd a big issue :
when i create other pointers pwb2, pwb3, etc... to navigate on a new website
(while the first pointer pwb is doing something on the first opened tab), they don't open
in new IE tabs, but new IE windows.

Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Navigate("http://www.google.fr")
Pwb.visible:=True
IELoad(Pwb)
Sleep, 100
Pwb2 := ComObjCreate("InternetExplorer.Application")
Pwb2.Navigate("http://www.yahoo.fr")
Pwb2.visible:=True
IELoad(Pwb2)
Pwb3 := ComObjCreate("InternetExplorer.Application")
Pwb3.Navigate("http://www.youtube.com")
Pwb3.visible:=True
IELoad(Pwb3)

IELoad(Pwb)   
{
   If !Pwb  
      Return False
   Loop   
      Sleep,100
   Until (Pwb.busy)
   Loop  
      Sleep,100
   Until (!Pwb.busy)
   Loop   
      Sleep,100
   Until (Pwb.Document.Readystate = "Complete")
Return True
}
I tested this code but it opens only google, and no other websites (needed in new tabs).
Then i commented out the loop :
;Loop   
    ;Sleep,100
   ;Until (Pwb.busy)
And now it opens 3 new Internet explorer windows, but i want just new tabs !

How to create new tabs for new pointers, so that each pointer pwbN can process only on its own
IE tab and doesn't disburb already created tabs ? And is IELoad() function really correct/optimal ?

I read many posts about this topic, and i saw a code containing this command :
ComObjCreate("Shell.Application").Windows
but there was not clear answer for new tab in built-in com language.
Thanks.
*********** FREE your Posted ImageMind ! :-) *****

Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011
Pwb := ComObjCreate("InternetExplorer.Application")

Pwb.visible:=True

Pwb.Navigate("http://www.google.com")

Pwb.Navigate2("http://www.yahoo.com", 2048) ; open in new tab

IELoad(Pwb)



WinWait, Yahoo! - Windows Internet Explorer

pwb2 := IEGet("Yahoo!")   ; get pointer of new tab

Pwb.Navigate("http://www.autohotkey.com")   ; test pwb

IELoad(Pwb)

Pwb2.Navigate("http://www.cnn.com")  ; test pwb2

IELoad(Pwb2)

return


jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
Could you please detail IEGet function code?
Ok i found it there :

IEGet(Name="")      ;Retrieve pointer to existing IE window/tab
{
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame
      Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" 
      : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" )
   For Pwb in ComObjCreate( "Shell.Application" ).Windows
      If ( Pwb.LocationName = Name ) && InStr( Pwb.FullName, "iexplore.exe" )
         Return Pwb
} ;written by Jethrow

what is 2048 number?
*********** FREE your Posted ImageMind ! :-) *****

Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011
I figured if you know IELoad() then you will find IEGet().
as for 2048, lookup http://msdn.microsof...752094(v=vs.85)
and http://msdn.microsof...565688(v=vs.85) navOpenInNewTab = 2048

jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
I tested your code and tried to make search in google,
but nothing is entered in second opened tab. Why ?

Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible:=True
Pwb.Navigate("http://www.google.fr")
IELoad(Pwb)   ;Wait until it's completely loaded
Pwb.Document.All.q.Value := "Hello" ; enters Hello in google search area
Pwb.document.GetElementById("btnK").click()
; type Hello in google search and launches search

; then opens new tab and searches Bye
Pwb.Navigate2("http://www.google.fr", 2048)
IELoad(Pwb)
Pwb2:=IEGet()

;;;; above code is not working, it types nothing in the second tab opened...
Pwb2.Document.All.q.Value := "Bye"
Pwb2.document.GetElementById("btnK").click()


IELoad(Pwb)   ;You need to send the IE handle to the function unless you define it as global.
{
   If !Pwb   ;If Pwb is not a valid pointer then quit
      Return False
   Loop   ;Otherwise sleep for .1 seconds untill the page starts loading
      Sleep,100
   Until (Pwb.busy)
   Loop   ;Once it starts loading wait until completes
      Sleep,100
   Until (!Pwb.busy)
   Loop   ;optional check to wait for the page to completely load
      Sleep,100
   Until (Pwb.Document.Readystate = "Complete")
Return True
}

IEGet( Name="") ; return pwb with the exact tab title
{ 
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter 
   Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" ) 
   For pwb in ComObjCreate( "Shell.Application" ).Windows 
      If ( pwb.LocationName = Name ) && InStr( pwb.FullName, "iexplore.exe" ) 
         Return pwb 
}

*********** FREE your Posted ImageMind ! :-) *****

jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
anyone?
*********** FREE your Posted ImageMind ! :-) *****

Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011
Pwb := ComObjCreate("InternetExplorer.Application")

Pwb.Visible:=True

Pwb.Navigate("http://www.google.fr")

IELoad(Pwb)   ;Wait until it's completely loaded

Pwb.Document.All.q.Value := "Hello" ; enters Hello in google search area

Pwb.document.GetElementById("btnK").click()



Pwb.Navigate2("http://www.yahoo.com", 2048)

WinWait, Yahoo

Pwb2:=IEGet("Yahoo!")



Pwb2.Navigate("http://www.google.fr")

IELoad(Pwb2)   ;Wait until it's completely loaded

Pwb2.Document.All.q.Value := "Bye"

Pwb2.document.GetElementById("btnK").click()



jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
Very Strange !!!!
After many trials and bugs, i finally found a (small) solution, but it's not yet
the better one..
I remind my target :
OPEN SEVERAL TABS IN SAME IE WINDOW, and do actions on different tabs with different pointers
pwb1, pwb2, etc...
This code is working but all problems are in comments. :roll:

Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible:=True
Pwb.Navigate("http://www.yahoo.fr")
; if URL = google.fr, the winwaitactive below won't be efficient, because 2 tabs contain "Google" word in Title
; so the "bye" word will NOT be entered !!! 
; HOW TO FIX THIS WITH SAME URL ??

IELoad(Pwb)   ;Wait until it's completely loaded
;Pwb.Document.All.q.Value := "Hello" ; enters Hello in google search area
;Pwb.document.GetElementById("btnK").click()

; type Hello in google search and launches search
; then opens new tab and is supposed to type "Bye" word in google search box
Pwb.Navigate2("http://www.google.fr", 2048) ; opens new tab
Sleep, 1000
WinWaitActive Google - Windows Internet Explorer
;the IELoad function makes a bug here
; We use WinWaitActive instead to be sure new tab is loaded
; the inconvenient is we must specify a window name...
; i would like a function waiting for last tab loaded...

;IELoad(Pwb)   so not good as we noticed...

 ; put Pwb2 in last active tab
Pwb2 := IEGet("") 

;;;; above code is NOW working :) it types word "Bye" (without " ") in the second tab opened.

Pwb2.Document.All.q.Value := "Bye"
Pwb2.document.GetElementById("btnK").click()
Sleep, 4000

Process, close, iexplore.exe  ; IF I COMMENT THIS COMMAND, the SECOND TAB is NO MORE COMPLETED with "Bye" word... strange !! everytime i need to close completely iexplore.exe..why?
ExitApp


;;;; usual COM functions
IELoad(Pwb)   ;You need to send the IE handle to the function unless you define it as global.
{
   If !Pwb   ;If Pwb is not a valid pointer then quit
      Return False
   Loop   ;Otherwise sleep for .1 seconds untill the page starts loading
      Sleep,100
   Until (Pwb.busy)
   Loop   ;Once it starts loading wait until completes
      Sleep,100
   Until (!Pwb.busy)
   Loop   ;optional check to wait for the page to completely load
      Sleep,100
   Until (Pwb.Document.Readystate = "Complete")
Return True
}

IEGet( Name="") ; return pwb with the exact tab title
{ 
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter 
   Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" ) 
   For pwb in ComObjCreate( "Shell.Application" ).Windows 
      If ( pwb.LocationName = Name ) && InStr( pwb.FullName, "iexplore.exe" ) 
         Return pwb 
}

Thanks if someone could help (and take time to read and test this code !)
*********** FREE your Posted ImageMind ! :-) *****

jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
Ok thanks very much Alpha Bravo for your nice and simple code !
I understood your "trick" to avoid problem with same URL :
just open a new tab ("naviagate2") with a random URL DIFFERENT from the first one,
and then retrieve new pointer, and open the wanted url with "navigate" again ! 8)

Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible:=True
Pwb.Navigate("http://www.google.fr")
IELoad(Pwb)   ;Wait until it's completely loaded
Pwb.Document.All.q.Value := "Hello" ; enters Hello in google search area
Pwb.document.GetElementById("btnK").click()

Pwb.Navigate2("http://www.icone.fr", 2048) 
; opens new tab with RANDOM URL DIFFERENT
; from first URL : here is the trick to solve the problem !!

WinWait icone.fr   ; no need winwaitactivate in fact
Pwb2:=IEGet("icone.fr") ; retrieves new pointer thanks to new random tab
Pwb2.Navigate("http://www.google.fr") ; and now, go to wanted Same URL (google.fr here)
IELoad(Pwb2)  ; usual function are now working !!! :)
Pwb2.Document.All.q.Value := "Bye"
Pwb2.document.GetElementById("btnK").click()
Sleep, 4000

;Process, close, iexplore.exe  ; now, when I COMMENT THIS COMMAND, the SECOND TAB is ;COMPLETED with "Bye" word !!! that's great, thanks alpha bravo !!!!
ExitApp


;; usual com functions used
IELoad(Pwb)   ;You need to send the IE handle to the function unless you define it as global.
{
   If !Pwb   ;If Pwb is not a valid pointer then quit
      Return False
   Loop   ;Otherwise sleep for .1 seconds untill the page starts loading
      Sleep,100
   Until (Pwb.busy)
   Loop   ;Once it starts loading wait until completes
      Sleep,100
   Until (!Pwb.busy)
   Loop   ;optional check to wait for the page to completely load
      Sleep,100
   Until (Pwb.Document.Readystate = "Complete")
Return True
}

IEGet( Name="") ; return pwb with the exact tab title
{ 
   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame ; Get active window if no parameter 
   Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" ) 
   For pwb in ComObjCreate( "Shell.Application" ).Windows 
      If ( pwb.LocationName = Name ) && InStr( pwb.FullName, "iexplore.exe" ) 
         Return pwb 
}
So i can say... Bravo ! :D the problem is now completely solved.
*********** FREE your Posted ImageMind ! :-) *****

freakkkAsGuest
  • Guests
  • Last active:
  • Joined: --
I'm having the same issue with this, but unfortunately the above workaround isn't going to cut it for me. I am trying to automate using a page at work, and I need to open several of the same pages in separate tabs in the same IE window (so all the tabs will have the same title number). I traced the issue down and it seems like the issue is that readyState and busy state don't reset when you navigate to a new tab. Since its not waiting for page to load, I'm not able to get the pointer to the specific page for me to use to manipulate individual pages. I would really like to avoid using the window title if at all possible. I was wondering if anyone else has figured out a better solution to this? Thanks in advance!
ie := ComObjCreate("InternetExplorer.Application"), ie.Visible := true

  ie.Navigate("http://google.com", "")

  While ie.readyState!=4 || ie.document.readyState!="complete" || ie.busy

    Sleep 100

  thisTab1 := WBGet()

  thisTab1.Document.All.q.Value := "this is tab 1"

  MsgBox, 262144,,so far so good..

  ;---

  ie.Navigate("http://google.com", 2048)

  While ie.readyState!=4 || ie.document.readyState!="complete" || ie.busy

    Sleep 100

  thisTab2 := WBGet()

  thisTab2.Document.All.q.Value := "this is tab 2"

  MsgBox, 262144,,since readyState never changes, it isn't waiting for tab to load..

return



WBGet(WinTitle="ahk_class IEFrame", Svr#=1) { ; based on ComObjQuery docs

  static

  msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")

      ,  IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IWebBrowserApp

  SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%

  if (ErrorLevel != "FAIL") {

    lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)

    if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {

      DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)



    pwb := ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)

    return pwb.Document.all[0]

    }

  }

}


jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
I updated WBGet() (it was returning the window object). Here's a working example:
navOpenInBackgroundTab := 4096

[color=#004000]; Load IE with 3 tabs[/color]
wb1 := ComObjCreate("InternetExplorer.Application")
wb1.Visible := True
wb1.Navigate("www.google.com")
wb1.Navigate("www.google.com", navOpenInBackgroundTab)
wb1.Navigate("www.google.com", navOpenInBackgroundTab)

[color=#004000]; get WebBrowser Object for Internet Explorer_Server 2 & 3[/color]
Loop 2 {
	i := A_Index+1
	while Not wb%i%
		wb%i% := WBGet("ahk_id" wb1.hwnd, i)
}

[color=#004000]; wait for all tabs to load[/color]
while wb1.busy or wb2.busy or wb3.busy
	sleep 10


Loop 3
	wb%A_Index%.Document.All.q.Value := "Hello" ; enters Hello in google search area
 , wb%A_Index%.document.GetElementById("btnK").click()




WBGet(WinTitle="ahk_class IEFrame", Svr#=1) { ; based on ComObjQuery docs
	static	msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
	,	IID := "{0002DF05-0000-0000-C000-000000000046}" ; IID_IWebBrowserApp
;	,	IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IHTMLWindow2
	SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
	if (ErrorLevel != "FAIL") {
		lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		}
	}
}

*EDIT - changed array syntax to psuedo-array syntax for wb, and modified how the code waits for the tabs to exist

jyloup
  • Members
  • 74 posts
  • Last active: May 05 2015 07:43 PM
  • Joined: 21 Feb 2012
Why you must do wb:=[]? is it necessary?
*********** FREE your Posted ImageMind ! :-) *****

Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011
I spent some time on it too, still using WinWait but independent of win title.
Pwb1 := ComObjCreate("InternetExplorer.Application")

Pwb1.visible:=True

Pwb1.Navigate("http://www.google.com")



Pwb1.Navigate2("about:Tabs", navOpenInNewTab := 0x0800)

WinWaitActive, New Tab

pwb2 := IEGet()

Pwb2.Navigate("http://www.google.com")  ; test pwb2



Pwb2.Navigate2("about:Tabs", navOpenInNewTab := 0x0800)

WinWaitActive, New Tab

pwb3 := IEGet()

Pwb3.Navigate("http://www.google.com")  ; test pwb3



loop, 3

	load(pwb%A_Index%)

return



load(p){

While p.readyState!=4 || p.document.readyState!="complete" || p.busy

    Sleep 100

}



IEGet(Name=""){      ;Retrieve pointer to existing IE window/tab

   IfEqual, Name,, WinGetTitle, Name, ahk_class IEFrame

      Name := ( Name="New Tab - Windows Internet Explorer" ) ? "about:Tabs" 

      : RegExReplace( Name, " - (Windows|Microsoft) Internet Explorer" )

   For Pwb in ComObjCreate( "Shell.Application" ).Windows

      If ( Pwb.LocationName = Name ) && InStr( Pwb.FullName, "iexplore.exe" )

         Return Pwb

} ;written by Jethrow


freakkk
  • Members
  • 182 posts
  • Last active: Dec 16 2014 06:23 PM
  • Joined: 29 Jul 2005
jethrow, that is absolutely amazing! 

It seems like using navOpenInBackgroundTab rather than the 2048 I was using is an important part of it.  I was still having issues implementing in my code until I changed that.

Your implementation of the 'while Not' statement rules!! I embarrassingly didn't even realize what the srv# param for WBGet() was for!

Thank you a million times for your help (and for giving me a copy of WBGet() in the first place!). If you had a donate button I would surely be pressing it right now.  :)

Alpha Bravo- thank you for the suggestion. While I'm going to try sticking to how jethrow implemented his example, I will definitely keep your idea in mind if I get stuck again.

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009

It seems like using navOpenInBackgroundTab rather than the 2048 I was using is an important part of it.  I was still having issues implementing in my code until I changed that.


The active tab is always Server1.