I have a WinForms application in which I hosted a webpage inside a WebBrowser .
The content of the web page is as follows:
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <title>onbeforeunload test</title> <meta charset="utf-8"> </head> <body> <a href="#" onclick="window.location.reload();">Test</a> <script type="text/javascript"> window.onbeforeunload = function () { return 'Are you sure you want to leave this page?'; }; </script> </body> </html>
As you can see, I signed up for the onbeforeunload event, which allows you to display a confirmation dialog before proceeding from this page. This works great when I click on an anchor that reloads the page. A confirmation window will appear, and the user can cancel the page reload. This works great inside a hosted WinForms control.
Now I am having difficulty intercepting and executing this event when the user closes the WinForms application (for example, by pressing the X button).
I can get the contents of this function in a WinForms application, but no matter what I tried, I was unable to get the contents of the string returned by this function to subsequently use it to fake a MessageBox when the user tries to close the application:
webBrowser1.Navigated += (sender, e) => { webBrowser1.Document.Window.Load += (s, ee) => {
I tried the window.execScript method window.execScript that it is not available:
// returns null var script = string.Format("({0})();", bu); var result = window.execScript(script, "javascript");
I also tried the following, but also returned null:
var result = window.execScript("(function() { return 'foo'; })();", "javascript");
As a final option, I could use a third-party javascript analyzer, which I can feed the body of this function, and it will execute it and give me a return value, but it really will be the last resort. I would be happy if there was a more natural way to do this using the Microsoft MSHTML library.
UPDATE:
This is now resolved thanks to the excellent answer that @Aans provided. For some reason, I couldn't get my solution to work on my test machine (Win7 x64, .NET 4.0 Client Profile, IE9, en-US locale), and I always got hr = -2147024809 after calling IDispatch.Invoke . Therefore, I changed the IDispatch P / Invoke signature as follows (this signature does not require a link to c:\windows\system32\stdole2.tlb to add to the project):
using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("00020400-0000-0000-C000-000000000046")] public interface IDispatch { [PreserveSig] int GetTypeInfoCount(out int Count); [PreserveSig] int GetTypeInfo( [MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, out ITypeInfo typeInfo ); [PreserveSig] int GetIDsOfNames( ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId ); [PreserveSig] int Invoke( int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr ); }
and then I signed up for the form closing event and was able to receive the message returned by the onbeforeunload event and request the user:
protected override void OnFormClosing(FormClosingEventArgs e) { var window = (IHTMLWindow2)webBrowser1.Document.Window.DomWindow; var args = new System.Runtime.InteropServices.ComTypes.DISPPARAMS(); var result = new object(); var except = new System.Runtime.InteropServices.ComTypes.EXCEPINFO(); var idisp = window.onbeforeunload as IDispatch; if (idisp != null) { var iid = Guid.Empty; var lcid = (uint)CultureInfo.CurrentCulture.LCID; int hr = idisp.Invoke(0, ref iid, lcid, 1, ref args, out result, ref except, null); if (hr == 0) { var msgBox = MessageBox.Show( this, (string)result, "Confirm", MessageBoxButtons.OKCancel ); e.Cancel = msgBox == DialogResult.Cancel; } } base.OnFormClosing(e); }