[Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No IE!

Post your working scripts, libraries and tools for AHK v1.1 and older
teadrinker
Posts: 4562
Joined: 29 Mar 2015, 09:41
Contact:

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

11 Aug 2021, 12:22

Tre4shunter wrote: completely wrong number
What do you mean?
I see "00540".

Code: Select all

jsonobj := {"Key 1":044505,"Key 2":"00540"}
MsgBox, % "Key 1 as interpreted by AHK: " . jsonobj["Key 1"] . "`n" ; leading zeros are removed by AHK
        . "Key 2: " . jsonobj["Key 2"]

jsonstring := LightJson.Stringify(jsonobj)
msgbox % jsonstring ; the same values as in the first MsgBox

class LightJson
{
   static JS := LightJson.GetJS(), true := {}, false := {}, null := {}
   
   Parse(json, _rec := false) {
      if !_rec
         obj := this.Parse(this.JS.JSON.parse(json), true)
      else if !IsObject(json)
         obj := json
      else if this.JS.Object.prototype.toString.call(json) == "[object Array]" {
         obj := []
         Loop % json.length
            obj.Push( this.Parse(json[A_Index - 1], true) )
      }
      else {
         obj := {}
         keys := this.JS.Object.keys(json)
         Loop % keys.length {
            k := keys[A_Index - 1]
            obj[k] := this.Parse(json[k], true)
         }
      }
      Return obj
   }
   
   Stringify(obj, indent := "") {
      if indent|1 {
         for k, v in ["true", "false", "null"]
            if (obj = this[v])
               Return v

         if IsObject( obj ) {
            isArray := true
            for key in obj {
               if IsObject(key)
                  throw Exception("Invalid key")
               if !( key = A_Index || isArray := false )
                  break
            }
            for k, v in obj
               str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : """" . k . """:" ) . this.Stringify(v, true)

            Return str = "" ? "{}" : isArray ? "[" . str . "]" : "{" . str . "}"
         }
         else if !(obj*1 = "" || RegExMatch(obj, "^-?0|\s"))
            Return obj
         
         for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(8), "\b"]]
            obj := StrReplace( obj, v[1], v[2] )

         Return """" obj """"
      }
      sObj := this.Stringify(obj, true)
      Return this.JS.eval("JSON.stringify(" . sObj . ",'','" . indent . "')")
   }
   
   GetJS() {
      static Doc, JS
      if !Doc {
         Doc := ComObjCreate("htmlfile")
         Doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
         JS := Doc.parentWindow
         ( Doc.documentMode < 9 && JS.execScript() )
      }
      Return JS
   }
}
Tre4shunter
Posts: 139
Joined: 26 Jan 2016, 16:05

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

11 Aug 2021, 15:09

Apparently...The version i was using, is not the latest.

I did a file comparison vs what you posted. Rats!

fwiw here is the one i was using...just so you can see i wasnt completely nuts lol.

DISCLAIMER - THIS VERSION OF LIGHTJSON IS NOT CORRECT

Code: Select all

class LightJson
{
   static JS := LightJson.GetJS(), true := {}, false := {}, null := {}
   
   Parse(json, _rec := false) {
      if !_rec
         obj := this.Parse(this.JS.eval("(" . json . ")"), true)
      else if !IsObject(json)
         obj := json
      else if this.JS.Object.prototype.toString.call(json) == "[object Array]" {
         obj := []
         Loop % json.length
            obj.Push( this.Parse(json[A_Index - 1], true) )
      }
      else {
         obj := {}
         keys := this.JS.Object.keys(json)
         Loop % keys.length {
            k := keys[A_Index - 1]
            obj[k] := this.Parse(json[k], true)
         }
      }
      Return obj
   }
   
   Stringify(obj, indent := "") {
      if indent|1 {
         for k, v in ["true", "false", "null"]
            if (obj = this[v])
               Return v

         if IsObject( obj ) {
            isArray := true
            for key in obj {
               if IsObject(key)
                  throw Exception("Invalid key")
               if !( key = A_Index || isArray := false )
                  break
            }
            for k, v in obj
               str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : """" . k . """:" ) . this.Stringify(v, true)

            Return isArray ? "[" str "]" : "{" str "}"
         }
         else if !(obj*1 = "" || RegExMatch(obj, "\s"))
            Return obj
         
         for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(8), "\b"]]
            obj := StrReplace( obj, v[1], v[2] )

         Return """" obj """"
      }
      sObj := this.Stringify(obj, true)
      Return this.JS.eval("JSON.stringify(" . sObj . ",'','" . indent . "')")
   }
   
   GetJS() {
      static Doc, JS
      if !Doc {
         Doc := ComObjCreate("htmlfile")
         Doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
         JS := Doc.parentWindow
         ( Doc.documentMode < 9 && JS.execScript() )
      }
      Return JS
   }
}
teadrinker
Posts: 4562
Joined: 29 Mar 2015, 09:41
Contact:

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

11 Aug 2021, 15:42

Thanks, fixed here. It was already fixed in the code with the class Chrome, but I forgot to fix in the first code box.
burque505
Posts: 1747
Joined: 22 Jan 2017, 19:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

13 Aug 2021, 07:57

Just to add a little fuel to the fire, cJson.ahk version:

Code: Select all

#Include cJson.ahk

jsonobj := {"Key 1":044505,"Key 2":"00540"}
jsonstring := cJson.Dumps(jsonobj)
msgbox % jsonstring
jsonobj2 := cJson.Loads(jsonstring)
msgbox % jsonobj2["Key 1"] . "`n" . jsonobj2["Key 2"]
No quotes around the Key 2 value on the return trip, and as above no leading 0 on the first key ...
What I don't know about JSON fills many volumes :oops: , but shouldn't a round-trip conversion for these parsers yield the original object?

Edit: I missed @teadrinker's update to LightJson, and his showing that AHK interprets values differently than I expected. The code in the spoiler below helped me understand a little better.
Spoiler
Regards,
burque505
mankvl
Posts: 27
Joined: 23 Sep 2016, 03:58

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

19 Aug 2021, 07:40

GeekDude wrote:
21 Jan 2018, 12:08
Ah, hm. This script works by creating a hidden web control (IE) and using Microsoft's WebSocket object through COM. It then uses this WebSocket to connect to Chrome. On my system, IE is forbidden from accessing localhost, but is allowed to access 127.0.0.1. It looks like your system is blocking 127.0.0.1 too, for some reason.

You can disable this block (not sure how this effects general security of IE) by following the steps in this StackOverflow post. From my testing, only that top checkbox (intranet) needed to be unchecked to allow access (to localhost), but it may be different for you. I'm not sure how this change would effect security, so I would only do this for testing purposes.

What version of Windows and Internet Explorer do you have, and are you on a corporate network? If you are, what kind of proxy settings are set in IE?
Any other workarounds? On work pc i 'am unable to uncheck "Automatically detect intranet network" in IE and get that error anytime I try to use Chrome class :( After IE becoming dead this looks like the only option.
Victoriyan
Posts: 5
Joined: 06 Aug 2017, 03:33

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

17 Sep 2021, 14:32

Hello.
Can you please tell me, is there something similar in chrome.ahk like in Selenium?

The following functions are of interest:
switchToFrame ()
switchTodefaultContent ()

Thank you in advance!
burque505
Posts: 1747
Joined: 22 Jan 2017, 19:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

18 Sep 2021, 08:38

@Victoriyan, as a workaround for switchToFrame() you might try the post at this page by Ken Soh of TagUI. I don't have any tips for switchToDefaultContent().
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

18 Sep 2021, 20:09

https://www.w3schools.com/jsref/prop_frame_contentdocument.asp
For example to change background of myframe iframe to red
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_iframe_contentdocument2
You can do with evaluating this code:

Code: Select all

document.getElementById("iframeResult").contentDocument.getElementById("myframe").contentDocument.body.style.backgroundColor = "red";
Victoriyan
Posts: 5
Joined: 06 Aug 2017, 03:33

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

24 Sep 2021, 03:53

Thank you for your help. This is difficult for me, but I'll try to figure it out.

I have the following question for you. When I click on the link, a window opens in a new tab. How do I connect to a new window without creating a new class? It was written here: viewtopic.php?style=17&f=6&t=42890&start=100#p239634 that you can redirect the page without creating a new class. Practice has shown that if I create 5-7 copies of the class, I have a websocket error (((
20170201225639
Posts: 144
Joined: 01 Feb 2017, 22:57

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

25 Sep 2021, 13:02

erohtar wrote:
06 Jul 2021, 17:33
Is there any way to have an ahk function called when something on the webpage in Chrome is interacted with? Maybe via some fancy eventListener?
Something like how when using Neutron library, a button click on the web app would call a function in the ahk script.
Edit: Forgot to mention that the page that'd be open in Chrome is not a website, but a local HTML document that I can modify.
Regarding the problem of receiving message from JS, someone posted the console.log solution in response to @erohtar's question, but the method requires first calling GetPage and passing a function reference to be called back, and this needs to be done for every new chrome tab (that you may want AHK to receive message from).

I have a userscript that does some checks when I visit any arbitrary webpage, and if certain conditions are met, I want the userscript to be able to send a message to my AHK somehow. The console.log solution won't work for this case (I think), since I expect to receive messages from any arbitrary webpage.

I was wondering if there's some way for JS to send message to AHK without having to first make setting up a callback via GetPage? Something in the vein of

Code: Select all

OnMessage([Special Message Number which I'll  must from my own userscript], "handler_function_name")
Is there a way to send system message from Chrome? (from my personal userscript in Tampermonkey, which has local filesystem access)

(One way to do it is by setting clipboard from JS and capture the 'message' in AHK by onclipborad, but I'd prefer a more elegant solution)

Would appreciate any ideas.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

25 Sep 2021, 13:09

Victoriyan, did You try to use PageInst.Disconnect(), as it written at Your link?
20170201225639, use nativeMessaging.
viewtopic.php?f=5&t=32299
Victoriyan
Posts: 5
Joined: 06 Aug 2017, 03:33

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

25 Sep 2021, 14:10

@malcev

Yes, I tried in that order

Code: Select all

Page := Chrome.GetPage () ; I connect to the page
; ... executing the code ...
Page.Call ("Page.close") ; I close the page
Page.Disconnect () ; disconnect
It doesn't work anyway. 5-7 times and an error appears.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

25 Sep 2021, 14:51

For me it works OK.
Also webbrowser control can have up to 128 websocket connections.
Just use registry editor.
https://docs.microsoft.com/en-us/previo ... onnections
20170201225639
Posts: 144
Joined: 01 Feb 2017, 22:57

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

25 Sep 2021, 22:31

malcev wrote:
25 Sep 2021, 13:09
Victoriyan, did You try to use PageInst.Disconnect(), as it written at Your link?
20170201225639, use nativeMessaging.
viewtopic.php?f=5&t=32299
Thanks malcev. I got it working. :thumbup:

And in case this is useful to anyone, while I got it working by following @qwerty12's instructions (in the page malcev linked to) down to the letter, anytime I tried to change the extension folder to any folder other than "C:\1" (e.g. to "C:\ahk\native_messaging"), it would no longer work and Chrome would show an error, even though I took care to change the paths in both host-manifest.json and in the registry value (to the correctly esacped "C:\\ahk\\native_messaging"). I spent half an hour trying to find out why this should be so (since nowhere else (than in those 2 files) in the example extension are absolute paths mentioned), and it turned out that the cause is ... most peculiar. It is this: for unpacked chrome extensions, the extension ID is generated based on the absolute path of the extension folder (you can't just give it an arbitrary ID). So changing the path in the example is not enough: you also must also change the ID used in qwerty12's example (the ID qwerty12 used is "hocphmgffekdgmepinkfjlmlglljckfg" and it's only good for "C:\\1") so that it matches the absolute path of your unpacked extensions. See here for more details, and for the python code you can use to generate the correct ID for any absolute path

https://stackoverflow.com/questions/26053434/how-is-the-chrome-extension-id-of-an-unpacked-extension-generated
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

26 Sep 2021, 16:22

You can do the same in ahk:

Code: Select all

var := bcrypt_sha256("C:\1\ext", "utf-16")
loop, parse, var
{
   a := "0x" A_LoopField
   a+=97
   id .= chr(a)
   if (A_Index = 32)
      break
}
msgbox % id

bcrypt_sha256(string, encoding := "utf-8")
{
    static BCRYPT_SHA256_ALGORITHM := "SHA256"
    static BCRYPT_OBJECT_LENGTH    := "ObjectLength"
    static BCRYPT_HASH_LENGTH      := "HashDigestLength"

	try
	{
		; loads the specified module into the address space of the calling process
		if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
			throw Exception("Failed to load bcrypt.dll", -1)

		; open an algorithm handle
		if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlg, "ptr", &BCRYPT_SHA256_ALGORITHM, "ptr", 0, "uint", 0) != 0)
			throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)

		; calculate the size of the buffer to hold the hash object
		if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlg, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", cbHashObject, "uint", 4, "uint*", cbData, "uint", 0) != 0)
			throw Exception("BCryptGetProperty: " NT_STATUS, -1)

		; allocate the hash object
		VarSetCapacity(pbHashObject, cbHashObject, 0)
		;	throw Exception("Memory allocation failed", -1)

		; calculate the length of the hash
		if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlg, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbData, "uint", 0) != 0)
			throw Exception("BCryptGetProperty: " NT_STATUS, -1)

		; allocate the hash buffer
		VarSetCapacity(pbHash, cbHash, 0)
		;	throw Exception("Memory allocation failed", -1)

		; create a hash
		if (NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr", hAlg, "ptr*", hHash, "ptr", &pbHashObject, "uint", cbHashObject, "ptr", 0, "uint", 0, "uint", 0) != 0)
			throw Exception("BCryptCreateHash: " NT_STATUS, -1)

		; hash some data
		VarSetCapacity(pbInput, (StrPut(string, encoding) - 1) * ((encoding = "utf-16" || encoding = "cp1200") ? 2 : 1), 0) && cbInput := (StrPut(string, &pbInput, encoding) - 1) * ((encoding = "utf-16" || encoding = "cp1200") ? 2 : 1)
		if (NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", cbInput, "uint", 0) != 0)
			throw Exception("BCryptHashData: " NT_STATUS, -1)

		; close the hash
		if (NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0) != 0)
			throw Exception("BCryptFinishHash: " NT_STATUS, -1)

		loop % cbHash
			hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))
	}
	catch exception
	{
		; represents errors that occur during application execution
		throw Exception
	}
	finally
	{
		; cleaning up resources
		if (pbInput)
			VarSetCapacity(pbInput, 0)
		if (hHash)
			DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
		if (pbHash)
			VarSetCapacity(pbHash, 0)
		if (pbHashObject)
			VarSetCapacity(pbHashObject, 0)
		if (hAlg)
			DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlg, "uint", 0)
		if (hBCRYPT)
			DllCall("FreeLibrary", "ptr", hBCRYPT)
	}

	return hash
}
Stavencross
Posts: 90
Joined: 24 May 2016, 16:42

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

28 Sep 2021, 15:38

I don't know who needs to see this, but some of my users were reporting that their app was getting "not connected to tab" errors. Turns out, if you issue a request that takes >30ish seconds from within your main script (For instance, exporting a large PPTX to PDF), you block the keep alive, and you can't reconnect to the websocket. I tried reconnecting a couple different ways, but nothing worked. Instead, when I encounter tasks that eat up a ton of time, I create separate scripts as an exe, and call them from my main script, which basically allows me to 'thread' my requests.
burque505
Posts: 1747
Joined: 22 Jan 2017, 19:37

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

28 Sep 2021, 15:52

Maybe using AutoHotkey_H would be another approach, since it has thread management.
Milchmann
Posts: 112
Joined: 05 Nov 2016, 08:50

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

29 Sep 2021, 12:21

mankvl wrote:
19 Aug 2021, 07:40
GeekDude wrote:
21 Jan 2018, 12:08
Ah, hm. This script works by creating a hidden web control (IE) and using Microsoft's WebSocket object through COM. It then uses this WebSocket to connect to Chrome. On my system, IE is forbidden from accessing localhost, but is allowed to access 127.0.0.1. It looks like your system is blocking 127.0.0.1 too, for some reason.

You can disable this block (not sure how this effects general security of IE) by following the steps in this StackOverflow post. From my testing, only that top checkbox (intranet) needed to be unchecked to allow access (to localhost), but it may be different for you. I'm not sure how this change would effect security, so I would only do this for testing purposes.

What version of Windows and Internet Explorer do you have, and are you on a corporate network? If you are, what kind of proxy settings are set in IE?
Any other workarounds? On work pc i 'am unable to uncheck "Automatically detect intranet network" in IE and get that error anytime I try to use Chrome class :( After IE becoming dead this looks like the only option.
push :D

Unfortunately, that's exactly how I feel. Is there another way to use "Chrome.ahk".
Tre4shunter
Posts: 139
Joined: 26 Jan 2016, 16:05

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

29 Sep 2021, 12:53

@Milchmann ,

afaik there are a few people (Including the G33k himself) working on modifying the lib to use websockets without IE.

Check this thread out:
viewtopic.php?f=6&t=94895&p=421942#p421942

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 81 guests