Binding to Internet Explorer events: bug in Typelibrary
I was using the web browser control and getting some errors when binding to its events. This can be duplicated with the code below.
To generate the event class, open the object browser (Tools->Object Browser) and select the Microsoft Web Browser Control. Navigate to the DWebBrowserEvents2 interface and drag and drop it onto an open PRG editor window.
The object browser reads the interface definition from the type library for the chosen COM object and defines a class with the appropriate method signatures for you.
Then I added a couple lines to instantiate the web browser, the event class, and bind them together.
Running the code highlights the FileDownload method and gives the error: “Must specify additional parameters.”
Because this error is generated by an external object (IE) calling VFP, but before even reaching any VFP user code, a TRY/CATCH or error handler doesn’t help.
Further investigation showed that the FileDownload method of the DWebBrowserEvents2 interface shows that there is one parameter specified in the Type library.
[id(0x0000010e), helpstring("Fired to indicate the File Download dialog is opening")]
void FileDownload([in, out] VARIANT_BOOL* Cancel);
However, IE is calling with 2 parameters. The MSDN documentation for this method shows 2 parameters:
void FileDownload(
VARIANT_BOOL *&ActiveDocument,
VARIANT_BOOL *&Cancel
);
This KB article has more info. In particular, it states “any development tool that generates event handlers that are based on the type library cannot properly sink the event. “ The article itself has to do with .NET interop with the web browser control, so C# and VB.Net have the same problem.
Rick Strahl’s article also mentions this bug.
VFP internally reads the typelib and tries to match the number and type of parameters for each method. If the number of parameters aren’t exactly the same, VFP triggers an error message.
Perhaps a fix to this on the VFP side would be to relax the restriction that the number of parameters match exactly: just trigger an error if the number of parameters in the TypeLib is greater than the number defined in the VFP method. This change will allow the user to add more parameters to the implemented methods, which would fix this issue and also allow the method to be called internally with additional parameter(s).
oIe=
CREATEOBJECT("internetexplorer.application")
oIe.
visible=1
oEvents =
NEWOBJECT("webEvents")
?
EVENTHANDLER(oIE,oEvents)
oIe.navigate2("www.msn.com")
DEFINE CLASS
webEvents AS custom
IMPLEMENTS
DWebBrowserEvents2 IN "c:\windows\system32\shdocvw.dll"
PROCEDURE logit(cstr as String)
?cstr
PROCEDURE init
this
.logit(PROGRAM())
PROCEDURE DWebBrowserEvents2_StatusTextChange(Text AS STRING) AS VOID;
HELPSTRING "Statusbar text changed."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_ProgressChange(Progress AS Number, ProgressMax AS Number) AS VOID;
HELPSTRING "Fired when download progress is updated."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_CommandStateChange(Command AS Number, Enable AS LOGICAL) AS VOID;
HELPSTRING "The enabled state of a command changed."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_DownloadBegin() AS VOID;
HELPSTRING "Download of a page started."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_DownloadComplete() AS VOID;
HELPSTRING "Download of page complete."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_TitleChange(Text AS STRING) AS VOID;
HELPSTRING "Document title changed."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_PropertyChange(szProperty AS STRING) AS VOID;
HELPSTRING "Fired when the PutProperty method has been called."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_BeforeNavigate2(pDisp AS VARIANT, URL AS VARIANT, Flags AS VARIANT, TargetFrameName AS VARIANT, PostData AS VARIANT, Headers AS VARIANT, Cancel AS LOGICAL @) AS VOID;
HELPSTRING "Fired before navigate occurs in the given WebBrowser (window or frameset element). The processing of this navigation may be modified."
this.logit(PROGRAM()+" "+url+" "+TRANSFORM(flags))
ENDPROC
PROCEDURE
DWebBrowserEvents2_NewWindow2(ppDisp AS VARIANT @, Cancel AS LOGICAL @) AS VOID;
HELPSTRING "A new, hidden, non-navigated WebBrowser window is needed."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_NavigateComplete2(pDisp AS VARIANT, URL AS VARIANT) AS VOID;
HELPSTRING "Fired when the document being navigated to becomes visible and enters the navigation stack."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_DocumentComplete(pDisp AS VARIANT, URL AS VARIANT) AS VOID;
HELPSTRING "Fired when the document being navigated to reaches ReadyState_Complete."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnQuit() AS VOID;
HELPSTRING "Fired when application is quiting."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnVisible(Visible AS LOGICAL) AS VOID;
HELPSTRING "Fired when the window should be shown/hidden"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnToolBar(ToolBar AS LOGICAL) AS VOID;
HELPSTRING "Fired when the toolbar should be shown/hidden"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnMenuBar(MenuBar AS LOGICAL) AS VOID;
HELPSTRING "Fired when the menubar should be shown/hidden"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnStatusBar(StatusBar AS LOGICAL) AS VOID;
HELPSTRING "Fired when the statusbar should be shown/hidden"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnFullScreen(FullScreen AS LOGICAL) AS VOID;
HELPSTRING "Fired when fullscreen mode should be on/off"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_OnTheaterMode(TheaterMode AS LOGICAL) AS VOID;
HELPSTRING "Fired when theater mode should be on/off"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowSetResizable(Resizable AS LOGICAL) AS VOID;
HELPSTRING "Fired when the host window should allow/disallow resizing"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowSetLeft(Left AS Number) AS VOID;
HELPSTRING "Fired when the host window should change its Left coordinate"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowSetTop(Top AS Number) AS VOID;
HELPSTRING "Fired when the host window should change its Top coordinate"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowSetWidth(Width AS Number) AS VOID;
HELPSTRING "Fired when the host window should change its width"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowSetHeight(Height AS Number) AS VOID;
HELPSTRING "Fired when the host window should change its height"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_WindowClosing(IsChildWindow AS LOGICAL, Cancel AS LOGICAL @) AS VOID;
HELPSTRING "Fired when the WebBrowser is about to be closed by script"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_ClientToHostWindow(CX AS Number @, CY AS Number @) AS VOID;
HELPSTRING "Fired to request client sizes be converted to host window sizes"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_SetSecureLockIcon(SecureLockIcon AS Number) AS VOID;
HELPSTRING "Fired to indicate the security level of the current web page contents"
this.logit(PROGRAM())
ENDPROC
* PROCEDURE DWebBrowserEvents2_FileDownload( Cancel AS LOGICAL @) AS VOID
PROCEDURE DWebBrowserEvents2_FileDownload(fActiveDoc as Logical @, Cancel AS LOGICAL @) AS VOID;
HELPSTRING "Fired to indicate the File Download dialog is opening"
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_NavigateError(pDisp AS VARIANT, URL AS VARIANT, Frame AS VARIANT, StatusCode AS VARIANT, Cancel AS LOGICAL @) AS VOID;
HELPSTRING "Fired when a binding error occurs (window or frameset element)."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_PrintTemplateInstantiation(pDisp AS VARIANT) AS VOID;
HELPSTRING "Fired when a print template is instantiated."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_PrintTemplateTeardown(pDisp AS VARIANT) AS VOID;
HELPSTRING "Fired when a print template destroyed."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_UpdatePageStatus(pDisp AS VARIANT, nPage AS VARIANT, fDone AS VARIANT) AS VOID;
HELPSTRING "Fired when a page is spooled. When it is fired can be changed by a custom template."
this.logit(PROGRAM())
ENDPROC
PROCEDURE
DWebBrowserEvents2_PrivacyImpactedStateChange(bImpacted AS LOGICAL) AS VOID;
HELPSTRING "Fired when the global privacy impacted state changes"
this.logit(PROGRAM())
ENDPROC
ENDDEFINE
Comments
- Anonymous
July 24, 2005
Hi Calvin,
I'm interested in binding to IE events dynamically for the currently active IE window open and selected by the user. Do you think I could bind to some windows event which notifies me when a new or exting IE window becomes active? - Anonymous
March 18, 2006
Is there a way to capture the event of an active IE window being moved in C#? Thanks. - Anonymous
June 14, 2006
The EventHandler function allows you to connect some code to an object’s event interface. For example,... - Anonymous
September 27, 2007
A customer wanted to run code whenever a user started Internet Explorer. A possible solution is to use