Search code examples
delphiinterfacedelphi-xeoletwebbrowser

How to get TWebBrowser error information


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?


Solution

  • 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;