/// <summary> /// Executes an Active Scripting function defined in the HTML document currently loaded in the WebBrowser control. /// </summary> /// <param name="scriptName">The name of the script method to invoke.</param> /// <param name="args"></param> /// <returns>The object returned by the Active Scripting call.</returns> public object InvokeScript(string scriptName, params object[] args) { VerifyAccess(); if (string.IsNullOrEmpty(scriptName)) { throw new ArgumentNullException("scriptName"); } UnsafeNativeMethods.IDispatchEx scriptObjectEx = null; UnsafeNativeMethods.IHTMLDocument2 htmlDocument = NativeHTMLDocument; if (htmlDocument != null) { scriptObjectEx = htmlDocument.GetScript() as UnsafeNativeMethods.IDispatchEx; } // Protect against the cross domain scripting attacks. // We rely on the site locking feature in gerneral. But in IE 6 server side redirect is not blocked. // (In IE 7 it is blocked by turning on the DOCHOSTUIFLAG.ENABLE_REDIRECT_NOTIFICATION flag so that // the additional BeforeNavigate2 event is fired for server side redirect.) object retVal = null; if (scriptObjectEx != null) { NativeMethods.DISPPARAMS dp = new NativeMethods.DISPPARAMS(); dp.rgvarg = IntPtr.Zero; try { // If we use reflection to call script code, we need to Assert for the UnmanagedCode permission. // But it will be a security issue when the WPF app makes a framework object available to the // hosted script via ObjectForScripting or as paramter of InvokeScript, and calls the framework // API that demands the UnmanagedCode permission. We do not want the demand to succeed. However, // The stack walk will igore the native frames and keeps going until it reaches the Assert. // That is why we switch to invoking the script via IDispatch with SUCS on the methods. Guid guid = Guid.Empty; string[] names = new string[] { scriptName }; int[] dispids = new int[] { NativeMethods.DISPID_UNKNOWN }; HRESULT hr = scriptObjectEx.GetIDsOfNames(ref guid, names, 1, Thread.CurrentThread.CurrentCulture.LCID, dispids); hr.ThrowIfFailed(); if (args != null) { // Reverse the arg order so that parms read naturally after IDispatch. (WinForms bug 187662) Array.Reverse(args); } dp.rgvarg = (args == null) ? IntPtr.Zero : UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args); dp.cArgs = (uint)((args == null) ? 0 : args.Length); dp.rgdispidNamedArgs = IntPtr.Zero; dp.cNamedArgs = 0; // It's important to use IDispatchEx::InvokeEx here rather than the non-Ex versions for security reasons. // This version allows us to pass the IServiceProvider for security context. // // Calling window.open from within WPF WebBrowser control results in Access Denied script error // Providing a service provider to InvokeEx only makes sense when nesting occurs (for e.g., when WPF calls // a script which calls back into WPF which in turn calls the script again) and there is a need to maintain // the service provider chain. When the execution is from a root occurance, then there is no valid service // provider that will have all of the information from the stack. // // Until recently, IE was ignoring bad service providers -so our passing (IServiceProvider)htmlDocument to InvokeEx // worked. IE has recently taken a security fix to ensure that it doesn't fall back to the last IOleCommandTarget // in the chain it found - so now we simply pass null to indicate that this is the root call site. hr = scriptObjectEx.InvokeEx( dispids[0], Thread.CurrentThread.CurrentCulture.LCID, NativeMethods.DISPATCH_METHOD, dp, out retVal, new NativeMethods.EXCEPINFO(), null); hr.ThrowIfFailed(); } finally { if (dp.rgvarg != IntPtr.Zero) { UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dp.rgvarg, args.Length); } } } else { throw new InvalidOperationException(SR.Get(SRID.CannotInvokeScript)); } return(retVal); }
private void HandleTaskbarListError(HRESULT hr) { if (hr.Failed) { // Even if some of the taskbar methods get this error it doesn't mean that all of them will. // They aren't all implemented with SendMessageTimeout, and unfortunately the ITaskbarList3 API inconsistently // exposes that implementation detail. if (hr == (HRESULT)Win32Error.ERROR_TIMEOUT) { // Explorer appears to be busy. Post back to the Window to try again. if (TraceShell.IsEnabled) { TraceShell.Trace(TraceEventType.Error, TraceShell.ExplorerTaskbarTimeout); TraceShell.Trace(TraceEventType.Warning, TraceShell.ExplorerTaskbarRetrying); } // Explorer being hung should be a transient issue. Post back to apply the full TaskbarItemInfo. _taskbarRetryTimer.Start(); } else if (hr == (HRESULT)Win32Error.ERROR_INVALID_WINDOW_HANDLE) { // We'll get this when Explorer's not running. This means there's no Shell to integrate with. if (TraceShell.IsEnabled) { TraceShell.Trace(TraceEventType.Warning, TraceShell.ExplorerTaskbarNotRunning); } // If this is a transient condition then we'll get a WM_TASKBARBUTTONCREATED when Explorer comes // back and the taskbar button gets created again, at which point we'll rehook. // In the meantime, just stop trying since there's no reasonable expectation of recovery. Utilities.SafeRelease(ref _taskbarList); } else { // That covers the troublesome errors that we know how to handle. // For anything else we'll ignore the error and count on a subsequent update to correct the state. if (TraceShell.IsEnabled) { TraceShell.Trace(TraceEventType.Error, TraceShell.NativeTaskbarError(hr.ToString())); } } } }