@@ -39,8 +39,9 @@ Public sessionId As String
3939' which browser did we connect to
4040Public browserProgram As browserType
4141
42- ' link to browser for sending and receiving protocol messages
42+ ' link to browser for sending and receiving protocol messages, only 1 of these (objBrowser, wsBrowser) should be valid
4343Private objBrowser As clsProcess
44+ Private wsBrowser As clsWebSocket
4445
4546' every message sent over Chrome Developer Protocol has an id, this is id of last message we sent
4647Private lngLastID As Long
@@ -82,22 +83,24 @@ Private Function searchNull() As Long
8283End Function
8384
8485
85- ' read in any pending data from connected browser pipe/soccket and append to buffer
86+ ' read in any pending data from connected browser pipe/socket and append to buffer
8687' nonblocking, will return immediately if nothing new to add
8788Private Sub readRawMessageData ()
88- Dim intRes As Long
89- Dim strRes As String
90-
91- ' read in all data currently sent from browser to us
92- intRes = 1
93- Do Until intRes < 1
94- DoEvents
95- intRes = objBrowser.readProcCDP(strRes)
96-
97- If intRes > 0 Then
98- strBuffer = strBuffer & strRes
99- End If
100- Loop
89+ Dim errorText As String , strResult As String
90+
91+ If Not objBrowser Is Nothing Then
92+ strResult = objBrowser.GetMessageData(errorText)
93+ ElseIf Not wsBrowser Is Nothing Then
94+ strResult = wsBrowser.GetMessageUTF8()
95+ errorText = wsBrowser.errorText
96+ Else
97+ Debug.Print "readRawMessageData() - Error: no implementation to communicate with browser available!"
98+ Stop
99+ End If
100+
101+ If errorText = "None" Then
102+ strBuffer = strBuffer & strResult
103+ End If
101104End Sub
102105
103106' store and retrieve messages from a queue event processing or delayed response handling
@@ -132,6 +135,7 @@ End Function
132135' event handlers are called and if returns true event not queued
133136' queues and returns any message found
134137Public Function peakMessage () As Dictionary
138+ On Error GoTo ErrHandler
135139 Dim lngNullCharPos As Long
136140
137141 ' get any new data if available since last call
@@ -186,6 +190,11 @@ messageHandled:
186190 End If
187191
188192 DoEvents
193+ Exit Function
194+ ErrHandler:
195+ Debug.Print "peakMessage() - Error: " & Err.description
196+ Stop
197+ Resume
189198End Function
190199
191200' sends a CDP message to browser
@@ -207,7 +216,7 @@ Private Function sendMessage(ByVal strMessage As String, Optional ByVal nowait A
207216 ' sometimes edge writes to stdout
208217 ' we clear stdout here, too.
209218 Dim ignored As String
210- objBrowser.readProcSTD ignored
219+ ' objBrowser.readProcSTD ignored
211220
212221 ' We add the currentID and sessionID to the message (assume flat messages and sessionId required)
213222 strMessage = left(strMessage, Len(strMessage) - 1 )
@@ -219,7 +228,16 @@ Private Function sendMessage(ByVal strMessage As String, Optional ByVal nowait A
219228 strMessage = strMessage & ", ""id"":" & lngLastID & "}" & vbNullChar
220229
221230 ' write message to browser
222- If objBrowser.writeProc(strMessage) = 0 Then
231+ Dim errorSending As Boolean
232+ If Not objBrowser Is Nothing Then
233+ errorSending = (objBrowser.writeProc(strMessage) = 0 )
234+ ElseIf Not wsBrowser Is Nothing Then
235+ errorSending = Not wsBrowser.SendMessageUTF8(strMessage)
236+ Else
237+ errorSending = True
238+ Debug.Print "Warning objBrowser and wsBrowser are both nothing, unable to communicate with browser!"
239+ End If
240+ If errorSending Then
223241 Debug.Print "-----"
224242 Debug.Print "Failed to write CDP message!"
225243 Debug.Print strMessage
@@ -381,56 +399,109 @@ End Function
381399' This method starts up the browser
382400' It will attempt to terminate the browser if found to already be running (user is prompted prior to abort)
383401' If autoAttach is True then after connection to browser established will initiate attach call automatically
402+ ' if useWebSocket is True then will connect to browser websocket on localhost port 9222, otherwise connects directly via a pipe
403+ ' if useWebSocket is True and useExistingBrowser then does not (kill and) spawn browser before connecting, ignored if useWebSocket is false
384404' Warning! if autoAttach is True then the url must exactly match and may fail if browser changes expected url unless partialMatch is True
385405' Returns True if successfully initialized browser, False otherwise
386- Public Function launch (Optional url As String = vbNullString, Optional autoAttach As Boolean = True , Optional partialMatch As Boolean = True ) As Boolean
406+ Public Function launch ( _
407+ Optional url As String = vbNullString, _
408+ Optional autoAttach As Boolean = True , _
409+ Optional partialMatch As Boolean = True , _
410+ Optional useWebSocket As Boolean = False , _
411+ Optional useExistingBrowser As Boolean = False _
412+ ) As Boolean
387413 ' ensure browser is not already running (kill it if it is)
388- If Not TerminateProcess(ProcessName:="msedge.exe" , PromptBefore:=True ) Then
389- ' abort if browser is already running and failed to kill it or user elected not to terminate
390- Exit Function
414+ If Not (useWebSocket And useExistingBrowser) Then
415+ If Not TerminateProcess(ProcessName:="msedge.exe" , PromptBefore:=True ) Then
416+ ' abort if browser is already running and failed to kill it or user elected not to terminate
417+ Exit Function
418+ End If
391419 End If
392420
393- Set objBrowser = New clsProcess
394-
395421 Dim strCall As String
396422 ' --remote-debugging-pipe allow communicating with Edge
397423 ' --remote-debugging-port=9222 alternative for communication via TCP
398424 ' --enable-automation can be omitted for Edge to avoid displaying "being controlled banner", but necessary for Chrome
399425 ' --disable-infobars removes messages such as "being controlled by automation" banners, ignored by Edge, used by Chrome
400426 ' --enable-logging allows viewing additional connection details, but causes opening of console windows
401427 ' --user-data-dir=c:\temp\fakeEdgeUser to open in different profile, and therefore session than current user, but screws up because Admin managed user so don't use
402- strCall = """C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"" --remote-debugging-pipe " & url
428+
429+ ' only one of objBrowser or wsBrowser can be valid, depending how we are connecting initialize the correct one
430+ If useWebSocket Then
431+ Set objBrowser = Nothing
432+ Set wsBrowser = New clsWebSocket
433+ strCall = """C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"" --remote-debugging-port=9222 " & url
434+ If Not useExistingBrowser Then
435+ If Not SpawnProcess(strCall) Then Exit Function
436+ End If
437+
438+ ' give it a bit to startup
439+ Sleep 1
440+
441+ ' get the path to the browser target websocket - we hard code only connecting to localhost port 9222
442+ Dim wsPath As String
443+
444+ ' we get the path (really full link) by connecting via HTTP to http://localhost:9222/json/version - note 9222 is same as specified on cmdline
445+ ' and extracting the information from the webSocketDebuggerUrl field of the returned JSON
446+ ' eg. "ws://localhost:9222/devtools/browser/f875efa4-b4ee-4c35-848b-73bc384a32bb"
447+ wsPath = "/devtools/browser/f875efa4-b4ee-4c35-848b-73bc384a32bb"
448+ wsPath = wsBrowser.HttpGetMessage("localhost" , 9222 , "/json/version" )
449+ Dim versionInfo As Dictionary
450+ Set versionInfo = JsonConverter.ParseJson(wsPath)
451+ wsPath = versionInfo("webSocketDebuggerUrl" )
452+ wsPath = Right(wsPath, Len(wsPath) - Len("ws://localhost:9222" ))
453+
454+ ' connect to the browser target websocket
455+ With wsBrowser
456+ .protocol = "ws://"
457+ .server = "localhost"
458+ .port = 9222
459+ .path = wsPath ' this one changes with each time browser is started
460+ If Not .Connect() Then Exit Function ' False
461+ End With
462+ Else
463+ Set objBrowser = New clsProcess
464+ Set wsBrowser = Nothing
465+ strCall = """C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"" --remote-debugging-pipe " & url
466+
467+ Dim intRes As Integer
468+ intRes = objBrowser.init(strCall)
469+ If intRes <> 0 Then
470+ 'Call Err.Raise(-99, , "error start browser")
471+ Exit Function ' False
472+ End If
473+
474+ ' give it a bit to startup
475+ Sleep 1
476+ End If
477+
478+ ' for now we only support Edge, but eventually we will add the logic to spawn/recognize Chrome and FireFox along with Edge
403479 browserProgram = browserType.Edge
404480
405- Dim intRes As Integer
406-
407- intRes = objBrowser.init(strCall)
408-
409- If intRes <> 0 Then
410- 'Call Err.Raise(-99, , "error start browser")
411- Exit Function ' False
412- End If
413-
414- Call Sleep
481+ ' initialize message id used to track message responses
415482 lngLastID = 1
416483
484+ ' if connected via pipe we need to clear pipe from any data written during startup
417485 Dim strRes As String
418-
419486 intRes = 0
420487
421488 Dim intCounter As Integer
422489 intCounter = 0
423490
424- Do Until intRes > 0 Or intCounter > 1000
491+ Do Until intRes > 0 Or intCounter > 1000 Or useWebSocket
425492 intRes = objBrowser.readProcSTD(strRes)
426493 DoEvents
427494 Call Sleep (0.1 )
428495 intCounter = intCounter + 1
429496 Loop
430497
431498 ' automatically attach to requested page or any page if no specific one requested
499+ ' WARNING if we didn't spawn browser then url may not match any page Target!
432500 If autoAttach Then
433- If Me.attach(url, partialMatch:=partialMatch) = vbNullString Then Exit Function ' failed to attach on launch
501+ If Me.attach(url, partialMatch:=partialMatch) = vbNullString Then
502+ If useWebSocket Then wsBrowser.Disconnect
503+ Exit Function ' failed to attach on launch
504+ End If
434505 End If
435506
436507 ' assume success
0 commit comments