/// <summary>Attempts to convert the script object to a string representation.</summary>
        /// <returns>A string representation of the script object, if the object can be converted; otherwise, a string representation of the object's default property or method.</returns>
        // Token: 0x060061E7 RID: 25063 RVA: 0x001B74C8 File Offset: 0x001B56C8
        public override string ToString()
        {
            Guid   empty = Guid.Empty;
            object obj   = null;

            NativeMethods.DISPPARAMS dp = new NativeMethods.DISPPARAMS();
            int     dispid;
            HRESULT hresult;

            if (this.TryGetDispIdForMember("toString", true, out dispid))
            {
                hresult = this.InvokeOnScriptObject(dispid, 1, dp, null, out obj);
            }
            else
            {
                dispid  = 0;
                hresult = this.InvokeOnScriptObject(dispid, 2, dp, null, out obj);
                if (hresult.Failed)
                {
                    hresult = this.InvokeOnScriptObject(dispid, 1, dp, null, out obj);
                }
            }
            if (hresult.Succeeded && obj != null)
            {
                return(obj.ToString());
            }
            return(base.ToString());
        }
示例#2
0
        private HRESULT InvokeOnScriptObject(int dispid, int flags, NativeMethods.DISPPARAMS dp, NativeMethods.EXCEPINFO exInfo, out object result)
        {
            // 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 parameter 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 ignore the native frames and keeps going until it reaches the Assert.
            //
            // As an example, if a call to a script object causes an immediate callback before the initial
            // call returns, reentrancy occurs via COM's blocking message loop on outgoing calls:
            //
            //   [managed ComVisible object]
            //   [CLR COM interop]
            //   [COM runtime]
            //   ole32.dll!CCliModalLoop::BlockFn()
            //   ole32.dll!ModalLoop()
            //   [COM runtime]
            //   PresentationFramework!DynamicScriptObject::InvokeScript(...)
            //
            // That is why we switch to invoking the script via IDispatch with SUCS on the methods.

            if (_scriptObjectEx != null)
            {
                // This case takes care of IE hosting where the use of IDispatchEx is recommended by IE people
                // since the service provider object we can pass here is used by the browser to enforce cross-
                // zone scripting mitigations.
                return(_scriptObjectEx.InvokeEx(dispid, Thread.CurrentThread.CurrentCulture.LCID, flags, dp, out result, exInfo, BrowserInteropHelper.HostHtmlDocumentServiceProvider));
            }
            else
            {
                Guid guid = Guid.Empty;
                return(_scriptObject.Invoke(dispid, ref guid, Thread.CurrentThread.CurrentCulture.LCID, flags, dp, out result, exInfo, null));
            }
        }
        private HRESULT InvokeOnScriptObject(int dispid, int flags, NativeMethods.DISPPARAMS dp, NativeMethods.EXCEPINFO exInfo, out object result)
        {
            if (this._scriptObjectEx != null)
            {
                return(this._scriptObjectEx.InvokeEx(dispid, Thread.CurrentThread.CurrentCulture.LCID, flags, dp, out result, exInfo, BrowserInteropHelper.HostHtmlDocumentServiceProvider));
            }
            Guid empty = Guid.Empty;

            return(this._scriptObject.Invoke(dispid, ref empty, Thread.CurrentThread.CurrentCulture.LCID, flags, dp, out result, exInfo, null));
        }
示例#4
0
        /// <summary>
        /// Provides a string representation of the wrapped script object.
        /// </summary>
        /// <returns>String representation of the wrapped script object, using the toString method or default member on the script object.</returns>
        public override string ToString()
        {
            // Note we shouldn't throw in this method (rule CA1065), so we try with best attempt.

            HRESULT hr;

            Guid   guid   = Guid.Empty;
            object result = null;
            var    dp     = new NativeMethods.DISPPARAMS();

            // Try to find a toString method.
            int dispid;

            if (TryGetDispIdForMember("toString", true /* DISPID caching */, out dispid))
            {
                hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_METHOD, dp, null /* EXCEPINFO */, out result);
            }
            else
            {
                // If no toString method is found, we try the default member first as a property, then as a method.

                dispid = NativeMethods.DISPID_VALUE;

                hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_PROPERTYGET, dp, null /* EXCEPINFO */, out result);

                if (hr.Failed)
                {
                    hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_METHOD, dp, null /* EXCEPINFO */, out result);
                }
            }

            if (hr.Succeeded && result != null)
            {
                return(result.ToString());
            }

            return(base.ToString());
        }
        internal unsafe bool TryFindMemberAndInvokeNonWrapped(string memberName, int flags, bool cacheDispId, object[] args, out object result)
        {
            result = null;

            // In true DLR style we'd return false here, deferring further attempts for resolution to the
            // call site. For better debuggability though, and as we're talking to a specialized object
            // model, we rather throw instead. This Try-method allows internal lookups without directly
            // throwing on non-fatal "member not found" situations, as we might want to have more complex
            // fallback logic (as in ToString).
            int dispid;
            if (!TryGetDispIdForMember(memberName, cacheDispId, out dispid))
            {
                return false;
            }

            NativeMethods.DISPPARAMS dp = new NativeMethods.DISPPARAMS();

            // Required additional DISPPARAMS arguments for PROPERTYPUT cases. See IDispatch::Invoke
            // documentation for more info.
            int propertyPutDispId = NativeMethods.DISPID_PROPERTYPUT;
            if (flags == NativeMethods.DISPATCH_PROPERTYPUT || flags == NativeMethods.DISPATCH_PROPERTYPUTREF)
            {
                dp.cNamedArgs = 1;

                // Stack allocated variables are fixed (unmoveable), so no need to use a fixed
                // statement. The local variable should not get repurposed by the compiler in an
                // unsafe block as we're handing out a pointer to it. For comparison, see the DLR
                // code, CorRuntimeHelpers.cs, where the ConvertInt32ByrefToPtr function relies
                // on the same behavior as they take an IntPtr to a stack-allocated variable that
                // gets used by a DISPPARAMS in a similar way. They have a separate method likely
                // because expression trees can't deal with unsafe code, and they need to fix as
                // they use a by-ref argument which is considered movable (see C# spec, 18.3):
                //
                // public static unsafe IntPtr ConvertInt32ByrefToPtr(ref Int32 value) {
                //     fixed (Int32 *x = &value) {
                //         AssertByrefPointsToStack(new IntPtr(x));
                //         return new IntPtr(x);
                //     }
                // }
                dp.rgdispidNamedArgs = new IntPtr(&propertyPutDispId);
            }

            try
            {
                if (args != null)
                {
                    // Callers of this method might want to implement fallbacks that require the original
                    // arguments in the original order, maybe to feed it in to this method again. If we
                    // wouldn't clone the arguments array into a local copy, we'd be reversing again.
                    args = (object[])args.Clone();

                    // Reverse the argument order so that parameters read naturally after IDispatch.
                    // This code was initially ported from [....], see [....] bug 187662.
                    Array.Reverse(args);

                    // Unwrap arguments that were already promoted to DynamicScriptObject. This can happen
                    // if the output of a script accessing method is fed in to the input of another one.
                    for (int i = 0; i < args.Length; i++)
                    {
                        var wrappedArg = args[i] as DynamicScriptObject;
                        if (wrappedArg != null)
                        {
                            args[i] = wrappedArg._scriptObject;
                        }

                        if (args[i] != null)
                        {
                            // Arrays of COM visible objects (in our definition of the word, see further) are
                            // not considered COM visible by themselves, so we take care of this case as well.
                            // Jagged arrays are not supported somehow, causing a SafeArrayTypeMismatchException
                            // in the call to GetNativeVariantForObject on ArrayToVARIANTVector called below.
                            // Multi-dimensional arrays turn out to work fine, so we don't opt out from those.
                            Type argType = args[i].GetType();
                            if (argType.IsArray)
                            {
                                argType = argType.GetElementType();
                            }

                            // Caveat: IsTypeVisibleFromCom evaluates false for COM object wrappers provided
                            // by the CLR. Therefore we also check for the IsCOMObject property. It also seems
                            // COM interop special-cases DateTime as it's not revealed to be visible by any
                            // of the first two checks below.
                            if (!Marshal.IsTypeVisibleFromCom(argType) && !argType.IsCOMObject && argType != typeof(DateTime))
                            {
                                throw new ArgumentException(SR.Get(SRID.NeedToBeComVisible));
                            }
                        }
                    }

                    dp.rgvarg = UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args);
                    dp.cArgs = (uint)args.Length;
                }

                NativeMethods.EXCEPINFO exInfo = new NativeMethods.EXCEPINFO();
                HRESULT hr = InvokeOnScriptObject(dispid, flags, dp, exInfo, out result);

                if (hr.Failed)
                {
                    if (hr == HRESULT.DISP_E_MEMBERNOTFOUND)
                    {
                        return false;
                    }

                    // See KB article 247784, INFO: '80020101' Returned From Some ActiveX Scripting Methods.
                    // Internet Explorer returns this error when it has already reported a script error to the user
                    // through a dialog or by putting a message in the status bar (Page contains script error). We
                    // want consistency between browsers, so route this through the DISP_E_EXCEPTION case.
                    if (hr == HRESULT.SCRIPT_E_REPORTED)
                    {
                        exInfo.scode = hr.Code;
                        hr = HRESULT.DISP_E_EXCEPTION;
                    }

                    // We prefix exception messagages with "[memberName]" so that the target of the invocation can
                    // be found easily. This is useful beyond just seeing the call site in the debugger as dynamic
                    // calls lead to complicated call stacks with the DLR sliced in between the source and target.
                    // Also, for good or for bad, dynamic has the potential to encourage endless "dotting into", so
                    // it's preferrable to have our runtime resolution failure eloquating the target of the dynamic
                    // call. Unfortunately stock CLR exception types often don't offer a convenient spot to put
                    // this info in, so we resort to the Message property. Anyway, those exceptions are primarily
                    // meant to provide debugging convenience and should not be reported to the end-user in a well-
                    // tested application. Essentially all of this is to be conceived as "deferred compilation".
                    string member = "[" + (memberName ?? "(default)") + "]";
                    Exception comException = hr.GetException();

                    if (hr == HRESULT.DISP_E_EXCEPTION)
                    {
                        // We wrap script execution failures in TargetInvocationException to keep the API surface
                        // free of COMExceptions that reflect a mere implementation detail.
                        int errorCode = exInfo.scode != 0 ? exInfo.scode : exInfo.wCode;
                        hr = HRESULT.Make(true /* severity */, Facility.Dispatch, errorCode);
                        string message = member + " " + (exInfo.bstrDescription ?? string.Empty);
                        throw new TargetInvocationException(message, comException)
                        {
                            HelpLink = exInfo.bstrHelpFile,
                            Source = exInfo.bstrSource
                        };
                    }
                    else if (hr == HRESULT.DISP_E_BADPARAMCOUNT || hr == HRESULT.DISP_E_PARAMNOTOPTIONAL)
                    {
                        throw new TargetParameterCountException(member, comException);
                    }
                    else if (hr == HRESULT.DISP_E_OVERFLOW || hr == HRESULT.DISP_E_TYPEMISMATCH)
                    {
                        throw new ArgumentException(member, new InvalidCastException(comException.Message, hr.Code));
                    }
                    else
                    {
                        // Something really bad has happened; keeping the exception as-is.
                        throw comException;
                    }
                }
            }
            finally
            {
                if (dp.rgvarg != IntPtr.Zero)
                {
                    UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dp.rgvarg, args.Length);
                }
            }

            return true;
        }
        /// <summary>
        /// Provides a string representation of the wrapped script object.
        /// </summary>
        /// <returns>String representation of the wrapped script object, using the toString method or default member on the script object.</returns>
        public override string ToString()
        {
            // Note we shouldn't throw in this method (rule CA1065), so we try with best attempt.

            HRESULT hr;

            Guid guid = Guid.Empty;
            object result = null;
            var dp = new NativeMethods.DISPPARAMS();

            // Try to find a toString method.
            int dispid;
            if (TryGetDispIdForMember("toString", true /* DISPID caching */, out dispid))
            {
                hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_METHOD, dp, null /* EXCEPINFO */, out result);
            }
            else
            {
                // If no toString method is found, we try the default member first as a property, then as a method.

                dispid = NativeMethods.DISPID_VALUE;

                hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_PROPERTYGET, dp, null /* EXCEPINFO */, out result);

                if (hr.Failed)
                {
                    hr = InvokeOnScriptObject(dispid, NativeMethods.DISPATCH_METHOD, dp, null /* EXCEPINFO */, out result);
                }
            }

            if (hr.Succeeded && result != null)
            {
                return result.ToString();
            }

            return base.ToString();
        }
示例#7
0
        internal unsafe bool TryFindMemberAndInvokeNonWrapped(string memberName, int flags, bool cacheDispId, object[] args, out object result)
        {
            result = null;

            // In true DLR style we'd return false here, deferring further attempts for resolution to the
            // call site. For better debuggability though, and as we're talking to a specialized object
            // model, we rather throw instead. This Try-method allows internal lookups without directly
            // throwing on non-fatal "member not found" situations, as we might want to have more complex
            // fallback logic (as in ToString).
            int dispid;

            if (!TryGetDispIdForMember(memberName, cacheDispId, out dispid))
            {
                return(false);
            }

            NativeMethods.DISPPARAMS dp = new NativeMethods.DISPPARAMS();

            // Required additional DISPPARAMS arguments for PROPERTYPUT cases. See IDispatch::Invoke
            // documentation for more info.
            int propertyPutDispId = NativeMethods.DISPID_PROPERTYPUT;

            if (flags == NativeMethods.DISPATCH_PROPERTYPUT || flags == NativeMethods.DISPATCH_PROPERTYPUTREF)
            {
                dp.cNamedArgs = 1;

                // Stack allocated variables are fixed (unmoveable), so no need to use a fixed
                // statement. The local variable should not get repurposed by the compiler in an
                // unsafe block as we're handing out a pointer to it. For comparison, see the DLR
                // code, CorRuntimeHelpers.cs, where the ConvertInt32ByrefToPtr function relies
                // on the same behavior as they take an IntPtr to a stack-allocated variable that
                // gets used by a DISPPARAMS in a similar way. They have a separate method likely
                // because expression trees can't deal with unsafe code, and they need to fix as
                // they use a by-ref argument which is considered movable (see C# spec, 18.3):
                //
                // public static unsafe IntPtr ConvertInt32ByrefToPtr(ref Int32 value) {
                //     fixed (Int32 *x = &value) {
                //         AssertByrefPointsToStack(new IntPtr(x));
                //         return new IntPtr(x);
                //     }
                // }
                dp.rgdispidNamedArgs = new IntPtr(&propertyPutDispId);
            }

            try
            {
                if (args != null)
                {
                    // Callers of this method might want to implement fallbacks that require the original
                    // arguments in the original order, maybe to feed it in to this method again. If we
                    // wouldn't clone the arguments array into a local copy, we'd be reversing again.
                    args = (object[])args.Clone();

                    // Reverse the argument order so that parameters read naturally after IDispatch.
                    // This code was initially ported from WinForms, see WinForms bug 187662.
                    Array.Reverse(args);

                    // Unwrap arguments that were already promoted to DynamicScriptObject. This can happen
                    // if the output of a script accessing method is fed in to the input of another one.
                    for (int i = 0; i < args.Length; i++)
                    {
                        var wrappedArg = args[i] as DynamicScriptObject;
                        if (wrappedArg != null)
                        {
                            args[i] = wrappedArg._scriptObject;
                        }

                        if (args[i] != null)
                        {
                            // Arrays of COM visible objects (in our definition of the word, see further) are
                            // not considered COM visible by themselves, so we take care of this case as well.
                            // Jagged arrays are not supported somehow, causing a SafeArrayTypeMismatchException
                            // in the call to GetNativeVariantForObject on ArrayToVARIANTVector called below.
                            // Multi-dimensional arrays turn out to work fine, so we don't opt out from those.
                            Type argType = args[i].GetType();
                            if (argType.IsArray)
                            {
                                argType = argType.GetElementType();
                            }

                            // Caveat: IsTypeVisibleFromCom evaluates false for COM object wrappers provided
                            // by the CLR. Therefore we also check for the IsCOMObject property. It also seems
                            // COM interop special-cases DateTime as it's not revealed to be visible by any
                            // of the first two checks below.
                            if (
#if NETFX
                                !Marshal.IsTypeVisibleFromCom(argType)
#else
                                !MarshalLocal.IsTypeVisibleFromCom(argType)
#endif
                                && !argType.IsCOMObject && argType != typeof(DateTime))
                            {
                                throw new ArgumentException(SR.Get(SRID.NeedToBeComVisible));
                            }
                        }
                    }

                    dp.rgvarg = UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args);
                    dp.cArgs  = (uint)args.Length;
                }

                NativeMethods.EXCEPINFO exInfo = new NativeMethods.EXCEPINFO();
                HRESULT hr = InvokeOnScriptObject(dispid, flags, dp, exInfo, out result);

                if (hr.Failed)
                {
                    if (hr == HRESULT.DISP_E_MEMBERNOTFOUND)
                    {
                        return(false);
                    }

                    // See KB article 247784, INFO: '80020101' Returned From Some ActiveX Scripting Methods.
                    // Internet Explorer returns this error when it has already reported a script error to the user
                    // through a dialog or by putting a message in the status bar (Page contains script error). We
                    // want consistency between browsers, so route this through the DISP_E_EXCEPTION case.
                    if (hr == HRESULT.SCRIPT_E_REPORTED)
                    {
                        exInfo.scode = hr.Code;
                        hr           = HRESULT.DISP_E_EXCEPTION;
                    }

                    // We prefix exception messagages with "[memberName]" so that the target of the invocation can
                    // be found easily. This is useful beyond just seeing the call site in the debugger as dynamic
                    // calls lead to complicated call stacks with the DLR sliced in between the source and target.
                    // Also, for good or for bad, dynamic has the potential to encourage endless "dotting into", so
                    // it's preferrable to have our runtime resolution failure eloquating the target of the dynamic
                    // call. Unfortunately stock CLR exception types often don't offer a convenient spot to put
                    // this info in, so we resort to the Message property. Anyway, those exceptions are primarily
                    // meant to provide debugging convenience and should not be reported to the end-user in a well-
                    // tested application. Essentially all of this is to be conceived as "deferred compilation".
                    string    member       = "[" + (memberName ?? "(default)") + "]";
                    Exception comException = hr.GetException();

                    if (hr == HRESULT.DISP_E_EXCEPTION)
                    {
                        // We wrap script execution failures in TargetInvocationException to keep the API surface
                        // free of COMExceptions that reflect a mere implementation detail.
                        int errorCode = exInfo.scode != 0 ? exInfo.scode : exInfo.wCode;
                        hr = HRESULT.Make(true /* severity */, Facility.Dispatch, errorCode);
                        string message = member + " " + (exInfo.bstrDescription ?? string.Empty);
                        throw new TargetInvocationException(message, comException)
                              {
                                  HelpLink = exInfo.bstrHelpFile,
                                  Source   = exInfo.bstrSource
                              };
                    }
                    else if (hr == HRESULT.DISP_E_BADPARAMCOUNT || hr == HRESULT.DISP_E_PARAMNOTOPTIONAL)
                    {
                        throw new TargetParameterCountException(member, comException);
                    }
                    else if (hr == HRESULT.DISP_E_OVERFLOW || hr == HRESULT.DISP_E_TYPEMISMATCH)
                    {
                        throw new ArgumentException(member, new InvalidCastException(comException.Message, hr.Code));
                    }
                    else
                    {
                        // Something really bad has happened; keeping the exception as-is.
                        throw comException;
                    }
                }
            }
            finally
            {
                if (dp.rgvarg != IntPtr.Zero)
                {
                    UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dp.rgvarg, args.Length);
                }
            }

            return(true);
        }
示例#8
0
        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.)
 
            // If it is our internal navigation to blank for navigating to null or load stream,
            // or before any navigation has happened, Source will be null.
            Uri currentSource = Source;
            if (currentSource != null) 
            {
                SecurityHelper.DemandWebPermission(currentSource); 
            } 
            // Unfortunately, IWebBrowser2::CurrentURL does not always give us the full truth. It is not updated
            // when the browser navigates to an error page. Then, supposedly, it points to the "intended 
            // destination". (But on canceled navigation the previous URL may stay.) We don't want to allow
            // running script from the built-in error pages as they are privileged.
            // See http://support.microsoft.com/kb/272095 and Dev10.724665. Contrary to what the KB article
            // suggests, document.location.href is not good either. But document.URL seems to be. 
            if (htmlDocument != null)
            { 
                string innerURL = htmlDocument.GetUrl(); 
                // Again, in the special case we've deliberately navigated to about:blank we don't want to
                // demand. But NavigatingToAboutBlank may not be true anymore, so it's not used as a condition. 
                // In that case the two URL properties should match. If not, we'll demand to be safe.
                if (string.CompareOrdinal(innerURL, AxIWebBrowser2.LocationURL) != 0)
                {
                    SecurityHelper.DemandWebPermission(new Uri(innerURL, UriKind.Absolute)); 
                }
            } 
 
            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. ([....] 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.
                    // See Dev10 bugs 710329 and 710325 for context. 
                    hr = scriptObjectEx.InvokeEx(
                        dispids[0], 
                        Thread.CurrentThread.CurrentCulture.LCID, 
                        NativeMethods.DISPATCH_METHOD,
                        dp, 
                        out retVal,
                        new NativeMethods.EXCEPINFO(),
                        (UnsafeNativeMethods.IServiceProvider)htmlDocument);
                    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; 
        }
示例#9
0
        /// <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);
        }
示例#10
0
        public object InvokeScript(string scriptName, params object[] args)
        {
            base.VerifyAccess();
            if (string.IsNullOrEmpty(scriptName))
            {
                throw new ArgumentNullException("scriptName");
            }
            UnsafeNativeMethods.IDispatchEx    dispatchEx         = null;
            UnsafeNativeMethods.IHTMLDocument2 nativeHTMLDocument = this.NativeHTMLDocument;
            if (nativeHTMLDocument != null)
            {
                dispatchEx = (nativeHTMLDocument.GetScript() as UnsafeNativeMethods.IDispatchEx);
            }
            Uri source = this.Source;

            if (source != null)
            {
                SecurityHelper.DemandWebPermission(source);
            }
            if (nativeHTMLDocument != null)
            {
                string url = nativeHTMLDocument.GetUrl();
                if (string.CompareOrdinal(url, this.AxIWebBrowser2.LocationURL) != 0)
                {
                    SecurityHelper.DemandWebPermission(new Uri(url, UriKind.Absolute));
                }
            }
            object result = null;

            if (dispatchEx != null)
            {
                NativeMethods.DISPPARAMS dispparams = new NativeMethods.DISPPARAMS();
                dispparams.rgvarg = IntPtr.Zero;
                try
                {
                    Guid     empty     = Guid.Empty;
                    string[] rgszNames = new string[]
                    {
                        scriptName
                    };
                    int[] array = new int[]
                    {
                        -1
                    };
                    dispatchEx.GetIDsOfNames(ref empty, rgszNames, 1, Thread.CurrentThread.CurrentCulture.LCID, array).ThrowIfFailed();
                    if (args != null)
                    {
                        Array.Reverse(args);
                    }
                    dispparams.rgvarg            = ((args == null) ? IntPtr.Zero : UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args));
                    dispparams.cArgs             = (uint)((args == null) ? 0 : args.Length);
                    dispparams.rgdispidNamedArgs = IntPtr.Zero;
                    dispparams.cNamedArgs        = 0U;
                    dispatchEx.InvokeEx(array[0], Thread.CurrentThread.CurrentCulture.LCID, 1, dispparams, out result, new NativeMethods.EXCEPINFO(), null).ThrowIfFailed();
                    return(result);
                }
                finally
                {
                    if (dispparams.rgvarg != IntPtr.Zero)
                    {
                        UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dispparams.rgvarg, args.Length);
                    }
                }
            }
            throw new InvalidOperationException(SR.Get("CannotInvokeScript"));
        }
        internal unsafe bool TryFindMemberAndInvokeNonWrapped(string memberName, int flags, bool cacheDispId, object[] args, out object result)
        {
            result = null;
            int dispid;

            if (!this.TryGetDispIdForMember(memberName, cacheDispId, out dispid))
            {
                return(false);
            }
            NativeMethods.DISPPARAMS dispparams = new NativeMethods.DISPPARAMS();
            int num = -3;

            if (flags == 4 || flags == 8)
            {
                dispparams.cNamedArgs        = 1U;
                dispparams.rgdispidNamedArgs = new IntPtr((void *)(&num));
            }
            try
            {
                if (args != null)
                {
                    args = (object[])args.Clone();
                    Array.Reverse(args);
                    for (int i = 0; i < args.Length; i++)
                    {
                        DynamicScriptObject dynamicScriptObject = args[i] as DynamicScriptObject;
                        if (dynamicScriptObject != null)
                        {
                            args[i] = dynamicScriptObject._scriptObject;
                        }
                        if (args[i] != null)
                        {
                            Type type = args[i].GetType();
                            if (type.IsArray)
                            {
                                type = type.GetElementType();
                            }
                            if (!Marshal.IsTypeVisibleFromCom(type) && !type.IsCOMObject && type != typeof(DateTime))
                            {
                                throw new ArgumentException(SR.Get("NeedToBeComVisible"));
                            }
                        }
                    }
                    dispparams.rgvarg = UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args);
                    dispparams.cArgs  = (uint)args.Length;
                }
                NativeMethods.EXCEPINFO excepinfo = new NativeMethods.EXCEPINFO();
                HRESULT hrLeft = this.InvokeOnScriptObject(dispid, flags, dispparams, excepinfo, out result);
                if (hrLeft.Failed)
                {
                    if (hrLeft == HRESULT.DISP_E_MEMBERNOTFOUND)
                    {
                        return(false);
                    }
                    if (hrLeft == HRESULT.SCRIPT_E_REPORTED)
                    {
                        excepinfo.scode = hrLeft.Code;
                        hrLeft          = HRESULT.DISP_E_EXCEPTION;
                    }
                    string    text      = "[" + (memberName ?? "(default)") + "]";
                    Exception exception = hrLeft.GetException();
                    if (hrLeft == HRESULT.DISP_E_EXCEPTION)
                    {
                        int code = (excepinfo.scode != 0) ? excepinfo.scode : ((int)excepinfo.wCode);
                        hrLeft = HRESULT.Make(true, Facility.Dispatch, code);
                        string message = text + " " + (excepinfo.bstrDescription ?? string.Empty);
                        throw new TargetInvocationException(message, exception)
                              {
                                  HelpLink = excepinfo.bstrHelpFile,
                                  Source   = excepinfo.bstrSource
                              };
                    }
                    if (hrLeft == HRESULT.DISP_E_BADPARAMCOUNT || hrLeft == HRESULT.DISP_E_PARAMNOTOPTIONAL)
                    {
                        throw new TargetParameterCountException(text, exception);
                    }
                    if (hrLeft == HRESULT.DISP_E_OVERFLOW || hrLeft == HRESULT.DISP_E_TYPEMISMATCH)
                    {
                        throw new ArgumentException(text, new InvalidCastException(exception.Message, hrLeft.Code));
                    }
                    throw exception;
                }
            }
            finally
            {
                if (dispparams.rgvarg != IntPtr.Zero)
                {
                    UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dispparams.rgvarg, args.Length);
                }
            }
            return(true);
        }