栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

通过C#解析并执行JS

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

通过C#解析并执行JS

为了回答标题为“如何在C#中解析和执行JS”的问题,下面的代码包装了Windows脚本引擎。它支持32位和64位环境。

在您的特定情况下,这意味着取决于.JS代码,您可能必须模拟/实现一些HTMLDOM元素,例如“文档”,“窗口”等(使用MyItem类使用“命名项”功能)。正是Internet Explorer所做的)。

以下是您可以使用它的一些示例:

1)直接表达式求值:

Console.WriteLine(scriptEngine.eval("jscript", "1+2/3"));

将显示1.66666666666667

2)函数调用,带有可选参数:

using (scriptEngine engine = new scriptEngine("jscript")){  Parsedscript parsed = engine.Parse("function MyFunc(x){return 1+2+x}");  Console.WriteLine(parsed.CallMethod("MyFunc", 3));}

将显示6

3)带有命名项和可选参数的函数调用:

using (scriptEngine engine = new scriptEngine("jscript")){    Parsedscript parsed = engine.Parse("function MyFunc(x){return 1+2+x+My.Num}");    MyItem item = new MyItem();    item.Num = 4;    engine.SetNamedItem("My", item);    Console.WriteLine(parsed.CallMethod("MyFunc", 3));}[ComVisible(true)] // script engines are COM components.public class MyItem{    public int Num { get; set; }}

将显示10。

编辑 :我添加了使用CLSID代替脚本语言名称的可能性,因此我们可以重复使用新的快速IE9 +“chakra”
Javascript引擎,如下所示:

using (scriptEngine engine = new scriptEngine("{16d51579-a30b-4c8b-a276-0ff4dc41e755}")){    // continue with chakra now}

这是完整的源代码:

/// <summary>/// Represents a Windows script Engine such as Jscript, VBscript, etc./// </summary>public sealed class scriptEngine : IDisposable{    /// <summary>    /// The name of the function used for simple evaluation.    /// </summary>    public const string MethodName = "evalMethod";    /// <summary>    /// The default scripting language name.    /// </summary>    public const string DefaultLanguage = JavascriptLanguage;    /// <summary>    /// The Javascript or jscript scripting language name.    /// </summary>    public const string JavascriptLanguage = "javascript";    /// <summary>    /// The javascript or jscript scripting language name.    /// </summary>    public const string VBscriptLanguage = "vbscript";    /// <summary>    /// The chakra javascript engine CLSID. The value is {16d51579-a30b-4c8b-a276-0ff4dc41e755}.    /// </summary>    public const string ChakraClsid = "{16d51579-a30b-4c8b-a276-0ff4dc41e755}";    private IActivescript _engine;    private IActivescriptParse32 _parse32;    private IActivescriptParse64 _parse64;    internal scriptSite Site;    private Version _version;    private string _name;    [Guid("BB1A2AE1-A4F9-11cf-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescript    {        [PreserveSig]        int SetscriptSite(IActivescriptSite pass);        [PreserveSig]        int GetscriptSite(Guid riid, out IntPtr site);        [PreserveSig]        int SetscriptState(scriptState state);        [PreserveSig]        int GetscriptState(out scriptState scriptState);        [PreserveSig]        int Close();        [PreserveSig]        int AddNamedItem(string name, scriptItem flags);        [PreserveSig]        int AddTypeLib(Guid typeLib, uint major, uint minor, uint flags);        [PreserveSig]        int GetscriptDispatch(string itemName, out IntPtr dispatch);        [PreserveSig]        int GetCurrentscriptThreadID(out uint thread);        [PreserveSig]        int GetscriptThreadID(uint win32ThreadId, out uint thread);        [PreserveSig]        int GetscriptThreadState(uint thread, out scriptThreadState state);        [PreserveSig]        int InterruptscriptThread(uint thread, out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo, uint flags);        [PreserveSig]        int Clone(out IActivescript script);    }    [Guid("4954E0D0-FBC7-11D1-8410-006008C3FBFC"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescriptProperty    {        [PreserveSig]        int GetProperty(int dwProperty, IntPtr pvarIndex, out object pvarValue);        [PreserveSig]        int SetProperty(int dwProperty, IntPtr pvarIndex, ref object pvarValue);    }    [Guid("DB01A1E3-A42B-11cf-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescriptSite    {        [PreserveSig]        int GetLCID(out int lcid);        [PreserveSig]        int GetItemInfo(string name, scriptInfo returnMask, out IntPtr item, IntPtr typeInfo);        [PreserveSig]        int GetDocVersionString(out string version);        [PreserveSig]        int OnscriptTerminate(object result, System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);        [PreserveSig]        int onStateChange(scriptState scriptState);        [PreserveSig]        int OnscriptError(IActivescriptError scriptError);        [PreserveSig]        int OnEnterscript();        [PreserveSig]        int OnLeavescript();    }    [Guid("EAE1BA61-A4ED-11cf-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescriptError    {        [PreserveSig]        int GetExceptionInfo(out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);        [PreserveSig]        int GetSourcePosition(out uint sourceContext, out int lineNumber, out int characterPosition);        [PreserveSig]        int GetSourceLineText(out string sourceLine);    }    [Guid("BB1A2AE2-A4F9-11cf-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescriptParse32    {        [PreserveSig]        int InitNew();        [PreserveSig]        int Addscriptlet(string defaultName, string pre, string itemName, string subItemName, string eventName, string delimiter, IntPtr sourceContextcookie, uint startingLineNumber, scriptText flags, out string name, out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);        [PreserveSig]        int ParsescriptText(string pre, string itemName, IntPtr context, string delimiter, int sourceContextcookie, uint startingLineNumber, scriptText flags, out object result, out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);    }    [Guid("C7EF7658-E1EE-480E-97EA-D52CB4D76D17"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]    private interface IActivescriptParse64    {        [PreserveSig]        int InitNew();        [PreserveSig]        int Addscriptlet(string defaultName, string pre, string itemName, string subItemName, string eventName, string delimiter, IntPtr sourceContextcookie, uint startingLineNumber, scriptText flags, out string name, out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);        [PreserveSig]        int ParsescriptText(string pre, string itemName, IntPtr context, string delimiter, long sourceContextcookie, uint startingLineNumber, scriptText flags, out object result, out System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo);    }    [Flags]    private enum scriptText    {        None = 0,        //DelayExecution = 1,        //IsVisible = 2,        Isexpression = 32,        IsPersistent = 64,        //HostManageSource = 128    }    [Flags]    private enum scriptInfo    {        //None = 0,        //IUnknown = 1,        ITypeInfo = 2    }    [Flags]    private enum scriptItem    {        //None = 0,        IsVisible = 2,        IsSource = 4,        //GlobalMembers = 8,        //IsPersistent = 64,        //Codeonly = 512,        //NoCode = 1024    }    private enum scriptThreadState    {        //NotInscript = 0,        //Running = 1    }    private enum scriptState    {        Uninitialized = 0,        Started = 1,        Connected = 2,        Disconnected = 3,        Closed = 4,        Initialized = 5    }    private const int TYPE_E_ELEMENTNOTFOUND = unchecked((int)(0x8002802B));    private const int E_NOTIMPL = -2147467263;    /// <summary>    /// Determines if a script engine with the input name exists.    /// </summary>    /// <param name="language">The language.</param>    /// <returns>true if the engine exists; false otherwise.</returns>    public static Version GetVersion(string language)    {        if (language == null) throw new ArgumentNullException("language");        Type engine;        Guid clsid;        if (Guid.TryParse(language, out clsid))        { engine = Type.GetTypeFromCLSID(clsid, false);        }        else        { engine = Type.GetTypeFromProgID(language, false);        }        if (engine == null) return null;        IActivescript scriptEngine = Activator.CreateInstance(engine) as IActivescript;        if (scriptEngine == null) return null;        IActivescriptProperty scriptProperty = scriptEngine as IActivescriptProperty;        if (scriptProperty == null) return new Version(1, 0, 0, 0);        int major = GetProperty(scriptProperty, scriptPROP_MAJORVERSION, 0);        int minor = GetProperty(scriptProperty, scriptPROP_MINORVERSION, 0);        int revision = GetProperty(scriptProperty, scriptPROP_BUILDNUMBER, 0);        Version version = new Version(major, minor, Environment.OSVersion.Version.Build, revision);        Marshal.ReleaseComObject(scriptProperty);        Marshal.ReleaseComObject(scriptEngine);        return version;    }    private static T GetProperty<T>(IActivescriptProperty prop, int index, T defaultValue)    {        object value;        if (prop.GetProperty(index, IntPtr.Zero, out value) != 0) return defaultValue;        try        { return (T)Convert.ChangeType(value, typeof(T));        }        catch        { return defaultValue;        }    }    /// <summary>     /// Initializes a new instance of the <see cref="scriptEngine"/> class.     /// </summary>     /// <param name="language">The scripting language. Standard Windows script engines names are 'jscript' or 'vbscript'.</param>     public scriptEngine(string language)    {        if (language == null) throw new ArgumentNullException("language");        Type engine;        Guid clsid;        if (Guid.TryParse(language, out clsid))        { engine = Type.GetTypeFromCLSID(clsid, true);        }        else        { engine = Type.GetTypeFromProgID(language, true);        }        _engine = Activator.CreateInstance(engine) as IActivescript;        if (_engine == null) throw new ArgumentException(language + " is not an Windows script Engine", "language");        Site = new scriptSite();        _engine.SetscriptSite(Site);        // support 32-bit & 64-bit process         if (IntPtr.Size == 4)        { _parse32 = (IActivescriptParse32)_engine; _parse32.InitNew();        }        else        { _parse64 = (IActivescriptParse64)_engine; _parse64.InitNew();        }    }    private const int scriptPROP_NAME = 0x00000000;    private const int scriptPROP_MAJORVERSION = 0x00000001;    private const int scriptPROP_MINORVERSION = 0x00000002;    private const int scriptPROP_BUILDNUMBER = 0x00000003;    /// <summary>    /// Gets the engine version.    /// </summary>    /// <value>    /// The version.    /// </value>    public Version Version    {        get        { if (_version == null) {     int major = GetProperty(scriptPROP_MAJORVERSION, 0);     int minor = GetProperty(scriptPROP_MINORVERSION, 0);     int revision = GetProperty(scriptPROP_BUILDNUMBER, 0);     _version = new Version(major, minor, Environment.OSVersion.Version.Build, revision); } return _version;        }    }    /// <summary>    /// Gets the engine name.    /// </summary>    /// <value>    /// The name.    /// </value>    public string Name    {        get        { if (_name == null) {     _name = GetProperty(scriptPROP_NAME, string.Empty); } return _name;        }    }    /// <summary>    /// Gets a script engine property.    /// </summary>    /// <typeparam name="T">The expected property type.</typeparam>    /// <param name="index">The property index.</param>    /// <param name="defaultValue">The default value if not found.</param>    /// <returns>The value of the property or the default value.</returns>    public T GetProperty<T>(int index, T defaultValue)    {        object value;        if (!TryGetProperty(index, out value)) return defaultValue;        try        { return (T)Convert.ChangeType(value, typeof(T));        }        catch        { return defaultValue;        }    }    /// <summary>    /// Gets a script engine property.    /// </summary>    /// <param name="index">The property index.</param>    /// <param name="value">The value.</param>    /// <returns>true if the property was successfully got; false otherwise.</returns>    public bool TryGetProperty(int index, out object value)    {        value = null;        IActivescriptProperty property = _engine as IActivescriptProperty;        if (property == null) return false;        return property.GetProperty(index, IntPtr.Zero, out value) == 0;    }    /// <summary>    /// Sets a script engine property.    /// </summary>    /// <param name="index">The property index.</param>    /// <param name="value">The value.</param>    /// <returns>true if the property was successfully set; false otherwise.</returns>    public bool SetProperty(int index, object value)    {        IActivescriptProperty property = _engine as IActivescriptProperty;        if (property == null) return false;        return property.SetProperty(index, IntPtr.Zero, ref value) == 0;    }    /// <summary>     /// Adds the name of a root-level item to the scripting engine's name space.     /// </summary>     /// <param name="name">The name. May not be null.</param>     /// <param name="value">The value. It must be a ComVisible object.</param>     public void SetNamedItem(string name, object value)    {        if (name == null) throw new ArgumentNullException("name");        _engine.AddNamedItem(name, scriptItem.IsVisible | scriptItem.IsSource);        Site.NamedItems[name] = value;    }    internal class scriptSite : IActivescriptSite    {        internal scriptException LastException;        internal Dictionary<string, object> NamedItems = new Dictionary<string, object>();        int IActivescriptSite.GetLCID(out int lcid)        { lcid = Thread.CurrentThread.CurrentCulture.LCID; return 0;        }        int IActivescriptSite.GetItemInfo(string name, scriptInfo returnMask, out IntPtr item, IntPtr typeInfo)        { item = IntPtr.Zero; if ((returnMask & scriptInfo.ITypeInfo) == scriptInfo.ITypeInfo)     return E_NOTIMPL; object value; if (!NamedItems.TryGetValue(name, out value))     return TYPE_E_ELEMENTNOTFOUND; item = Marshal.GetIUnknownForObject(value); return 0;        }        int IActivescriptSite.GetDocVersionString(out string version)        { version = null; return 0;        }        int IActivescriptSite.OnscriptTerminate(object result, System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo)        { return 0;        }        int IActivescriptSite.onStateChange(scriptState scriptState)        { return 0;        }        int IActivescriptSite.OnscriptError(IActivescriptError scriptError)        { string sourceLine = null; try {     scriptError.GetSourceLineText(out sourceLine); } catch {     // happens sometimes...  } uint sourceContext; int lineNumber; int characterPosition; scriptError.GetSourcePosition(out sourceContext, out lineNumber, out characterPosition); lineNumber++; characterPosition++; System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo; scriptError.GetExceptionInfo(out exceptionInfo); string message; if (!string.IsNullOrEmpty(sourceLine)) {     message = "script exception: {1}. Error number {0} (0x{0:X8}): {2} at line {3}, column {4}. Source line: '{5}'."; } else {     message = "script exception: {1}. Error number {0} (0x{0:X8}): {2} at line {3}, column {4}."; } LastException = new scriptException(string.Format(message, exceptionInfo.spre, exceptionInfo.bstrSource, exceptionInfo.bstrDescription, lineNumber, characterPosition, sourceLine)); LastException.Column = characterPosition; LastException.Description = exceptionInfo.bstrDescription; LastException.Line = lineNumber; LastException.Number = exceptionInfo.spre; LastException.Text = sourceLine; return 0;        }        int IActivescriptSite.OnEnterscript()        { LastException = null; return 0;        }        int IActivescriptSite.OnLeavescript()        { return 0;        }    }    /// <summary>     /// evaluates an expression using the specified language.     /// </summary>     /// <param name="language">The language.</param>     /// <param name="expression">The expression. May not be null.</param>     /// <returns>The result of the evaluation.</returns>     public static object eval(string language, string expression)    {        return eval(language, expression, null);    }    /// <summary>     /// evaluates an expression using the specified language, with an optional array of named items.     /// </summary>     /// <param name="language">The language.</param>     /// <param name="expression">The expression. May not be null.</param>     /// <param name="namedItems">The named items array.</param>     /// <returns>The result of the evaluation.</returns>     public static object eval(string language, string expression, params KeyValuePair<string, object>[] namedItems)    {        if (language == null) throw new ArgumentNullException("language");        if (expression == null) throw new ArgumentNullException("expression");        using (scriptEngine engine = new scriptEngine(language))        { if (namedItems != null) {     foreach (KeyValuePair<string, object> kvp in namedItems)     {         engine.SetNamedItem(kvp.Key, kvp.Value);     } } return engine.eval(expression);        }    }    /// <summary>     /// evaluates an expression.     /// </summary>     /// <param name="expression">The expression. May not be null.</param>     /// <returns>The result of the evaluation.</returns>     public object eval(string expression)    {        if (expression == null) throw new ArgumentNullException("expression");        return Parse(expression, true);    }    /// <summary>     /// Parses the specified text and returns an object that can be used for evaluation.     /// </summary>     /// <param name="text">The text to parse.</param>     /// <returns>An instance of the Parsedscript class.</returns>     public Parsedscript Parse(string text)    {        if (text == null) throw new ArgumentNullException("text");        return (Parsedscript)Parse(text, false);    }    private object Parse(string text, bool expression)    {        const string varName = "x___";        object result;        _engine.SetscriptState(scriptState.Connected);        scriptText flags = scriptText.None;        if (expression)        { flags |= scriptText.Isexpression;        }        try        { // immediate expression computation seems to work only for 64-bit  // so hack something for 32-bit...  System.Runtime.InteropServices.ComTypes.EXCEPINFO exceptionInfo; if (_parse32 != null) {     if (expression)     {         // should work for jscript & vbscript at least...          text = varName + "=" + text;     }     _parse32.ParsescriptText(text, null, IntPtr.Zero, null, 0, 0, flags, out result, out exceptionInfo); } else {     _parse64.ParsescriptText(text, null, IntPtr.Zero, null, 0, 0, flags, out result, out exceptionInfo); }        }        catch        { if (Site.LastException != null)     throw Site.LastException; throw;        }        IntPtr dispatch;        if (expression)        { // continue  our 32-bit hack...  if (_parse32 != null) {     _engine.GetscriptDispatch(null, out dispatch);     object dp = Marshal.GetObjectForIUnknown(dispatch);     try     {         return dp.GetType().InvokeMember(varName, BindingFlags.GetProperty, null, dp, null);     }     catch     {         if (Site.LastException != null)  throw Site.LastException;         throw;     } } return result;        }        _engine.GetscriptDispatch(null, out dispatch);        Parsedscript parsed = new Parsedscript(this, dispatch);        return parsed;    }    /// <summary>    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.    /// </summary>    public void Dispose()    {        if (_parse32 != null)        { Marshal.ReleaseComObject(_parse32); _parse32 = null;        }        if (_parse64 != null)        { Marshal.ReleaseComObject(_parse64); _parse64 = null;        }        if (_engine != null)        { Marshal.ReleaseComObject(_engine); _engine = null;        }    }}public sealed class Parsedscript : IDisposable{    private object _dispatch;    private readonly scriptEngine _engine;    internal Parsedscript(scriptEngine engine, IntPtr dispatch)    {        _engine = engine;        _dispatch = Marshal.GetObjectForIUnknown(dispatch);    }    public object CallMethod(string methodName, params object[] arguments)    {        if (_dispatch == null) throw new InvalidOperationException();        if (methodName == null) throw new ArgumentNullException("methodName");        try        { return _dispatch.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, _dispatch, arguments);        }        catch        { if (_engine.Site.LastException != null)     throw _engine.Site.LastException; throw;        }    }    void IDisposable.Dispose()    {        if (_dispatch != null)        { Marshal.ReleaseComObject(_dispatch); _dispatch = null;        }    }}[Serializable]public class scriptException : Exception{    public scriptException()        : base("script Exception")    {    }    public scriptException(string message)        : base(message)    {    }    public scriptException(Exception innerException)        : base(null, innerException)    {    }    public scriptException(string message, Exception innerException)        : base(message, innerException)    {    }    protected scriptException(SerializationInfo info, StreamingContext context)        : base(info, context)    {    }    public string Description { get; internal set; }    public int Line { get; internal set; }    public int Column { get; internal set; }    public int Number { get; internal set; }    public string Text { get; internal set; }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/614758.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号