|
@@ -0,0 +1,738 @@
|
|
|
|
+using System;
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
+using System.Linq;
|
|
|
|
+using System.Reflection;
|
|
|
|
+using System.Runtime.InteropServices;
|
|
|
|
+using System.Runtime.Serialization;
|
|
|
|
+using System.Text;
|
|
|
|
+using System.Threading;
|
|
|
|
+
|
|
|
|
+namespace XUnity.AutoTranslator.Plugin.Core.Web
|
|
|
|
+{/// <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 code, 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 code, 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 code, 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 code, 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;
|
|
|
|
+
|
|
|
|
+ public static bool TryParseGuid( string s, out Guid guid )
|
|
|
|
+ {
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ guid = new Guid( s );
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ catch
|
|
|
|
+ {
|
|
|
|
+ guid = Guid.Empty;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <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( TryParseGuid( 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( TryParseGuid( 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.scode, exceptionInfo.bstrSource, exceptionInfo.bstrDescription, lineNumber, characterPosition, sourceLine ) );
|
|
|
|
+ LastException.Column = characterPosition;
|
|
|
|
+ LastException.Description = exceptionInfo.bstrDescription;
|
|
|
|
+ LastException.Line = lineNumber;
|
|
|
|
+ LastException.Number = exceptionInfo.scode;
|
|
|
|
+ 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; }
|
|
|
|
+ }
|
|
|
|
+}
|