Quick question in case anyone can point me in the right direction. At the moment I have two different windows of the Chrome browser open, each with multiple tabs open, and another windows of the IE browser, also with several tabs open. Is there a way I can grab all the URLs from the various browser tabs and write them to a file?
Thanks in advance
EdT
Not 100% of what you wanted, but here's a couple related things from the database:
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/UDF~-~UDS~Library/Web~UDFs+Get~Active~Web~Page~Url.txt
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/dotNet/System_CodeDom+Grab~URL~from~Chrome.txt
Thanks - a good starting point. Now I need to figure out how to change focus to each tab in turn.
Hmm,
Run into a problem with the C# code subroutine in the second link (written by Deana Falk)
Running under 2015A I get an error on line 71:
ObjectClrOption ( 'use', 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
which states: 1848 CLR:Type name not found
then continues: objCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
I have the .NET framework 4.52 installed, but I had a search in the registry for System.Core and the entries looked consistent with the code that is erroring out, for both version, culture and PublicKeyToken.
I have tried running under both 32 bit and 64 bit settings and the error is consistent in both cases. I am not a programmer so am at a loss what to try next.
If anyone can steer me in the right direction, I would be most grateful.
Thanks
EdT
The line
ObjectClrOption ( 'use', 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
is not correct and is likely causing the puke (technical term) on the next line. I have no idea why its there but remove the '.Core' from the assembly name. You end up with this
ObjectClrOption ( 'use', 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
and hopefully a happy script with no unseemly regurgitation.
Just a curiosity question...where did "System.Core" come from, as that wasn't in the Tech Database code? At least I'm not seeing it.
Jim
It was (note past tense as apposed to present tense) in the the Tech Database example.
Thanks - that has fixed the error. Now I need to find out why the box is displaying nothing even though there are many tabs open in Chrome...
Adding in some extra display code shows that the code is returning a null value each time the sub is called, so it would appear that there has been a change in Chrome again, which stops the code working. Back to the drawing board.
Cheers
Ed
Here is the latest that fixed things as of version 38. I just tested and it works. I've gotten a little smarter since I did the first version. Not sure about that "Core" thing as it was in my code and used to work.
Jim
;************************************************************************************************************
;** This retrieves the Current URL from Chrome Version 38. May work with earlier versions as I changed
;** what I did for version 35 but no good way to test.
;** Guessing it will break again soon (but maybe not as this approach is a bit more flexible) but offers an
;** approach that could be modified as versions change.
;** JTaylor 2014-10-14
;************************************************************************************************************
If !AppExist("chrome.exe",0, 0) Then
Display(2,"Note","Chrome is not running.")
Exit
EndIf
GoSub Load_Routines
Load_GetMyURL()
url_save = ""
While 1
url = sha1.GetMyURL()
If url != url_save Then Display(2,"URL",url)
url_save = url
TimeDelay(3)
EndWhile
Exit
:LOAD_ROUTINES
#DefineSubRoutine Load_GetMyURL()
;***************************************************************************
;** Run C# in memory using WinBatch - Use Namespace.Class defined in CSharpeSource
;**
;** Purpose: Run C# in memory using WinBatch - Using Namespace.Class defined in CSharpeSource
;** Inputs:
;** Outputs: Results in message
;**
;** Developer: Deana Falk 2014.04.14
;***************************************************************************
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ObjectClrOption ( 'use', 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Compiles the c# code in Memory
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
objCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
objParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
objParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 ) ;TRUE
objParams.ReferencedAssemblies.Add("System.dll")
objParams.ReferencedAssemblies.Add("C:\Windows\Microsoft.NET\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll")
objParams.ReferencedAssemblies.Add("C:\Windows\Microsoft.NET\assembly\GAC_MSIL\UIAutomationClient\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationClient.dll")
;Make sure the cSharp code includes both namepspace and class that can be later used by ObjectCLRNew
cSharpSource = `namespace URLEngine {`:@LF
cSharpSource = cSharpSource :`using System;`:@LF
cSharpSource = cSharpSource :`using System.Text;`:@LF
cSharpSource = cSharpSource :`using System.Threading;`:@LF
cSharpSource = cSharpSource :`using System.Runtime.InteropServices;`:@LF
cSharpSource = cSharpSource :`using System.Text.RegularExpressions;`:@LF
cSharpSource = cSharpSource :`using System.Collections.Generic;`:@LF
cSharpSource = cSharpSource :`using System.Windows.Automation;`:@LF
cSharpSource = cSharpSource :`using System.Diagnostics; `:@LF
cSharpSource = cSharpSource :`public class MyURLEngine {`:@LF
cSharpSource = cSharpSource :`public string GetMyURL() `:@LF
cSharpSource = cSharpSource :` { `:@LF
cSharpSource = cSharpSource :` `:@LF
cSharpSource = cSharpSource :` Process[] procsChrome = Process.GetProcessesByName("chrome"); `:@LF
cSharpSource = cSharpSource :` int myint = procsChrome.Length; `:@LF
cSharpSource = cSharpSource :` string mystring = myint.ToString(); `:@LF
; cSharpSource = cSharpSource :` return mystring; `:@LF
cSharpSource = cSharpSource :` foreach (Process chrome in procsChrome) { `:@LF
cSharpSource = cSharpSource :` if (chrome.MainWindowHandle == IntPtr.Zero) { continue; }`:@LF
cSharpSource = cSharpSource :` AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle); `:@LF
cSharpSource = cSharpSource :` AutomationElement elmUrlBar = null; `:@LF
cSharpSource = cSharpSource :` try { `:@LF
cSharpSource = cSharpSource :` elmUrlBar = elm.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));`:@LF
cSharpSource = cSharpSource :` if (elmUrlBar == null) { return ""; } // not the right chrome.exe `:@LF
cSharpSource = cSharpSource :` } `:@LF
cSharpSource = cSharpSource :` catch { `:@LF
cSharpSource = cSharpSource :` continue; `:@LF
cSharpSource = cSharpSource :` } `:@LF
cSharpSource = cSharpSource :` if (elmUrlBar == null) { continue; }`:@LF
cSharpSource = cSharpSource :` AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns(); `:@LF
cSharpSource = cSharpSource :` if (patterns.Length == 1) { `:@LF
cSharpSource = cSharpSource :` try { `:@LF
cSharpSource = cSharpSource :` string ret = ((ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0])).Current.Value; `:@LF
cSharpSource = cSharpSource :` return ret; `:@LF
cSharpSource = cSharpSource :` } catch { } `:@LF
cSharpSource = cSharpSource :` continue; `:@LF
cSharpSource = cSharpSource :` } `:@LF
cSharpSource = cSharpSource :` } `:@LF
cSharpSource = cSharpSource :` return ""; `:@LF
cSharpSource = cSharpSource :` } `:@LF
cSharpSource = cSharpSource :` }`:@LF
cSharpSource = cSharpSource :`}`:@LF
objResult = objCSharp.CompileAssemblyFromSource(objParams,cSharpSource)
;Compiler Output
If objResult.Output.Count > 0 Then
strOutput = ''
For x = 0 to objResult.Output.Count-1
If strOutput == "" Then
strOutput = objResult.Output.Item(x)
Else
strOutput = strOutput:@LF:objResult.Output.Item(x)
EndIf
Next
Pause('Compiler Output',strOutput)
Endif
; Compiler Errors
If objResult.Errors.Count > 0 Then
strErrors = ''
ForEach ce In objResult.Errors
;Pause("Error", ce.ToString())
If strErrors == "" Then
strErrors = ce.ToString()
Else
strErrors = strErrors:@LF:ce.ToString()
EndIf
Next
Pause('Compiler Errors',strErrors)
Exit
EndIf
sha1 = ObjectClrNew( 'URLEngine.MyURLEngine' )
#EndSubRoutine
Return
Hi Jim,
I did get a URL displayed with your code, but after that the app never exited, and looking closer at the code, the while loop does not appear to have an exit strategy:
While 1
url = sha1.GetMyURL()
If url != url_save Then Display(2,"URL",url)
url_save = url
TimeDelay(3)
EndWhile
In the event that url = url_save then you end up in an endless loop. I'm guessing that an "else" is missing in your logic. When you test your code, does it display all tabs in sequence, or just the one that has focus? Are you running as 32 bit or 64 bit ?
Cheers
Ed
No. That is by design. It was for a particular project and I just posted it as it was. Should have mentioned that fact but, as you note, it is fairly obviously. I figured your main interest was the function containing the C# code and you would discard the rest or alter as needed. Wasn't really trying to give you a final solution to your problem...just helping you along the way a bit. Plus the code in the Tech Database needs updated with the version I posted. Hopefully this version is flexible enough it will last more than 2-3 versions of Chrome updates.
Jim
I just realized I hadn't responded to all your questions...
It displays the active Tab, again by design.
32-bit.
Unfortunately Chrome doesn't list all of it's tabs as windows like IE or it would be easier to get what you want. You might look at Selenium if you can't find another way to retrieve the information. Wish I had a good answer for you.
Jim
Thanks Jim, appreciate all the help. I will explore a few avenues as task manager certainly shows numerous Chrome processes running so the answer may be to enumerate all the relevant processes, then set the focus on them in turn and finally run the code to grab the URL.
Since the 'inactive' Chrome processes do not appear to have Windows attached to them, you may have to resort to using the lowly 'SendKey' function to send ctl+tab keys to Chrome to given each process in turn an active window. This is of course a common approach used with the soon to be replaced Internet Explorer.