Internet Explorer classic (IE in the following) was based on ActiveX technology. It was very easy to automate IE for tasks like Webscraping or testing from OLE-aware programming languages like VBA. But Microsoft will end support for IE in the near future and wants users to move to newer browsers like Microsoft Edge.
Microsoft Edge is no longer based on ActiveX technology. Microsoft seems uninterested in creating a drop-in replacement for the IE OLE Object. There are libraries that try to fill this gap using Selenium, see Seleniumbasic as an example. But this requires the installation of a Webdriver, which might not be feasible in some environments. The following solution needs no additional software, apart from a Chrome-based browser.
Keep in mind, that all running Edge procceses must be terminated before running the code. Otherwise the tabs are opened in the currently running process, not the one that has been started and subsequent communication between VBA and Edge fails.
The code uses the Chrome Devtools Protocol (CDP) to communicate with the browser. A full documentation of the protocol can be found here . The code implements only a very narrow set of functions:
But these functions should suffice to do basic Webscraping. The main code is as follows:
The class
clsEdge
implements the CDP protocol. The CDP protocol is a message-based protocol. Messages are encoded as JSON. To generate and parse JSON, the code uses the VBA-JSON library from
here
.
The low-level access to the CDP protocol is avaible by two means: Either Edge starts a small Webserver on a specific port or via pipes. The Webserver lacks any security features. Any user on the computer has access to the webserver. This may pose no risks on single user computers or dedicated virtual containers. But if the process is run on a terminal server with more than one user, this is not acceptable. That's why the code uses pipes to communicate with Edge.
Edge uses the third file descriptor (fd) for reading messages and the fourth fd for writing messages. Passing fds from a parent process to child process is common under Unix, but not under Windows. The WinApi call to create a child process (
CreateProcess
) allows to setup pipes for the three common fds (
stdin
,
stdout
,
stderr
) using the
STARTUPINFO
structure, see
CreateProcessA function (processthreadsapi.h)
and
STARTUPINFOA structure (processthreadsapi.h)
. Other fds cannot be passed to the child process.
In order to set up the fourth and fifth fds, one must use an undocumented feature of the Microsoft Visual C Runtime (
MSVCRT
): If an application is compiled with Microsoft C, than one can pass the pipes using the
lpReserved2
parameter of the
STARTUPINFO
structure. See "
Undocumented CreateProcess
" for more details (scroll down the page).
The structure that can be passed in
lpReserved2
is defined in the module
modExec
.
The structure is defined to pass five fds in the
os_handle
array. The values for the
crt_flags
array can be obtained from
https://github.com/libuv/libuv/blob/v1.x/src/win/process-stdio.c
. The fields of the
struct
must lie contiguously in memory (packed). VBA aligns
struct
fields to 4 byte boundaries (on 32-bit systems). That's why a second
struct
with raw types is defined.
After populating the
STDIO_BUFFER struct
, the content is copied using
MoveMemory
to the
STDIO_BUFFER2
struct. The size of 25 bytes is enought to hold
crt_flags
(5 bytes) and the pointers (20 bytes).
Would you please teach me how to use these codes? I still have "Error PeekNamedPipe in readProcCDP Pin".
I still have this:"Error PeekNamedPipe in readProcCDP"
I included the files and pasted the sample code. I also added the reference to the Scripting for Dictionary. When I try to run the sample code I get an error.
Quote:Call objBrowser.attach("")
Quote:Runetime: 901; Error PeekNamedPipe in readProcCDP
For me a similiar approach worked. Before opening Edge I kill all running instances with this little function (this takes some seconds but I never had that error again):
is it possible to attach to edge that already opened without run objBrowser.start() ?
Just want update base on my experience so far. I think there is no way to attach edge already oppened.
Hello, Chris K23
I removed it also and everything works as expected.
to hide that window you can set as below on clsEdge
Your code works perfectly thank you so much..
The easiest way to try out commands is the JavaScript console in the developer tools. I think it even has syntax completion.
If objRes.Item(
"
result"
).Item(
"
result"
).Item(
"
type"
) =
"
string"
Or objRes.Item(
"
result"
).Item(
"
result"
).Item(
"
type"
) =
"
boolean"
Or objRes.Item(
"
result"
).Item(
"
result"
).Item(
"
type"
) =
"
number"
Then
jsEval = objRes.Item(
"
result"
).Item(
"
result"
).Item(
"
value"
)
End If
But if he wants to use "getElementsByTagName", this will give him a collection of objects. Is there a way for the jsEval function to return a collection of objects from the CDP message?
With the current code:no. If you need to work with non-elementary objects like DOM elements you could code your logic in JavaScript as a workaround. The JavaScript code could then be evaluated in the browser using jseval and return the plain resulting object back to VBA.
Or you could do it the long way around as I do.
IF you opened Edge with the provided code (through CDP protocol) in the first place, then yes!