I need to capture script errors in MS IE activex control (dubbed as WebBrowser).
As I see it, this is done by implementing the IOleCommandTarget interface in my application and listening for OLECMDID_SHOWSCRIPTERROR.
I did the above and I know it works since my Exec method is called, but here's the problem; it is only called once with nCmdID
being set to $00000037
(OLECMDID_PAGEACTIONBLOCKED
), but never $00000028
(OLECMDID_SHOWSCRIPTERROR
).
In order to trigger that error, I've been using this code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TEST SCRIPT</title>
</head><body>
<script type="text/javascript">
document.body.style.background='yellow';
setTimeout(function(){
document.body.style.background='red';
causeERROR(); // purposefully undefined function
document.body.style.background='green';
},500);
</script>
</body>
</html>
The code above shows a yellow page, then after a few milliseconds, a red one and if script execution continues (after the error occurs) it should be green.
Right after turning red, I get MSIE's script error dialog, which is all fine. But my Exec method is not triggered.
Note: The delayed error above is to ensure a runtime error as opposed to a page load error, just in case it does a difference.
My IOleCommandTarget
implementation is as follows (Delphi):
type
TNulWBContainer = class(TWebBrowser, IUnknown, IOleClientSite,
IDocHostUIHandler, IDispatch, IOleCommandTarget)
protected
{ OTHER STUFF }
{IOleCommandTarget Interface}
function QueryStatus(CmdGroup: PGUID; cCmds: Cardinal;
prgCmds: POleCmd; CmdText: POleCmdText): HResult; stdcall;
function Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD;
const vaIn: OleVariant; var vaOut: OleVariant): HResult; stdcall;
end;
implementation
{ OTHER STUFF }
function TNulWBContainer.QueryStatus(CmdGroup: PGUID; cCmds: Cardinal;
prgCmds: POleCmd; CmdText: POleCmdText): HResult; stdcall;
begin
prgCmds.cmdf := OLECMDF_ENABLED;
Result := S_OK; //inherited QueryStatus(CmdGroup,cCmds,prgCmds,CmdText);
end;
function TNulWBContainer.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD;
const vaIn: OleVariant; var vaOut: OleVariant): HResult; stdcall;
begin
ShowMessage('nCmdID=$'+IntToHex(nCmdID,8));
Result:=OLECMDERR_E_UNKNOWNGROUP;
end;
end.
I'm running this stuff on Windows 7 Ult 64bit. I have MS Script Debugger installed and MSIE's "Disable script debugging for nnn" turned off for both options. MSIE is v9.0.8112.16421.
Note: I didn't tag this under Delphi since all native languages out there can be easily translated to Delphi, even some managed languages such as VB or C#.
Related Links:
- http://support.microsoft.com/kb/261003
- http://www.codeproject.com/KB/shell/popupblocker.aspx
- http://www.tech-archive.net/Archive/VC/microsoft.public.vc.atl/2007-10/msg00158.html - This is kind of cryptic, I didn't understand (2), (4) and (5).
This is the silliest bug in ages! No seriously!
MS, you really SUCK on this one ;)
I got it working, my code was actually correct from the beginning (ie, two days ago ;))
As the article said, you need
Disable Script Debugging (Internet Explorer)
unchecked.BUT
Disable Script Debugging (Other)
must be checked (in Internet Options > Advanced).Weird huh? I got the tip from here: http://www.delphigroups.info/2/9/938468.html (2005-04-29 09:42:48 PM).
Yes, that's 6 years ago. I'm surprised, no, amazed, that such a thing could be possible and not documented anywhere.
Edit: Programmatic fix: