Clicks not working in Internet Explorer Automation from FoxPro
July 19, 2015 •
A few days ago, somebody posted a question on our message board mentioning that when using Internet Explorer Automation (using COM and InternetExplorer.Application) fails to automate click events in recent versions of Internet Explorer. A quick check with my own code confirmed that indeed clicks are not properly triggering when running code like the following:
o = CREATEOBJECT('InternetExplorer.Application') o.visible = .t. o.Navigate('http://west-wind.com/wconnect/webcontrols/ControlBasics.wcsx') DO WHILE o.ReadyState != 4 WAIT WINDOW "" TIMEOUT .1 ENDDO loWindow = o.document.ParentWindow ? loWindow *loWindow.execScript([alert('hello')]) oLinks = o.Document.getElementsByTagName('a') oLink = oLinks.item(0) ? oLink.href
oLink.click() && doesn’t work o.document.getElementById('txtName').value = 'Rick' oButton = o.document.getElementById('btnSubmit') ? oButton oButton.Click() &&doesn’t work
Note the link and button clicks – when this code is run with Internet Explorer 10 or later the page navigates but the clicks are never registered in the control. Now this used to work just fine in IE 9 and older, but something has clearly changed.
IE 10 – DOM Compliance comes with Changes
Internet Explorer 10 was the first version of IE that supports the standard W3C DOM model, which is different than IE’s older custom DOM implementation. If you’re working with IE COM Automation you will find there are number of small issues that have changed and that can cause major issues in applications. In Html Help Builder which extensively uses IE automation to provide HTML and Markdown editors, I ran into major issues at the time when IE was updated. There both actual DOM changes to deal with the w3C compliance, as well as some behavior changes in the actual COM interface to accessing the DOM from external applications.
The issue in this case is the latter. The problem is that IE is exposing DOM elements natively which means the DOM elements are exposed using the native JavaScript objects as COM objects. Specifically JavaScript always have at least one parameter which is the arguments array and that’s reflected in the dynamic COM interface.
JavaScript Method Calls Require a Parameter
The workaround for this is very simple – instead of calling
.Click()
you can call
.Click(.F.)
Passing the single parameter matches the COM signature and that makes it all work. Thanks to Tore Bleken who reminded me of this issue that I’ve run into myself countless times before in a few other scenarios.
So the updated code is:
o = CREATEOBJECT('InternetExplorer.Application') o.visible = .t. o.Navigate('http://west-wind.com/wconnect/webcontrols/ControlBasics.wcsx') DO WHILE o.ReadyState != 4 WAIT WINDOW "" TIMEOUT .1 ENDDO * Target object has no id so navigate DOM to get object reference oLinks = o.Document.getElementsByTagName('a') oLink = oLinks.item(0) * oLine.Click(.F.) o.document.getElementById('txtName').value = 'Rick' oButton = o.document.getElementById('btnSubmit') ? oButton oButton.Click(.F.)
The hardest part about this is to remember that sometimes this is required other times it is not – it depends on the particular implementation of the element you’re dealing with. In general if you are dealing with an actual element of the DOM this rule applies. I’ve also run into this with global functions called from FoxPro.
The rule is this: Whenever you call into the actual HTML DOM’s native interface, you need to do this. For example, if you define public functions and call them from FoxPro (o.document.parentWindow.myfunction(.F.)) you also need to ensure at least one parameter is passed. As a side note, functions have to be all lower case in order for FoxPro to be able to call them, due to FoxPro forcing COM calls to lower case and the functions being case sensitive in JavaScript.
These are silly issues that if FoxPro were still supported would probably be fairly easy to fix. Alas, since it’s done, we’ll have to live with these oddball COM behaviors. Luckily there are reasonably easy solutions to work around some of the issues like the simple parameter trick above.
Sam
February 03, 2017