I'm implementing the Exec method of TWebBrowser based on this answer. This method is triggered whenever a script error occurs. Now I need to get error information.
I first get hold of the event object of the TWebBrowser.
var
Doc: IHTMLDocument2;
HTMLWindow: IHTMLWindow2;
Event: IHTMLEventObj;
MethodName: String;
MethodResult: OleVariant;
DispatchId: Integer;
Param: array of OleVariant;
begin
//Avoid non-error calls
if nCmdID != OLECMDID_SHOWSCRIPTERROR then
Exit;
//Get hold of the event object
Doc := MapForm.WebBrowser.Document as IHTMLDocument2;
if not Assigned(Doc) then
Exit;
HTMLWindow := Doc.parentWindow;
if not Assigned(HTMLWindow) then
Exit;
//Get the current event
Event := HTMLWindow.event;
And then I'm trying to get the information I need (as demonstrated in this link) using GetIDsOfNames
and Invoke
functions of the interface. A working Delphi code for using these methods are in this documentation link.
Here is how I use these functions on the Event object.
MethodName := 'errorMessage';
Result := Event.GetIDsOfNames(GUID_NULL, @MethodName, 1, SysLocale.DefaultLCID, @DispatchId);
Result := Event.Invoke(DispatchId, GUID_NULL, SysLocale.DefaultLCID, DISPATCH_METHOD, Param, @MethodResult, nil, nil);
The GetIDsOfNames
fuGetIDsOfNames function executes properly, outputs an acceptable integer to DispatchId
and returns S_OK
.
But the Invoke
function just fails. It returns some negative integer as HRESULT
and doesn't output anything to MethodResult
.
How can I work around this?
The error values you are trying to access are not object methods, they are properties, so Invoke()
is going to fail due to your use of DISPATCH_METHOD
. Use DISPATCH_PROPERTYGET
instead.
However, OleVariant
(and Variant
) has built-in support for IDispatch.Invoke()
, so you don't need to mess with it manually at all. You can call object methods and read/write object properties normally, and the compiler will produce the necessary IDispatch
calls for you.
Try something more like this:
function TWebBrowser.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD;
const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall;
var
Event: OleVariant;
ErrorLine: Integer;
ErrorChar: Char;
ErrorCode: Integer;
ErrorMsg: String;
ErrorUrl: String;
begin
if (CmdGroup = nil) or not IsEqualGUID(CmdGroup^, CGID_DocHostCommandHandler) then
begin
Result := OLECMDERR_E_UNKNOWNGROUP;
Exit;
end;
if nCmdID <> OLECMDID_SHOWSCRIPTERROR then
begin
Result := OLECMDERR_E_NOTSUPPORTED;
Exit;
end;
Event := (IUnknown(vaIn) as IHTMLDocument2).parentWindow.event;
ErrorLine := Event.errorLine;
ErrorChar := Event.errorCharacter;
ErrorCode := Event.errorCode;
ErrorMsg := Event.errorMessage;
ErrorUrl := Event.errorUrl;
...
if (should continue running scripts) then
begin
vaOut := True;
end else
begin
vaOut := False;
end;
Result := S_OK;
end;