-
-
- JsEngineMode enumeration:
+MSIE JavaScript Engine requires a installation of Internet Explorer or Edge Legacy on the machine and can work in 5 modes, that are defined in the JsEngineMode enumeration:
* `Auto`. Automatically selects the most modern JavaScript engine from available on the machine.
- * `Classic`. Classic MSIE JavaScript engine (supports ECMAScript 3 with possibility of using the ECMAScript 5 Polyfill and the JSON2 library). Requires Internet Explorer 6 or higher on the machine.
- * `ChakraActiveScript`. ActiveScript version of Chakra JavaScript engine (supports ECMAScript 5). Requires Internet Explorer 9 or higher on the machine.
- * `ChakraIeJsRt`. “IE” JsRT version of Chakra JavaScript engine (supports ECMAScript 5). Requires Internet Explorer 11 or Microsoft Edge on the machine.
- * `ChakraEdgeJsRt`. “Edge” JsRT version of Chakra JavaScript engine (supports ECMAScript 5). Requires Microsoft Edge on the machine.
+ * `Classic`. Classic MSIE JavaScript engine (supports ECMAScript 3 with possibility of using the ECMAScript 5 Polyfill and the JSON2 library). Requires Internet Explorer 6 or higher on the machine. **Not supported in version for .NET Core.**
+ * `ChakraActiveScript`. ActiveScript version of Chakra JavaScript engine (supports ECMAScript 5). Requires Internet Explorer 9 or higher on the machine. **Not supported in version for .NET Core.**
+ * `ChakraIeJsRt`. “IE” JsRT version of Chakra JavaScript engine (supports ECMAScript 5). Requires Internet Explorer 11 or Microsoft Edge Legacy on the machine.
+ * `ChakraEdgeJsRt`. “Edge” JsRT version of Chakra JavaScript engine (supports ECMAScript 5). Requires Microsoft Edge Legacy on the machine.
The supported .NET types are as follows:
@@ -23,94 +23,129 @@ The supported .NET types are as follows:
* `System.String`
## Installation
-This library can be installed through NuGet - [http://nuget.org/packages/MsieJavaScriptEngine](http://nuget.org/packages/MsieJavaScriptEngine).
+This library can be installed through NuGet - [https://www.nuget.org/packages/MsieJavaScriptEngine](https://www.nuget.org/packages/MsieJavaScriptEngine).
## Usage
Consider a simple example of usage of the MSIE JavaScript Engine:
```csharp
+using System;
+
+using MsieJavaScriptEngine;
+using MsieJavaScriptEngine.Helpers;
+
namespace MsieJavaScriptEngine.Example.Console
{
- using System;
-
- using MsieJavaScriptEngine;
- using MsieJavaScriptEngine.Helpers;
-
- class Program
- {
- static void Main(string[] args)
- {
- try
- {
- using (var jsEngine = new MsieJsEngine())
- {
- const string expression = "7 * 8 - 20";
- var result = jsEngine.EvaluateMsieJsEngine class.
Then we evaluate a JavaScript expression by using of the `Evaluate` method and output its result to the console.
-In addition, we provide handling of the following exception types: JsEngineLoadException and JsRuntimeException.
+In addition, we provide handling of the following exception types: JsEngineLoadException, JsScriptException and JsException.
+In the MSIE JavaScript Engine, exceptions have the following hierarchy:
+
+ * JsException
+ * JsEngineException
+ * JsEngineLoadException
+ * JsFatalException
+ * JsScriptException
+ * JsCompilationException
+ * JsRuntimeException
+ * JsInterruptedException
+ * JsUsageException
Also, when you create an instance of the MsieJsEngine class, then you can pass the JavaScript engine settings via the constructor.
Consider in detail properties of the JsEngineSettings class:
| Property name | -Data type | -Default value | -Description | -
|---|---|---|---|
EnableDebugging |
- Boolean |
- false |
- Flag for whether to allow debugging in Visual Studio by adding the `debugger` statement to script code (only works in the `ChakraIeJsRt` and `ChakraEdgeJsRt` modes). | -
EngineMode |
- JsEngineMode enumeration |
- Auto |
- JavaScript engine mode. | -
UseEcmaScript5Polyfill |
- Boolean |
- false |
- Flag for whether to use the ECMAScript 5 Polyfill. | -
UseJson2Library |
- Boolean |
- false |
- Flag for whether to use the JSON2 library | -
| Property name | +Data type | +Default value | +Description | +
AllowReflection |
+ Boolean |
+ false |
+
+ Flag for whether to allow the usage of reflection API in the script code. +This affects |
+
EnableDebugging |
+ Boolean |
+ false |
+ Flag for whether to allow debugging in Visual Studio by adding the debugger statement to script code. |
+
EngineMode |
+ JsEngineMode enumeration |
+ Auto |
+ JavaScript engine mode. | +
MaxStackSize |
+ Int32 |
+ 503 808 or 1 007 616 |
+
+ Maximum stack size in bytes. +Set a |
+
UseEcmaScript5Polyfill |
+ Boolean |
+ false |
+ Flag for whether to use the ECMAScript 5 Polyfill. | +
UseJson2Library |
+ Boolean |
+ false |
+ Flag for whether to use the JSON2 library | +
+ .NETFramework
+ v4.0
+ client
+
+
\ No newline at end of file
diff --git a/build/strong-name-signing.props b/build/strong-name-signing.props
new file mode 100644
index 0000000..543e8a3
--- /dev/null
+++ b/build/strong-name-signing.props
@@ -0,0 +1,7 @@
+
+
+ ../../build/Key.snk
+ true
+ true
+
+
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..512142d
--- /dev/null
+++ b/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "10.0.100",
+ "rollForward": "latestFeature"
+ }
+}
diff --git a/images/MsieJavaScriptEngine_Logo_128x128.png b/images/MsieJavaScriptEngine_Logo_128x128.png
new file mode 100644
index 0000000..d53d471
Binary files /dev/null and b/images/MsieJavaScriptEngine_Logo_128x128.png differ
diff --git a/run-tests.cmd b/run-tests.cmd
new file mode 100644
index 0000000..d9818c7
--- /dev/null
+++ b/run-tests.cmd
@@ -0,0 +1,39 @@
+@echo off
+setlocal
+
+set common_test_project_name=MsieJavaScriptEngine.Test.Common
+set auto_test_project_name=MsieJavaScriptEngine.Test.Auto
+set chakra_edge_jsrt_test_project_name=MsieJavaScriptEngine.Test.ChakraEdgeJsRt
+set chakra_ie_jsrt_test_project_name=MsieJavaScriptEngine.Test.ChakraIeJsRt
+set chakra_activescript_test_project_name=MsieJavaScriptEngine.Test.ChakraActiveScript
+set classic_test_project_name=MsieJavaScriptEngine.Test.Classic
+
+set common-args=%*
+set test_dir_path=test
+set common_test_project_file_path=%test_dir_path%\%common_test_project_name%\%common_test_project_name%.csproj
+set auto_test_project_file_path=%test_dir_path%\%auto_test_project_name%\%auto_test_project_name%.csproj
+set chakra_edge_jsrt_test_project_file_path=%test_dir_path%\%chakra_edge_jsrt_test_project_name%\%chakra_edge_jsrt_test_project_name%.csproj
+set chakra_ie_jsrt_test_project_file_path=%test_dir_path%\%chakra_ie_jsrt_test_project_name%\%chakra_ie_jsrt_test_project_name%.csproj
+set chakra_activescript_test_project_file_path=%test_dir_path%\%chakra_activescript_test_project_name%\%chakra_activescript_test_project_name%.csproj
+set classic_test_project_file_path=%test_dir_path%\%classic_test_project_name%\%classic_test_project_name%.csproj
+
+@echo Run unit tests...
+@echo.
+
+dotnet test %common-args% "%common_test_project_file_path%"
+@echo.
+
+dotnet test %common-args% "%auto_test_project_file_path%"
+@echo.
+
+dotnet test %common-args% "%chakra_edge_jsrt_test_project_file_path%"
+@echo.
+
+dotnet test %common-args% "%chakra_ie_jsrt_test_project_file_path%"
+@echo.
+
+dotnet test %common-args% "%chakra_activescript_test_project_file_path%"
+@echo.
+
+dotnet test %common-args% "%classic_test_project_file_path%"
+@echo.
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/.uglifyjsrc b/src/MsieJavaScriptEngine/.uglifyjsrc
new file mode 100644
index 0000000..8a91584
--- /dev/null
+++ b/src/MsieJavaScriptEngine/.uglifyjsrc
@@ -0,0 +1,11 @@
+{
+ "compress": {
+ "hoist_funs": true,
+ "hoist_vars": true,
+ "passes": 2
+ },
+ "mangle": {},
+ "output": {
+ "comments": "/^!/"
+ }
+}
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptException.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptException.cs
index 315e2fc..a005e9a 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptException.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptException.cs
@@ -1,46 +1,101 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.InteropServices.ComTypes;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.Serialization;
+using System.Security.Permissions;
+namespace MsieJavaScriptEngine.ActiveScript
+{
[Serializable]
- internal sealed class ActiveScriptException : Exception
+ public sealed class ActiveScriptException : Exception
{
///
- /// Gets or sets a error code
+ /// The HRESULT of the error
+ ///
+ private int _errorCode;
+
+ ///
+ /// Type of the script error
+ ///
+ private string _type = string.Empty;
+
+ ///
+ /// Category of error
+ ///
+ private string _category = string.Empty;
+
+ ///
+ /// Description of error
+ ///
+ private string _description = string.Empty;
+
+ ///
+ /// Document name
+ ///
+ private string _documentName = string.Empty;
+
+ ///
+ /// Line number on which the error occurred
+ ///
+ private uint _lineNumber;
+
+ ///
+ /// Column number on which the error occurred
+ ///
+ private int _columnNumber;
+
+ ///
+ /// String representation of the script call stack
+ ///
+ private string _callStack = string.Empty;
+
+ ///
+ /// Source fragment
+ ///
+ private string _sourceFragment = string.Empty;
+
+ ///
+ /// Gets or sets a HRESULT of the error
///
public int ErrorCode
{
- get;
- set;
+ get { return _errorCode; }
+ set { _errorCode = value; }
+ }
+
+ ///
+ /// Gets or sets a type of the script error
+ ///
+ public string Type
+ {
+ get { return _type; }
+ set { _type = value; }
}
///
- /// Gets or sets a WCode
+ /// Gets or sets a category of error
///
- public short ErrorWCode
+ public string Category
{
- get;
- set;
+ get { return _category; }
+ set { _category = value; }
}
///
- /// Gets or sets a application specific source context
+ /// Gets or sets a description of error
///
- public uint SourceContext
+ public string Description
{
- get;
- set;
+ get { return _description; }
+ set { _description = value; }
}
///
- /// Gets or sets a subcategory of error
+ /// Gets or sets a document name
///
- public string Subcategory
+ public string DocumentName
{
- get;
- set;
+ get { return _documentName; }
+ set { _documentName = value; }
}
///
@@ -48,8 +103,8 @@ public string Subcategory
///
public uint LineNumber
{
- get;
- set;
+ get { return _lineNumber; }
+ set { _lineNumber = value; }
}
///
@@ -57,28 +112,32 @@ public uint LineNumber
///
public int ColumnNumber
{
- get;
- set;
+ get { return _columnNumber; }
+ set { _columnNumber = value; }
}
///
- /// Gets or sets a content of the line on which the error occurred
+ /// Gets or sets a string representation of the script call stack
///
- public string SourceError
+ public string CallStack
{
- get;
- set;
+ get { return _callStack; }
+ set { _callStack = value; }
}
-
///
- /// Initializes a new instance of the class
+ /// Gets or sets a source fragment
///
- public ActiveScriptException()
- { }
+ public string SourceFragment
+ {
+ get { return _sourceFragment; }
+ set { _sourceFragment = value; }
+ }
+
///
/// Initializes a new instance of the class
+ /// with a specified error message
///
/// The message
public ActiveScriptException(string message)
@@ -87,14 +146,8 @@ public ActiveScriptException(string message)
///
/// Initializes a new instance of the class
- ///
- /// The inner exception
- public ActiveScriptException(Exception innerException)
- : base(null, innerException)
- { }
-
- ///
- /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
///
/// The message
/// The inner exception
@@ -103,92 +156,55 @@ public ActiveScriptException(string message, Exception innerException)
{ }
///
- /// Initializes a new instance of the class
+ /// Initializes a new instance of the class with serialized data
///
- /// The
- /// that holds the serialized object data about the exception being thrown
- /// The
- /// that contains contextual information about the source or destination
- ///
- /// The parameter is null
- ///
- ///
- /// The class name is null or is zero (0)
- ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
private ActiveScriptException(SerializationInfo info, StreamingContext context)
: base(info, context)
- { }
-
-
- internal static ActiveScriptException Create(IActiveScriptError error)
{
- string message = string.Empty;
- int errorCode = 0;
- short errorWCode = 0;
- uint sourceContext = 0;
- string subcategory = string.Empty;
- string helpLink = string.Empty;
- uint lineNumber = 0;
- int columnNumber = 0;
- string sourceError = string.Empty;
-
- try
- {
- error.GetSourceLineText(out sourceError);
- }
- catch
+ if (info is not null)
{
- // Do nothing
+ _errorCode = info.GetInt32("ErrorCode");
+ _type = info.GetString("Type");
+ _category = info.GetString("Category");
+ _description = info.GetString("Description");
+ _documentName = info.GetString("DocumentName");
+ _lineNumber = info.GetUInt32("LineNumber");
+ _columnNumber = info.GetInt32("ColumnNumber");
+ _callStack = info.GetString("CallStack");
+ _sourceFragment = info.GetString("SourceFragment");
}
+ }
- try
- {
- error.GetSourcePosition(out sourceContext, out lineNumber, out columnNumber);
- ++lineNumber;
- ++columnNumber;
- }
- catch
- {
- // Do nothing
- }
+ #region Exception overrides
- try
- {
- EXCEPINFO excepInfo;
- error.GetExceptionInfo(out excepInfo);
-
- message = excepInfo.bstrDescription;
- subcategory = excepInfo.bstrSource;
- errorCode = excepInfo.scode;
- errorWCode = excepInfo.wCode;
- if (!string.IsNullOrWhiteSpace(excepInfo.bstrHelpFile)
- && excepInfo.dwHelpContext != 0)
- {
- helpLink = string.Format("{0}: {1}", excepInfo.bstrHelpFile, excepInfo.dwHelpContext);
- }
- else if (!string.IsNullOrWhiteSpace(excepInfo.bstrHelpFile))
- {
- helpLink = excepInfo.bstrHelpFile;
- }
- }
- catch
+ ///
+ /// Populates a with the data needed to serialize the target object
+ ///
+ /// The to populate with data
+ /// The destination (see ) for this serialization
+ [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info is null)
{
- // Do nothing
+ throw new ArgumentNullException("info");
}
- var activeScriptException = new ActiveScriptException(message)
- {
- ErrorCode = errorCode,
- ErrorWCode = errorWCode,
- SourceContext = sourceContext,
- Subcategory = subcategory,
- LineNumber = lineNumber,
- ColumnNumber = columnNumber,
- SourceError = sourceError,
- HelpLink = helpLink,
- };
-
- return activeScriptException;
+ base.GetObjectData(info, context);
+ info.AddValue("ErrorCode", _errorCode);
+ info.AddValue("Type", _type);
+ info.AddValue("Category", _category);
+ info.AddValue("Description", _description);
+ info.AddValue("DocumentName", _documentName);
+ info.AddValue("LineNumber", _lineNumber);
+ info.AddValue("ColumnNumber", _columnNumber);
+ info.AddValue("CallStack", _callStack);
+ info.AddValue("SourceFragment", _sourceFragment);
}
+
+ #endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.ScriptSiteBase.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.ScriptSiteBase.cs
new file mode 100644
index 0000000..7e6749f
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.ScriptSiteBase.cs
@@ -0,0 +1,343 @@
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Resources;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ internal abstract partial class ActiveScriptJsEngineBase
+ {
+ ///
+ /// Active Script site
+ ///
+ protected abstract class ScriptSiteBase : IActiveScriptSite,
+ IActiveScriptSiteDebug32, IActiveScriptSiteDebug64,
+ IActiveScriptSiteDebugEx, ICustomQueryInterface
+ {
+ ///
+ /// Instance of the Active Script JS engine
+ ///
+ private readonly ActiveScriptJsEngineBase _jsEngine;
+
+ ///
+ /// Gets or sets a last Active Script exception
+ ///
+ public ActiveScriptException LastException
+ {
+ get { return _jsEngine._lastException; }
+ set { _jsEngine._lastException = value; }
+ }
+
+ ///
+ /// Gets a instance of Active Script wrapper
+ ///
+ public IActiveScriptWrapper ActiveScriptWrapper
+ {
+ get { return _jsEngine._activeScriptWrapper; }
+ }
+
+ ///
+ /// Gets a flag that indicates if the script interruption is requested
+ ///
+ public virtual bool InterruptRequested
+ {
+ get { return _jsEngine._interruptRequested; }
+ }
+
+
+ ///
+ /// Constructs an instance of the Active Script site
+ ///
+ /// Instance of the Active Script JS engine
+ protected ScriptSiteBase(ActiveScriptJsEngineBase jsEngine)
+ {
+ _jsEngine = jsEngine;
+ }
+
+
+ ///
+ /// Processes a Active Script error
+ ///
+ /// Instance of
+ protected virtual void ProcessActiveScriptError(IActiveScriptError error)
+ {
+ var activeScriptException = CreateActiveScriptException(error);
+ LastException = activeScriptException;
+ }
+
+ ///
+ /// Creates a instance of
+ ///
+ /// Instance of
+ /// Instance of
+ protected ActiveScriptException CreateActiveScriptException(IActiveScriptError error)
+ {
+ EXCEPINFO exceptionInfo;
+ error.GetExceptionInfo(out exceptionInfo);
+
+ int hResult = exceptionInfo.scode;
+ string message = string.Empty;
+ string category = string.Empty;
+ string description = string.Empty;
+ string type = string.Empty;
+ string helpLink = string.Empty;
+ string documentName = string.Empty;
+ uint lineNumber = 0;
+ int columnNumber = 0;
+ string callStack = string.Empty;
+ string sourceFragment = string.Empty;
+
+ if (hResult == ComErrorCode.E_ABORT)
+ {
+ category = JsErrorCategory.Interrupted;
+ description = CommonStrings.Runtime_ScriptInterrupted;
+ message = description;
+ }
+ else
+ {
+ int errorNumber = ComHelpers.HResult.GetFacility(hResult) == ComErrorCode.FACILITY_CONTROL ?
+ ComHelpers.HResult.GetCode(hResult) : 0;
+ category = _jsEngine.ShortenErrorCategoryName(exceptionInfo.bstrSource);
+ description = exceptionInfo.bstrDescription;
+ type = _jsEngine.GetErrorTypeByNumber(errorNumber);
+
+ if (!string.IsNullOrWhiteSpace(exceptionInfo.bstrHelpFile))
+ {
+ helpLink = exceptionInfo.dwHelpContext != 0 ?
+ string.Format("{0}: {1}", exceptionInfo.bstrHelpFile, exceptionInfo.dwHelpContext)
+ :
+ exceptionInfo.bstrHelpFile
+ ;
+ }
+
+ uint sourceContext = 0;
+ error.GetSourcePosition(out sourceContext, out lineNumber, out columnNumber);
+ ++lineNumber;
+ ++columnNumber;
+
+ documentName = GetDocumentName(sourceContext);
+
+ if (ActiveScriptJsErrorHelpers.IsCompilationError(errorNumber))
+ {
+ string sourceLine;
+ error.GetSourceLineText(out sourceLine);
+
+ sourceFragment = TextHelpers.GetTextFragmentFromLine(sourceLine, columnNumber);
+ }
+ else
+ {
+ callStack = JsErrorHelpers.StringifyCallStackItems(GetCallStackItems());
+ }
+
+ message = JsErrorHelpers.GenerateScriptErrorMessage(type, description, documentName,
+ (int)lineNumber, columnNumber, sourceFragment, callStack);
+ }
+
+ var activeScriptException = new ActiveScriptException(message)
+ {
+ ErrorCode = hResult,
+ Type = type,
+ Category = category,
+ Description = description,
+ DocumentName = documentName,
+ LineNumber = lineNumber,
+ ColumnNumber = columnNumber,
+ CallStack = callStack,
+ SourceFragment = sourceFragment,
+ HelpLink = helpLink
+ };
+
+ return activeScriptException;
+ }
+
+ ///
+ /// Gets a document name
+ ///
+ /// Application specific source context
+ /// Document name
+ private string GetDocumentName(uint sourceContext)
+ {
+ string documentName = string.Empty;
+ var documentKey = new UIntPtr(sourceContext);
+ DebugDocument document;
+
+ if (_jsEngine._debugDocuments.TryGetValue(documentKey, out document))
+ {
+ document.GetName(DocumentNameType.Title, out documentName);
+ }
+ else if (!_jsEngine._documentNames.TryGetValue(documentKey, out documentName))
+ {
+ documentName = string.Empty;
+ }
+
+ return documentName;
+ }
+
+ ///
+ /// Gets a array of instances
+ ///
+ /// An array of instances
+ protected virtual CallStackItem[] GetCallStackItems()
+ {
+ return [];
+ }
+
+ #region IActiveScriptSite implementation
+
+ public void GetLcid(out int lcid)
+ {
+ lcid = CultureInfo.CurrentCulture.LCID;
+ }
+
+ public void GetItemInfo(string name, ScriptInfoFlags mask, ref IntPtr pUnkItem, ref IntPtr pTypeInfo)
+ {
+ object item = _jsEngine._hostItems[name];
+ if (item is null)
+ {
+ throw new COMException(
+ string.Format(NetFrameworkStrings.Runtime_ItemNotFound, name),
+ ComErrorCode.E_ELEMENT_NOT_FOUND
+ );
+ }
+
+ if (mask.HasFlag(ScriptInfoFlags.IUnknown))
+ {
+ pUnkItem = Marshal.GetIDispatchForObject(item);
+ }
+
+ if (mask.HasFlag(ScriptInfoFlags.ITypeInfo))
+ {
+ pTypeInfo = Marshal.GetITypeInfoForType(item.GetType());
+ }
+ }
+
+ public void GetDocVersionString(out string version)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void OnScriptTerminate(object result, EXCEPINFO exceptionInfo)
+ { }
+
+ public void OnStateChange(ScriptState state)
+ { }
+
+ public void OnScriptError(IActiveScriptError error)
+ {
+ ProcessActiveScriptError(error);
+ }
+
+ public void OnEnterScript()
+ { }
+
+ public void OnLeaveScript()
+ { }
+
+ #endregion
+
+ #region IActiveScriptSiteDebug32 and IActiveScriptSiteDebug64 implementation
+
+ public void GetRootApplicationNode(out IDebugApplicationNode node)
+ {
+ _jsEngine._debugApplicationWrapper.GetRootNode(out node);
+ }
+
+ public void OnScriptErrorDebug(IActiveScriptErrorDebug errorDebug, out bool enterDebugger,
+ out bool callOnScriptErrorWhenContinuing)
+ {
+ var error = errorDebug as IActiveScriptError;
+ if (error is not null)
+ {
+ ProcessActiveScriptError(error);
+ }
+
+ enterDebugger = true;
+ callOnScriptErrorWhenContinuing = true;
+ }
+
+ #region IActiveScriptSiteDebug32 implementation
+
+ public void GetApplication(out IDebugApplication32 application)
+ {
+ application = _jsEngine._debugApplicationWrapper.DebugApplication32;
+ }
+
+ public void GetDocumentContextFromPosition(uint sourceContext, uint offset, uint length,
+ out IDebugDocumentContext documentContext)
+ {
+ documentContext = null;
+ DebugDocument document;
+
+ if (_jsEngine._debugDocuments.TryGetValue(new UIntPtr(sourceContext), out document))
+ {
+ document.GetContextOfPosition(offset, length, out documentContext);
+ }
+ }
+
+ #endregion
+
+ #region IActiveScriptSiteDebug64 implementation
+
+ public void GetApplication(out IDebugApplication64 application)
+ {
+ application = _jsEngine._debugApplicationWrapper.DebugApplication64;
+ }
+
+ public void GetDocumentContextFromPosition(ulong sourceContext, uint offset, uint length,
+ out IDebugDocumentContext documentContext)
+ {
+ documentContext = null;
+ DebugDocument document;
+
+ if (_jsEngine._debugDocuments.TryGetValue(new UIntPtr(sourceContext), out document))
+ {
+ document.GetContextOfPosition(offset, length, out documentContext);
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region IActiveScriptSiteDebugEx implementation
+
+ public void OnCanNotJitScriptErrorDebug(IActiveScriptErrorDebug errorDebug,
+ out bool callOnScriptErrorWhenContinuing)
+ {
+ bool enterDebugger;
+
+ OnScriptErrorDebug(errorDebug, out enterDebugger, out callOnScriptErrorWhenContinuing);
+ }
+
+ #endregion
+
+ #region ICustomQueryInterface implementation
+
+ public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr pInterface)
+ {
+ pInterface = IntPtr.Zero;
+
+ if (iid == typeof(IActiveScriptSiteDebug32).GUID
+ || iid == typeof(IActiveScriptSiteDebug64).GUID
+ || iid == typeof(IActiveScriptSiteDebugEx).GUID)
+ {
+ return _jsEngine._processDebugManagerWrapper is not null ?
+ CustomQueryInterfaceResult.NotHandled : CustomQueryInterfaceResult.Failed;
+ }
+
+ return CustomQueryInterfaceResult.NotHandled;
+ }
+
+ #endregion
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs
index c3006a8..fbb4e44 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs
@@ -1,24 +1,23 @@
-namespace MsieJavaScriptEngine.ActiveScript
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Expando;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Resources;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.ActiveScript
{
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Runtime.InteropServices.Expando;
- using System.Windows.Threading;
-
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
-
- using Constants;
- using Helpers;
- using Resources;
- using Utilities;
-
///
- /// Base class of the ActiveScript JavaScript engine
+ /// Active Script version of JS engine
///
- internal abstract class ActiveScriptJsEngineBase : IInnerJsEngine, IActiveScriptSite
+ internal abstract partial class ActiveScriptJsEngineBase : InnerJsEngineBase
{
///
/// Name of resource, which contains a ECMAScript 5 Polyfill
@@ -31,134 +30,187 @@ internal abstract class ActiveScriptJsEngineBase : IInnerJsEngine, IActiveScript
private const string JSON2_LIBRARY_RESOURCE_NAME = "MsieJavaScriptEngine.Resources.json2.min.js";
///
- /// Pointer to an instance of native JavaScript engine
+ /// Instance of Active Script wrapper
///
- private IntPtr _pActiveScript;
+ protected IActiveScriptWrapper _activeScriptWrapper;
///
- /// Instance of native JavaScript engine
+ /// Instance of script dispatch
///
- private IActiveScript _activeScript;
+ private IExpando _dispatch;
///
- /// Instance of ActiveScriptParseWrapper
+ /// List of host items
///
- private IActiveScriptParseWrapper _activeScriptParse;
+ protected Dictionary _hostItems = new Dictionary();
///
- /// Instance of script dispatch
+ /// Last Active Script exception
///
- private IExpando _dispatch;
+ private ActiveScriptException _lastException;
///
- /// List of host items
+ /// Instance of process debug manager wrapper
///
- private Dictionary _hostItems = new Dictionary();
+ private ProcessDebugManagerWrapper _processDebugManagerWrapper;
///
- /// Host-defined document version string
+ /// Instance of debug application wrapper
///
- private readonly string _documentVersion;
+ private DebugApplicationWrapper _debugApplicationWrapper;
///
- /// Last ActiveScript exception
+ /// The cookie of the debug application
///
- private ActiveScriptException _lastException;
+ private uint _debugApplicationCookie;
///
- /// JavaScript engine mode
+ /// Flag indicating whether debugging started
///
- private readonly JsEngineMode _engineMode;
+ private bool _debuggingStarted;
///
- /// Name of JavaScript engine mode
+ /// List of document names
///
- private readonly string _engineModeName;
+ private Dictionary _documentNames = new Dictionary();
///
- /// for the thread currently executing
+ /// List of debug documents
///
- private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
+ private Dictionary _debugDocuments = new Dictionary();
///
- /// Flag that object is destroyed
+ /// Next source context
///
- private StatedFlag _disposedFlag = new StatedFlag();
+ private uint _nextSourceContext = 1;
+ ///
+ /// Lowest supported version of Internet Explorer
+ ///
+ private readonly string _lowerIeVersion;
///
- /// Constructs an instance of the ActiveScript JavaScript engine
+ /// Prefix of error category name
///
- /// CLSID of JavaScript engine
- /// JavaScript engine mode
- /// Lowest supported version of Internet Explorer
+ private readonly string _errorCategoryNamePrefix;
+
+ ///
+ /// Flag that indicates if the script interruption is requested
+ ///
+ protected bool _interruptRequested;
+
+ ///
+ /// Instance of script dispatcher
+ ///
+ private static ScriptDispatcher _dispatcher;
+
+ ///
+ /// Synchronizer of script dispatcher initialization
+ ///
+ private static readonly Lock _dispatcherSynchronizer = new Lock();
+
+
+ ///
+ /// Constructs an instance of the Active Script engine
+ ///
+ /// JS engine settings
+ /// CLSID of JS engine
/// Version of script language
- /// Flag for whether to use the ECMAScript 5 Polyfill
- /// Flag for whether to use the JSON2 library
- protected ActiveScriptJsEngineBase(string clsid, JsEngineMode engineMode, string lowerIeVersion,
- ScriptLanguageVersion languageVersion, bool useEcmaScript5Polyfill, bool useJson2Library)
+ /// Lowest supported version of Internet Explorer
+ /// Prefix of error category name
+ protected ActiveScriptJsEngineBase(JsEngineSettings settings, string clsid,
+ ScriptLanguageVersion languageVersion, string lowerIeVersion, string errorCategoryNamePrefix)
+ : base(settings)
{
- _engineMode = engineMode;
- _engineModeName = JsEngineModeHelpers.GetModeName(engineMode);
- _pActiveScript = IntPtr.Zero;
+ InitScriptDispatcher(_settings.MaxStackSize);
+
+ _lowerIeVersion = lowerIeVersion;
+ _errorCategoryNamePrefix = errorCategoryNamePrefix;
try
{
- _pActiveScript = ComHelpers.CreateInstanceByClsid(clsid);
- _activeScript = (IActiveScript)Marshal.GetObjectForIUnknown(_pActiveScript);
+ _dispatcher.Invoke(() =>
+ {
+ _activeScriptWrapper = CreateActiveScriptWrapper(clsid, languageVersion);
+
+ if (_settings.EnableDebugging)
+ {
+ StartDebugging();
+ }
+
+ _activeScriptWrapper.SetScriptSite(CreateScriptSite());
+ _activeScriptWrapper.InitNew();
+ _activeScriptWrapper.SetScriptState(ScriptState.Started);
+ LoadPolyfills();
+
+ _dispatch = WrapScriptDispatch(_activeScriptWrapper.GetScriptDispatch());
+ });
}
- catch (Exception e)
+ catch (COMException e)
{
- throw new JsEngineLoadException(
- string.Format(Strings.Runtime_IeJsEngineNotLoaded,
- _engineModeName, lowerIeVersion, e.Message), _engineModeName);
+ throw WrapCOMException(e);
}
+ catch (ActiveScriptException e)
+ {
+ string description = e.Description;
+ string message = JsErrorHelpers.GenerateEngineLoadErrorMessage(description, _engineModeName, true);
- if (languageVersion != ScriptLanguageVersion.None)
+ var wrapperEngineLoadException = new JsEngineLoadException(message, _engineModeName, e)
+ {
+ Description = description
+ };
+
+ throw wrapperEngineLoadException;
+ }
+ catch (InvalidOperationException e)
+ {
+ throw JsErrorHelpers.WrapEngineLoadException(e, _engineModeName);
+ }
+ catch (Exception e)
+ {
+ throw JsErrorHelpers.WrapEngineLoadException(e, _engineModeName, true);
+ }
+ finally
{
- var activeScriptProperty = _activeScript as IActiveScriptProperty;
- if (activeScriptProperty != null)
+ if (_dispatch is null)
{
- object scriptLanguageVersion = (int)languageVersion;
- uint result = activeScriptProperty.SetProperty((uint)ScriptProperty.InvokeVersioning,
- IntPtr.Zero, ref scriptLanguageVersion);
- if (result != (uint)ScriptHResult.Ok)
- {
- throw new JsEngineLoadException(
- string.Format(Strings.Runtime_ActiveScriptLanguageVersionSelectionFailed, languageVersion));
- }
+ Dispose();
}
}
-
- _activeScriptParse = new ActiveScriptParseWrapper(_pActiveScript, _activeScript);
- _activeScriptParse.InitNew();
-
- _activeScript.SetScriptSite(this);
- _activeScript.SetScriptState(ScriptState.Started);
-
- InitScriptDispatch();
- _documentVersion = DateTime.UtcNow.ToString("o");
-
- LoadResources(useEcmaScript5Polyfill, useJson2Library);
}
+
///
- /// Destructs instance of ActiveScript JavaScript engine
+ /// Initializes a script dispatcher
///
- ~ActiveScriptJsEngineBase()
+ /// The maximum stack size, in bytes, to be used by the thread,
+ /// or 0 to use the default maximum stack size specified in the header for the executable.
+ private static void InitScriptDispatcher(int maxStackSize)
{
- Dispose(false);
- }
+ if (_dispatcher is not null)
+ {
+ return;
+ }
+ lock (_dispatcherSynchronizer)
+ {
+ if (_dispatcher is not null)
+ {
+ return;
+ }
+
+ _dispatcher = new ScriptDispatcher(maxStackSize);
+ }
+ }
///
- /// Checks a support of the JavaScript engine on the machine
+ /// Checks a support of the JS engine on the machine
///
- /// CLSID of JavaScript engine
- /// Flag indicating whether this JavaScript engine is supported
+ /// CLSID of JS engine
+ /// Flag indicating whether this JS engine is supported
/// Support synchronizer
- /// Result of check (true - supports; false - does not support)
- protected static bool IsSupported(string clsid, ref bool? isSupported, ref object supportSynchronizer)
+ /// Result of check (true - supports; false - does not support)
+ protected static bool IsSupported(string clsid, ref bool? isSupported, ref Lock supportSynchronizer)
{
if (isSupported.HasValue)
{
@@ -181,7 +233,7 @@ protected static bool IsSupported(string clsid, ref bool? isSupported, ref objec
}
catch (COMException e)
{
- if (e.ErrorCode == ComErrorCode.ClassNotRegistered)
+ if (e.ErrorCode == ComErrorCode.E_CLASS_NOT_REGISTERED)
{
isSupported = false;
}
@@ -204,87 +256,66 @@ protected static bool IsSupported(string clsid, ref bool? isSupported, ref objec
}
///
- /// Makes a mapping of value from the host type to a script type
+ /// Creates a instance of the Active Script wrapper
///
- /// The source value
- /// The mapped value
- private object MapToScriptType(object value)
+ /// CLSID of JS engine
+ /// Version of script language
+ /// Instance of the Active Script wrapper
+ private IActiveScriptWrapper CreateActiveScriptWrapper(string clsid, ScriptLanguageVersion languageVersion)
{
- return TypeMappingHelpers.MapToScriptType(value, _engineMode);
- }
+ IActiveScriptWrapper activeScriptWrapper;
- ///
- /// Makes a mapping of array items from the host type to a script type
- ///
- /// The source array
- /// The mapped array
- private object[] MapToScriptType(object[] args)
- {
- return TypeMappingHelpers.MapToScriptType(args, _engineMode);
- }
+ if (Utils.Is64BitProcess())
+ {
+ activeScriptWrapper = new ActiveScriptWrapper64(clsid, languageVersion, _settings.EnableDebugging);
+ }
+ else
+ {
+ activeScriptWrapper = new ActiveScriptWrapper32(clsid, languageVersion, _settings.EnableDebugging);
+ }
- ///
- /// Makes a mapping of value from the script type to a host type
- ///
- /// The source value
- /// The mapped value
- private object MapToHostType(object value)
- {
- return TypeMappingHelpers.MapToHostType(value);
+ return activeScriptWrapper;
}
///
- /// Makes a mapping of array items from the script type to a host type
+ /// Starts debugging
///
- /// The source array
- /// The mapped array
- private object[] MapToHostType(object[] args)
- {
- return TypeMappingHelpers.MapToHostType(args);
- }
-
- private JsRuntimeException ConvertActiveScriptExceptionToJsRuntimeException(
- ActiveScriptException activeScriptException)
+ private void StartDebugging()
{
- var jsEngineException = new JsRuntimeException(activeScriptException.Message, _engineModeName)
+ if (ProcessDebugManagerWrapper.TryCreate(out _processDebugManagerWrapper))
{
- ErrorCode = activeScriptException.ErrorCode.ToString(CultureInfo.InvariantCulture),
- Category = activeScriptException.Subcategory,
- LineNumber = (int)activeScriptException.LineNumber,
- ColumnNumber = activeScriptException.ColumnNumber,
- SourceFragment = activeScriptException.SourceError,
- Source = activeScriptException.Source,
- HelpLink = activeScriptException.HelpLink
- };
+ _processDebugManagerWrapper.CreateApplication(out _debugApplicationWrapper);
- return jsEngineException;
+ if (_processDebugManagerWrapper.TryAddApplication(_debugApplicationWrapper, out _debugApplicationCookie))
+ {
+ _debuggingStarted = true;
+ }
+ else
+ {
+ _debugApplicationWrapper.Close();
+ _debugApplicationWrapper = null;
+
+ _processDebugManagerWrapper = null;
+ }
+ }
}
///
- /// Initializes a script dispatch
+ /// Creates a instance of the Active Script site
///
- private void InitScriptDispatch()
- {
- IExpando dispatch = null;
- object obj;
-
- _activeScript.GetScriptDispatch(null, out obj);
-
- if (obj != null && obj.GetType().IsCOMObject)
- {
- dispatch = obj as IExpando;
- }
+ /// Instance of the Active Script site
+ protected abstract ScriptSiteBase CreateScriptSite();
- if (dispatch == null)
- {
- throw new InvalidOperationException(Strings.Runtime_ActiveScriptDispatcherNotInitialized);
- }
-
- _dispatch = dispatch;
+ ///
+ /// Initializes a script context
+ ///
+ protected virtual void InitScriptContext()
+ {
+ // Do nothing
}
///
- /// Gets and resets a last exception. Returns null for none.
+ /// Gets and resets a last exception. Returns null for none.
///
private ActiveScriptException GetAndResetLastException()
{
@@ -297,53 +328,39 @@ private ActiveScriptException GetAndResetLastException()
private void ThrowError()
{
ActiveScriptException last = GetAndResetLastException();
- if (last != null)
+ if (last is not null)
{
throw last;
}
}
- private void InvokeScript(Action action)
- {
- try
- {
- _dispatcher.Invoke(DispatcherPriority.Input, action);
- }
- catch (ActiveScriptException e)
- {
- throw ConvertActiveScriptExceptionToJsRuntimeException(e);
- }
- catch (TargetInvocationException e)
- {
- var activeScriptException = e.InnerException as ActiveScriptException;
- if (activeScriptException != null)
- {
- throw ConvertActiveScriptExceptionToJsRuntimeException(activeScriptException);
- }
-
- throw;
- }
- }
+ ///
+ /// Gets a error type by number
+ ///
+ /// Error number
+ /// Error type
+ protected abstract string GetErrorTypeByNumber(int errorNumber);
- private T InvokeScript(Func func)
+ ///
+ /// Loads a JS polyfills
+ ///
+ private void LoadPolyfills()
{
- try
- {
- return (T)_dispatcher.Invoke(DispatcherPriority.Input, func);
- }
- catch (ActiveScriptException e)
+ Assembly assembly = GetType()
+#if !NET40
+ .GetTypeInfo()
+#endif
+ .Assembly
+ ;
+
+ if (_settings.UseEcmaScript5Polyfill)
{
- throw ConvertActiveScriptExceptionToJsRuntimeException(e);
+ InnerExecuteResource(ES5_POLYFILL_RESOURCE_NAME, assembly);
}
- catch (TargetInvocationException e)
- {
- var activeScriptException = e.InnerException as ActiveScriptException;
- if (activeScriptException != null)
- {
- throw ConvertActiveScriptExceptionToJsRuntimeException(activeScriptException);
- }
- throw;
+ if (_settings.UseJson2Library)
+ {
+ InnerExecuteResource(JSON2_LIBRARY_RESOURCE_NAME, assembly);
}
}
@@ -351,16 +368,24 @@ private T InvokeScript(Func func)
/// Executes a script text
///
/// Script text
+ /// Document name
/// Flag that script text needs to run as an expression
/// Result of the execution
- private object InnerExecute(string code, bool isExpression)
+ private object InnerExecute(string code, string documentName, bool isExpression)
{
object result;
+ DebugDocument debugDocument;
+ UIntPtr sourceContext;
+ ScriptTextFlags flags = isExpression ? ScriptTextFlags.IsExpression : ScriptTextFlags.IsVisible;
+
+ if (TryCreateDebugDocument(documentName, code, out sourceContext, out debugDocument))
+ {
+ flags |= ScriptTextFlags.HostManagesSource;
+ }
try
{
- result = _activeScriptParse.ParseScriptText(code, null, null, null, IntPtr.Zero,
- 0, isExpression ? ScriptTextFlags.IsExpression : ScriptTextFlags.IsVisible);
+ result = _activeScriptWrapper.ParseScriptText(code, null, null, null, sourceContext, 0, flags);
}
catch
{
@@ -374,6 +399,50 @@ private object InnerExecute(string code, bool isExpression)
return result;
}
+ ///
+ /// Executes a code from embedded JS resource
+ ///
+ /// The case-sensitive resource name
+ /// The assembly, which contains the embedded resource
+ private void InnerExecuteResource(string resourceName, Assembly assembly)
+ {
+ string code = Utils.GetResourceAsString(resourceName, assembly);
+ InnerExecute(code, resourceName, false);
+ }
+
+ ///
+ /// Try create a debug document
+ ///
+ /// Document name
+ /// Script text
+ /// Application specific source context
+ /// Debug document
+ /// Result of creating a debug document (true - is created; false - is not created)
+ private bool TryCreateDebugDocument(string name, string code, out UIntPtr sourceContext,
+ out DebugDocument document)
+ {
+ bool result;
+ sourceContext = new UIntPtr(_nextSourceContext++);
+ document = null;
+
+ if (_debuggingStarted)
+ {
+ document = new DebugDocument(_activeScriptWrapper, _debugApplicationWrapper, sourceContext,
+ name, code);
+ _debugDocuments[sourceContext] = document;
+
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+
+ _documentNames[sourceContext] = name;
+
+ return result;
+ }
+
///
/// Calls a function
///
@@ -410,7 +479,7 @@ private object InnerGetVariableValue(string variableName)
try
{
variableValue = _dispatch.InvokeMember(variableName, BindingFlags.GetProperty,
- null, _dispatch, new object[0], null,
+ null, _dispatch, [], null,
CultureInfo.InvariantCulture, null);
}
catch
@@ -427,9 +496,9 @@ private object InnerGetVariableValue(string variableName)
///
/// Name of variable
/// Value of variable
- private void InnerSetVariableValue(string variableName, object value)
+ protected void InnerSetVariableValue(string variableName, object value)
{
- object[] args = { value };
+ object[] args = [value];
try
{
@@ -449,272 +518,267 @@ private void InnerSetVariableValue(string variableName, object value)
}
}
- private void EmbedHostItem(string itemName, object value)
+ ///
+ /// Removes a variable
+ ///
+ /// Name of variable
+ protected abstract void InnerRemoveVariable(string variableName);
+
+ private void InnerEmbedHostItem(string itemName, object value)
{
- InvokeScript(() =>
+ object oldValue = null;
+ if (_hostItems.ContainsKey(itemName))
{
- object oldValue = null;
- if (_hostItems.ContainsKey(itemName))
- {
- oldValue = _hostItems[itemName];
- }
- _hostItems[itemName] = value;
+ oldValue = _hostItems[itemName];
+ }
+ _hostItems[itemName] = value;
- try
+ try
+ {
+ _activeScriptWrapper.AddNamedItem(itemName, ScriptItemFlags.IsVisible);
+ }
+ catch
+ {
+ if (oldValue is not null)
{
- _activeScript.AddNamedItem(itemName, ScriptItemFlags.IsVisible | ScriptItemFlags.GlobalMembers);
+ _hostItems[itemName] = oldValue;
}
- catch (Exception)
+ else
{
- if (oldValue != null)
- {
- _hostItems[itemName] = oldValue;
- }
- else
- {
- _hostItems.Remove(itemName);
- }
-
- throw;
+ _hostItems.Remove(itemName);
}
- });
+
+ ThrowError();
+ throw;
+ }
}
///
- /// Loads a resources
+ /// Starts a garbage collection
///
- /// Flag for whether to use the ECMAScript 5 Polyfill
- /// Flag for whether to use the JSON2 library
- private void LoadResources(bool useEcmaScript5Polyfill, bool useJson2Library)
+ /// The type of garbage collection
+ private void InnerCollectGarbage(ScriptGCType type)
{
- Type type = GetType();
+ _activeScriptWrapper.CollectGarbage(type);
+ }
- if (useEcmaScript5Polyfill)
- {
- ExecuteResource(ES5_POLYFILL_RESOURCE_NAME, type);
- }
+ #region Mapping
- if (useJson2Library)
- {
- ExecuteResource(JSON2_LIBRARY_RESOURCE_NAME, type);
- }
+ ///
+ /// Makes a mapping of value from the host type to a script type
+ ///
+ /// The source value
+ /// The mapped value
+ private object MapToScriptType(object value)
+ {
+ return TypeMappingHelpers.MapToScriptType(value, _settings.EngineMode, _settings.AllowReflection);
+ }
+
+ ///
+ /// Makes a mapping of array items from the host type to a script type
+ ///
+ /// The source array
+ /// The mapped array
+ private object[] MapToScriptType(object[] args)
+ {
+ return TypeMappingHelpers.MapToScriptType(args, _settings.EngineMode, _settings.AllowReflection);
}
///
- /// Executes a code from embedded JS-resource
+ /// Makes a mapping of value from the script type to a host type
///
- /// JS-resource name
- /// Type from assembly that containing an embedded resource
- private void ExecuteResource(string resourceName, Type type)
+ /// The source value
+ /// The mapped value
+ private object MapToHostType(object value)
+ {
+ return TypeMappingHelpers.MapToHostType(value);
+ }
+
+ ///
+ /// Makes a mapping of array items from the script type to a host type
+ ///
+ /// The source array
+ /// The mapped array
+ private object[] MapToHostType(object[] args)
+ {
+ return TypeMappingHelpers.MapToHostType(args);
+ }
+
+ private static IExpando WrapScriptDispatch(object dispatch)
{
- if (string.IsNullOrWhiteSpace(resourceName))
+ IExpando wrappedDispatch = null;
+ if (dispatch is not null && dispatch.GetType().IsCOMObject)
{
- throw new ArgumentException(
- string.Format(Strings.Common_ArgumentIsEmpty, "resourceName"), "resourceName");
+ wrappedDispatch = dispatch as IExpando;
}
- if (type == null)
+ if (wrappedDispatch is null)
{
- throw new ArgumentNullException(
- "type", string.Format(Strings.Common_ArgumentIsNull, "type"));
+ throw new InvalidOperationException(
+ NetFrameworkStrings.Engine_ActiveScriptDispatcherNotInitialized);
}
- string code = Utils.GetResourceAsString(resourceName, type);
- Execute(code);
+ return wrappedDispatch;
}
- ///
- /// Destroys object
- ///
- /// Flag, allowing destruction of
- /// managed objects contained in fields of class
- private void Dispose(bool disposing)
+ private JsException WrapActiveScriptException(ActiveScriptException originalException)
{
- _dispatcher.Invoke(DispatcherPriority.Input, (Action)(() =>
- {
- if (_disposedFlag.Set())
- {
- if (_dispatch != null)
- {
- ComHelpers.ReleaseComObject(ref _dispatch, !disposing);
- _dispatch = null;
- }
+ JsException wrapperException;
+ string message = originalException.Message;
+ string category = originalException.Category;
- if (_activeScriptParse != null)
- {
- _activeScriptParse.Dispose();
- _activeScriptParse = null;
- }
+ switch (category)
+ {
+ case JsErrorCategory.Compilation:
+ wrapperException = new JsCompilationException(message, _engineModeName, originalException);
+ break;
- if (_activeScript != null)
+ case JsErrorCategory.Runtime:
+ wrapperException = new JsRuntimeException(message, _engineModeName, originalException)
{
- _activeScript.Close();
- _activeScript = null;
- }
+ CallStack = originalException.CallStack
+ };
+ break;
- ComHelpers.ReleaseAndEmpty(ref _pActiveScript);
+ case JsErrorCategory.Interrupted:
+ wrapperException = new JsInterruptedException(message, _engineModeName, originalException);
+ break;
- if (_hostItems != null)
- {
- _hostItems.Clear();
- _hostItems = null;
- }
+ default:
+ wrapperException = new JsException(message, _engineModeName, originalException);
+ break;
+ }
- _lastException = null;
- }
- }));
- }
+ wrapperException.Description = originalException.Description;
- #region IActiveScriptSite implementation
+ var wrapperScriptException = wrapperException as JsScriptException;
+ if (wrapperScriptException is not null)
+ {
+ wrapperScriptException.Type = originalException.Type;
+ wrapperScriptException.DocumentName = originalException.DocumentName;
+ wrapperScriptException.LineNumber = (int)originalException.LineNumber;
+ wrapperScriptException.ColumnNumber = originalException.ColumnNumber;
+ wrapperScriptException.SourceFragment = originalException.SourceFragment;
+ }
- ///
- /// Retrieves the locale identifier associated with the host's user interface. The scripting
- /// engine uses the identifier to ensure that error strings and other user-interface elements
- /// generated by the engine appear in the appropriate language.
- ///
- /// A variable that receives the locale identifier for user-interface
- /// elements displayed by the scripting engine
- void IActiveScriptSite.GetLcid(out int lcid)
- {
- lcid = CultureInfo.CurrentCulture.LCID;
+ return wrapperException;
}
- ///
- /// Allows the scripting engine to obtain information about an item added with the
- /// IActiveScript.AddNamedItem method
- ///
- /// The name associated with the item, as specified in the
- /// IActiveScript.AddNamedItem method
- /// A bit mask specifying what information about the item should be
- /// returned. The scripting engine should request the minimum amount of information possible
- /// because some of the return parameters (for example, ITypeInfo) can take considerable
- /// time to load or generate
- /// A variable that receives a pointer to the IUnknown interface associated
- /// with the given item. The scripting engine can use the IUnknown.QueryInterface method to
- /// obtain the IDispatch interface for the item. This parameter receives null if mask
- /// does not include the ScriptInfo.IUnknown value. Also, it receives null if there is no
- /// object associated with the item name; this mechanism is used to create a simple class when
- /// the named item was added with the ScriptItem.CodeOnly flag set in the
- /// IActiveScript.AddNamedItem method.
- /// A variable that receives a pointer to the ITypeInfo interface
- /// associated with the item. This parameter receives null if mask does not include the
- /// ScriptInfo.ITypeInfo value, or if type information is not available for this item. If type
- /// information is not available, the object cannot source events, and name binding must be
- /// realized with the IDispatch.GetIDsOfNames method. Note that the ITypeInfo interface
- /// retrieved describes the item's coclass (TKIND_COCLASS) because the object may support
- /// multiple interfaces and event interfaces. If the item supports the IProvideMultipleTypeInfo
- /// interface, the ITypeInfo interface retrieved is the same as the index zero ITypeInfo that
- /// would be obtained using the IProvideMultipleTypeInfo.GetInfoOfIndex method.
- void IActiveScriptSite.GetItemInfo(string name, ScriptInfoFlags mask, ref IntPtr pUnkItem, ref IntPtr pTypeInfo)
+ private JsEngineLoadException WrapCOMException(COMException originalComException)
{
- object item = _hostItems[name];
- if (item == null)
+ string description;
+ string message;
+
+ if (originalComException.ErrorCode == ComErrorCode.E_CLASS_NOT_REGISTERED)
{
- throw new COMException(
- string.Format(Strings.Runtime_ItemNotFound, name), ComErrorCode.ElementNotFound);
+ description = string.Format(CommonStrings.Engine_AssemblyNotRegistered,
+ _settings.EngineMode == JsEngineMode.Classic ? DllName.JScript : DllName.JScript9) +
+ " " +
+ string.Format(CommonStrings.Engine_IeInstallationRequired, _lowerIeVersion)
+ ;
+ message = JsErrorHelpers.GenerateEngineLoadErrorMessage(description, _engineModeName);
}
-
- if (mask.HasFlag(ScriptInfoFlags.IUnknown))
+ else
{
- pUnkItem = Marshal.GetIDispatchForObject(item);
+ description = originalComException.Message;
+ message = JsErrorHelpers.GenerateEngineLoadErrorMessage(description, _engineModeName, true);
}
- if (mask.HasFlag(ScriptInfoFlags.ITypeInfo))
+ var wrapperEngineLoadException = new JsEngineLoadException(message, _engineModeName,
+ originalComException)
{
- pTypeInfo = Marshal.GetITypeInfoForType(item.GetType());
- }
- }
+ Description = description
+ };
- ///
- /// Retrieves a host-defined string that uniquely identifies the current document version. If
- /// the related document has changed outside the scope of Windows Script (as in the case of an
- /// HTML page being edited with Notepad), the scripting engine can save this along with its
- /// persisted state, forcing a recompile the next time the script is loaded.
- ///
- /// The host-defined document version string
- void IActiveScriptSite.GetDocVersionString(out string version)
- {
- version = _documentVersion;
+ return wrapperEngineLoadException;
}
///
- /// Informs the host that the script has completed execution
- ///
- /// A variable that contains the script result, or null if the script
- /// produced no result
- /// Contains exception information generated when the script
- /// terminated, or null if no exception was generated
- void IActiveScriptSite.OnScriptTerminate(object result, EXCEPINFO exceptionInfo)
- { }
-
- ///
- /// Informs the host that the scripting engine has changed states
- ///
- /// Indicates the new script state
- void IActiveScriptSite.OnStateChange(ScriptState scriptState)
- { }
-
- ///
- /// Informs the host that an execution error occurred while the engine was running the script.
+ /// Shortens a name of error category
///
- /// A host can use this interface to obtain information about the
- /// execution error
- void IActiveScriptSite.OnScriptError(IActiveScriptError scriptError)
+ /// Name of error category
+ /// Short name of error category
+ private string ShortenErrorCategoryName(string categoryName)
{
- _lastException = ActiveScriptException.Create(scriptError);
+ return ActiveScriptJsErrorHelpers.ShortenErrorItemName(categoryName, _errorCategoryNamePrefix);
}
- ///
- /// Informs the host that the scripting engine has begun executing the script code
- ///
- void IActiveScriptSite.OnEnterScript()
- { }
-
- ///
- /// Informs the host that the scripting engine has returned from executing script code
- ///
- void IActiveScriptSite.OnLeaveScript()
- { }
-
#endregion
+ #region InnerJsEngineBase overrides
+
#region IInnerJsEngine implementation
- public string Mode
+ public override PrecompiledScript Precompile(string code, string documentName)
{
- get { return _engineModeName; }
+ throw new NotSupportedException();
}
- public object Evaluate(string expression)
+ public override object Evaluate(string expression, string documentName)
{
- object result = InvokeScript(() => InnerExecute(expression, true));
+ object result = _dispatcher.Invoke(() =>
+ {
+ InitScriptContext();
+
+ try
+ {
+ return InnerExecute(expression, documentName, true);
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
+ });
+
result = MapToHostType(result);
return result;
}
- public void Execute(string code)
+ public override void Execute(string code, string documentName)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- InnerExecute(code, false);
+ InitScriptContext();
+
+ try
+ {
+ InnerExecute(code, documentName, false);
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
});
}
- public object CallFunction(string functionName, params object[] args)
+ public override void Execute(PrecompiledScript precompiledScript)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override object CallFunction(string functionName, params object[] args)
{
object[] processedArgs = MapToScriptType(args);
- object result = InvokeScript(() =>
+ object result = _dispatcher.Invoke(() =>
{
+ InitScriptContext();
+
try
{
return InnerCallFunction(functionName, processedArgs);
}
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
catch (MissingMemberException)
{
throw new JsRuntimeException(
- string.Format(Strings.Runtime_FunctionNotExist, functionName));
+ string.Format(CommonStrings.Runtime_FunctionNotExist, functionName),
+ _engineModeName
+ );
}
});
@@ -723,16 +787,22 @@ public object CallFunction(string functionName, params object[] args)
return result;
}
- public bool HasVariable(string variableName)
+ public override bool HasVariable(string variableName)
{
- bool result = InvokeScript(() =>
+ bool result = _dispatcher.Invoke(() =>
{
+ InitScriptContext();
+
bool variableExist;
try
{
object variableValue = InnerGetVariableValue(variableName);
- variableExist = variableValue != null;
+ variableExist = variableValue is not null;
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
}
catch (MissingMemberException)
{
@@ -745,18 +815,26 @@ public bool HasVariable(string variableName)
return result;
}
- public object GetVariableValue(string variableName)
+ public override object GetVariableValue(string variableName)
{
- object result = InvokeScript(() =>
+ object result = _dispatcher.Invoke(() =>
{
+ InitScriptContext();
+
try
{
return InnerGetVariableValue(variableName);
}
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
catch (MissingMemberException)
{
throw new JsRuntimeException(
- string.Format(Strings.Runtime_VariableNotExist, variableName));
+ string.Format(NetFrameworkStrings.Runtime_VariableNotExist, variableName),
+ _engineModeName
+ );
}
});
@@ -765,35 +843,83 @@ public object GetVariableValue(string variableName)
return result;
}
- public void SetVariableValue(string variableName, object value)
+ public override void SetVariableValue(string variableName, object value)
{
object processedValue = MapToScriptType(value);
- InvokeScript(() => InnerSetVariableValue(variableName, processedValue));
+
+ _dispatcher.Invoke(() =>
+ {
+ InitScriptContext();
+
+ try
+ {
+ InnerSetVariableValue(variableName, processedValue);
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
+ });
}
- public void RemoveVariable(string variableName)
+ public override void RemoveVariable(string variableName)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- InnerSetVariableValue(variableName, null);
+ InitScriptContext();
- if (_hostItems.ContainsKey(variableName))
+ try
+ {
+ InnerRemoveVariable(variableName);
+ }
+ catch (ActiveScriptException e)
{
- _hostItems.Remove(variableName);
+ throw WrapActiveScriptException(e);
}
});
}
- public void EmbedHostObject(string itemName, object value)
+ public override void EmbedHostObject(string itemName, object value)
{
object processedValue = MapToScriptType(value);
- EmbedHostItem(itemName, processedValue);
+
+ _dispatcher.Invoke(() =>
+ {
+ InitScriptContext();
+
+ try
+ {
+ InnerEmbedHostItem(itemName, processedValue);
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
+ });
}
- public void EmbedHostType(string itemName, Type type)
+ public override void EmbedHostType(string itemName, Type type)
{
- var typeValue = new HostType(type, _engineMode);
- EmbedHostItem(itemName, typeValue);
+ var typeValue = new HostType(type, _settings.EngineMode, _settings.AllowReflection);
+
+ _dispatcher.Invoke(() =>
+ {
+ InitScriptContext();
+
+ try
+ {
+ InnerEmbedHostItem(itemName, typeValue);
+ }
+ catch (ActiveScriptException e)
+ {
+ throw WrapActiveScriptException(e);
+ }
+ });
+ }
+
+ public override void CollectGarbage()
+ {
+ _dispatcher.Invoke(() => InnerCollectGarbage(ScriptGCType.Exhaustive));
}
#endregion
@@ -803,12 +929,69 @@ public void EmbedHostType(string itemName, Type type)
///
/// Destroys object
///
- public void Dispose()
+ public override void Dispose()
{
- Dispose(true /* disposing */);
- GC.SuppressFinalize(this);
+ if (_disposedFlag.Set())
+ {
+ if (_debuggingStarted && _debugDocuments is not null)
+ {
+ foreach (UIntPtr debugDocumentKey in _debugDocuments.Keys)
+ {
+ var debugDocumentValue = _debugDocuments[debugDocumentKey];
+ debugDocumentValue.Close();
+ }
+
+ _debugDocuments.Clear();
+ _debugDocuments = null;
+ }
+
+ if (_processDebugManagerWrapper is not null)
+ {
+ _processDebugManagerWrapper.RemoveApplication(_debugApplicationCookie);
+
+ if (_debugApplicationWrapper is not null)
+ {
+ _debugApplicationWrapper.Close();
+ _debugApplicationWrapper = null;
+ }
+
+ _processDebugManagerWrapper = null;
+ }
+
+ if (_documentNames is not null)
+ {
+ _documentNames.Clear();
+ _documentNames = null;
+ }
+
+ _dispatcher.Invoke(() =>
+ {
+ if (_dispatch is not null)
+ {
+ Marshal.ReleaseComObject(_dispatch);
+ _dispatch = null;
+ }
+
+ if (_activeScriptWrapper is not null)
+ {
+ _activeScriptWrapper.Dispose();
+ _activeScriptWrapper = null;
+ }
+ });
+
+ if (_hostItems is not null)
+ {
+ _hostItems.Clear();
+ _hostItems = null;
+ }
+
+ _lastException = null;
+ }
}
#endregion
+
+ #endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsErrorHelpers.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsErrorHelpers.cs
new file mode 100644
index 0000000..3cf8b1f
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsErrorHelpers.cs
@@ -0,0 +1,102 @@
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Extensions;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Active Script error helpers
+ ///
+ internal static class ActiveScriptJsErrorHelpers
+ {
+ ///
+ /// Checks whether the specified error number is compilation error
+ ///
+ /// Error number
+ /// Result of check (true - is compilation error; false - is not compilation error)
+ public static bool IsCompilationError(int errorNumber)
+ {
+ bool result = errorNumber >= JScriptSyntaxErrorNumber.SyntaxError
+ && errorNumber <= JScriptSyntaxErrorNumber.ThrowMustBeFollowedByExpressionOnSameSourceLine;
+
+ return result;
+ }
+
+ ///
+ /// Checks whether the specified error number is runtime error
+ ///
+ /// Error number
+ /// Result of check (true - is runtime error; false - is not runtime error)
+ public static bool IsRuntimeError(int errorNumber)
+ { bool result = errorNumber == JScriptRuntimeErrorNumber.OutOfStackSpace
+ || (errorNumber >= JScriptRuntimeErrorNumber.CannotAssignToThisKeyword
+ && errorNumber <= JScriptRuntimeErrorNumber.InvalidReplacerArgument);
+
+ return result;
+ }
+
+ ///
+ /// Gets a error type by number
+ ///
+ /// Error number
+ /// Mapping of error numbers and types
+ /// Error type
+ public static string GetErrorTypeByNumber(int errorNumber, Dictionary runtimeErrorTypeMap)
+ {
+ string errorType = string.Empty;
+
+ if (IsCompilationError(errorNumber))
+ {
+ errorType = JsErrorType.Syntax;
+ }
+ else if (IsRuntimeError(errorNumber))
+ {
+ if (!runtimeErrorTypeMap.TryGetValue(errorNumber, out errorType))
+ {
+ errorType = string.Empty;
+ }
+ }
+
+ return errorType;
+ }
+
+ ///
+ /// Shortens a name of error item
+ ///
+ /// Name of error item
+ /// Prefix
+ /// Short name of error item
+ public static string ShortenErrorItemName(string itemName, string prefix)
+ {
+ if (itemName is null)
+ {
+ throw new ArgumentNullException(nameof(itemName));
+ }
+
+ if (prefix is null)
+ {
+ throw new ArgumentNullException(nameof(prefix));
+ }
+
+ int itemNameLength = itemName.Length;
+ if (itemNameLength == 0 || prefix.Length == 0)
+ {
+ return itemName;
+ }
+
+ string shortItemName = itemName.TrimStart(prefix);
+ int shortItemNameLength = shortItemName.Length;
+
+ if (shortItemNameLength > 0 && shortItemNameLength < itemNameLength)
+ {
+ shortItemName = shortItemName.CapitalizeFirstLetter();
+ }
+
+ return shortItemName;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptParseWrapper.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptParseWrapper.cs
deleted file mode 100644
index b3f7ac6..0000000
--- a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptParseWrapper.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
-
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
-
- using Helpers;
- using Resources;
-
- internal sealed class ActiveScriptParseWrapper : IActiveScriptParseWrapper
- {
- ///
- /// Flag that the current process is a 64-bit process
- ///
- private readonly bool _is64Bit;
-
- ///
- /// Pointer to an instance of 32-bit ActiveScript parser
- ///
- private IntPtr _pActiveScriptParse32 = IntPtr.Zero;
-
- ///
- /// Instance of 32-bit ActiveScript parser
- ///
- private IActiveScriptParse32 _activeScriptParse32;
-
- ///
- /// Pointer to an instance of 64-bit ActiveScript parser
- ///
- private IntPtr _pActiveScriptParse64 = IntPtr.Zero;
-
- ///
- /// Instance of 64-bit ActiveScript parser
- ///
- private IActiveScriptParse64 _activeScriptParse64;
-
- ///
- /// Last COM exception
- ///
- private EXCEPINFO _lastException;
-
- ///
- /// Flag that object is destroyed
- ///
- private StatedFlag _disposedFlag = new StatedFlag();
-
- ///
- /// Gets a last COM exception
- ///
- public EXCEPINFO LastException
- {
- get { return _lastException; }
- }
-
-
- ///
- /// Constructs instance of the class
- ///
- /// Pointer to an instance of native JavaScript engine
- /// Instance of native JavaScript engine.
- /// Must implement IActiveScriptParse32 or IActiveScriptParse64.
- public ActiveScriptParseWrapper(IntPtr pActiveScript, IActiveScript activeScript)
- {
- _is64Bit = Environment.Is64BitProcess;
-
- if (_is64Bit)
- {
- _pActiveScriptParse64 = ComHelpers.QueryInterface(pActiveScript);
- _activeScriptParse64 = activeScript as IActiveScriptParse64;
- }
- else
- {
- _pActiveScriptParse32 = ComHelpers.QueryInterface(pActiveScript);
- _activeScriptParse32 = activeScript as IActiveScriptParse32;
- }
-
- if (_activeScriptParse64 == null && _activeScriptParse32 == null)
- {
- throw new NotSupportedException(Strings.Runtime_InvalidParserImplementationError);
- }
- }
-
- ///
- /// Destructs instance of
- ///
- ~ActiveScriptParseWrapper()
- {
- Dispose(false);
- }
-
-
- ///
- /// Destroys object
- ///
- /// Flag, allowing destruction of
- /// managed objects contained in fields of class
- private void Dispose(bool disposing)
- {
- if (_disposedFlag.Set())
- {
- if (_is64Bit)
- {
- _activeScriptParse64 = null;
- ComHelpers.ReleaseAndEmpty(ref _pActiveScriptParse64);
- }
- else
- {
- _activeScriptParse32 = null;
- ComHelpers.ReleaseAndEmpty(ref _pActiveScriptParse32);
- }
- }
- }
-
- #region IActiveScriptParseWrapper implementation
-
- ///
- /// Initializes the scripting engine
- ///
- public void InitNew() {
- if (_is64Bit)
- {
- _activeScriptParse64.InitNew();
- }
- else
- {
- _activeScriptParse32.InitNew();
- }
- }
-
- ///
- /// Adds a code scriptlet to the script. This method is used in environments where the
- /// persistent state of the script is intertwined with the host document and the host
- /// is responsible for restoring the script, rather than through an IPersist* interface.
- /// The primary examples are HTML scripting languages that allow scriptlets of code
- /// embedded in the HTML document to be attached to intrinsic events (for instance,
- /// ONCLICK="button1.text='Exit'").
- ///
- /// The default name to associate with the scriptlet. If the
- /// scriptlet does not contain naming information (as in the ONCLICK example above),
- /// this name will be used to identify the scriptlet. If this parameter is NULL, the
- /// scripting engine manufactures a unique name, if necessary.
- /// The scriptlet text to add. The interpretation of this string
- /// depends on the scripting language.
- /// The item name associated with this scriptlet. This parameter,
- /// in addition to pstrSubItemName, identifies the object for which the scriptlet is
- /// an event handler.
- /// The name of a subobject of the named item with which this
- /// scriptlet is associated; this name must be found in the named item's type
- /// information. This parameter is NULL if the scriptlet is to be associated with the
- /// named item instead of a subitem. This parameter, in addition to pstrItemName,
- /// identifies the specific object for which the scriptlet is an event handler.
- /// The name of the event for which the scriptlet is an event
- /// handler.
- /// The end-of-scriptlet delimiter. When the pstrCode parameter
- /// is parsed from a stream of text, the host typically uses a delimiter, such as two
- /// single quotation marks (''), to detect the end of the scriptlet. This parameter
- /// specifies the delimiter that the host used, allowing the scripting engine to
- /// provide some conditional primitive preprocessing (for example, replacing a single
- /// quotation mark ['] with two single quotation marks for use as a delimiter).
- /// Exactly how (and if) the scripting engine makes use of this information depends
- /// on the scripting engine. Set this parameter to NULL if the host did not use a
- /// delimiter to mark the end of the scriptlet.
- /// Application-defined value that is used for
- /// debugging purposes
- /// Zero-based value that specifies which line the
- /// parsing will begin at
- /// Flags associated with the scriptlet
- ///
- /// Actual name used to identify the scriptlet. This is to be in
- /// order of preference: a name explicitly specified in the scriptlet text, the
- /// default name provided in pstrDefaultName, or a unique name synthesized by the
- /// scripting engine.
- ///
- public string AddScriptlet(
- string defaultName,
- string code,
- string itemName,
- string subItemName,
- string eventName,
- string delimiter,
- IntPtr sourceContextCookie,
- uint startingLineNumber,
- ScriptTextFlags flags) {
-
- string name;
-
- if (_is64Bit)
- {
- _activeScriptParse64.AddScriptlet(
- defaultName,
- code,
- itemName,
- subItemName,
- eventName,
- delimiter,
- sourceContextCookie,
- startingLineNumber,
- flags,
- out name,
- out _lastException);
- }
- else
- {
- _activeScriptParse32.AddScriptlet(
- defaultName,
- code,
- itemName,
- subItemName,
- eventName,
- delimiter,
- sourceContextCookie,
- startingLineNumber,
- flags,
- out name,
- out _lastException);
- }
-
- return name;
- }
-
- ///
- /// Parses the given code scriptlet, adding declarations into the namespace and
- /// evaluating code as appropriate.
- ///
- /// The scriptlet text to evaluate. The interpretation of this
- /// string depends on the scripting language
- /// The item name that gives the context in which the
- /// scriptlet is to be evaluated. If this parameter is NULL, the code is evaluated
- /// in the scripting engine's global context
- /// The context object. This object is reserved for use in a
- /// debugging environment, where such a context may be provided by the debugger to
- /// represent an active run-time context. If this parameter is NULL, the engine
- /// uses pstrItemName to identify the context.
- /// The end-of-scriptlet delimiter. When pstrCode is parsed
- /// from a stream of text, the host typically uses a delimiter, such as two single
- /// quotation marks (''), to detect the end of the scriptlet. This parameter specifies
- /// the delimiter that the host used, allowing the scripting engine to provide some
- /// conditional primitive preprocessing (for example, replacing a single quotation
- /// mark ['] with two single quotation marks for use as a delimiter). Exactly how
- /// (and if) the scripting engine makes use of this information depends on the
- /// scripting engine. Set this parameter to NULL if the host did not use a delimiter
- /// to mark the end of the scriptlet.
- /// Application-defined value that is used for
- /// debugging purposes
- /// Zero-based value that specifies which line the
- /// parsing will begin at
- /// Flags associated with the scriptlet
- ///
- /// The results of scriptlet processing, or NULL if the caller
- /// expects no result (that is, the SCRIPTTEXT_ISEXPRESSION value is not set).
- ///
- public object ParseScriptText(
- string code,
- string itemName,
- object context,
- string delimiter,
- IntPtr sourceContextCookie,
- uint startingLineNumber,
- ScriptTextFlags flags) {
-
- object result;
-
- if (_is64Bit)
- {
- _activeScriptParse64.ParseScriptText(
- code,
- itemName,
- context,
- delimiter,
- sourceContextCookie,
- startingLineNumber,
- flags,
- out result,
- out _lastException);
- }
- else
- {
- _activeScriptParse32.ParseScriptText(
- code,
- itemName,
- context,
- delimiter,
- sourceContextCookie,
- startingLineNumber,
- flags,
- out result,
- out _lastException);
- }
-
- return result;
- }
-
- #endregion
-
- #region IDisposable implementation
-
- ///
- /// Destroys object
- ///
- public void Dispose()
- {
- Dispose(true /* disposing */);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper32.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper32.cs
new file mode 100644
index 0000000..9239d76
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper32.cs
@@ -0,0 +1,179 @@
+#if NETFRAMEWORK
+using System;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// 32-bit Active Script wrapper
+ ///
+ internal sealed class ActiveScriptWrapper32 : ActiveScriptWrapperBase
+ {
+ ///
+ /// Pointer to an instance of 32-bit Active Script parser
+ ///
+ private IntPtr _pActiveScriptParse32;
+
+ ///
+ /// Pointer to an instance of 32-bit Active Script debugger
+ ///
+ private IntPtr _pActiveScriptDebug32;
+
+ ///
+ /// Pointer to an instance of 32-bit debug stack frame sniffer
+ ///
+ private IntPtr _pDebugStackFrameSniffer32;
+
+ ///
+ /// Instance of 32-bit Active Script parser
+ ///
+ private IActiveScriptParse32 _activeScriptParse32;
+
+ ///
+ /// Instance of 32-bit Active Script debugger
+ ///
+ private IActiveScriptDebug32 _activeScriptDebug32;
+
+ ///
+ /// Instance of 32-bit debug stack frame sniffer
+ ///
+ private IDebugStackFrameSnifferEx32 _debugStackFrameSniffer32;
+
+
+ ///
+ /// Constructs an instance of the 32-bit Active Script wrapper
+ ///
+ /// CLSID of JS engine
+ /// Version of script language
+ /// Flag for whether to enable script debugging features
+ public ActiveScriptWrapper32(string clsid, ScriptLanguageVersion languageVersion, bool enableDebugging)
+ : base(clsid, languageVersion, enableDebugging)
+ {
+ _pActiveScriptParse32 = ComHelpers.QueryInterface(_pActiveScript);
+ _activeScriptParse32 = (IActiveScriptParse32)_activeScript;
+
+ if (_enableDebugging)
+ {
+ _pActiveScriptDebug32 = ComHelpers.QueryInterface(_pActiveScript);
+ _activeScriptDebug32 = (IActiveScriptDebug32)_activeScript;
+
+ _pDebugStackFrameSniffer32 = ComHelpers.QueryInterfaceNoThrow(
+ _pActiveScript);
+ _debugStackFrameSniffer32 = _activeScript as IDebugStackFrameSnifferEx32;
+ }
+ }
+
+ ///
+ /// Destructs an instance of the 32-bit Active Script wrapper
+ ///
+ ~ActiveScriptWrapper32()
+ {
+ Dispose(false);
+ }
+
+
+ #region ActiveScriptWrapperBase overrides
+
+ protected override uint InnerEnumCodeContextsOfPosition(UIntPtr sourceContext, uint offset,
+ uint length, out IEnumDebugCodeContexts enumContexts)
+ {
+ uint result = _activeScriptDebug32.EnumCodeContextsOfPosition(sourceContext.ToUInt32(),
+ offset, length, out enumContexts);
+
+ return result;
+ }
+
+ #region IActiveScriptWrapper implementation
+
+ public override void InitNew()
+ {
+ _activeScriptParse32.InitNew();
+ }
+
+ public override object ParseScriptText(string code, string itemName, object context,
+ string delimiter, UIntPtr sourceContextCookie, uint startingLineNumber, ScriptTextFlags flags)
+ {
+ object result;
+ EXCEPINFO exceptionInfo;
+
+ _activeScriptParse32.ParseScriptText(
+ code,
+ itemName,
+ context,
+ delimiter,
+ sourceContextCookie,
+ startingLineNumber,
+ flags,
+ out result,
+ out exceptionInfo);
+
+ return result;
+ }
+
+ public override void EnumStackFrames(out IEnumDebugStackFrames enumFrames)
+ {
+ if (_debugStackFrameSniffer32 is not null)
+ {
+ _debugStackFrameSniffer32.EnumStackFrames(out enumFrames);
+ }
+ else
+ {
+ enumFrames = new NullEnumDebugStackFrames();
+ }
+ }
+
+ #endregion
+
+ #region IDisposable implementation
+
+ ///
+ /// Destroys object
+ ///
+ public override void Dispose()
+ {
+ Dispose(true /* disposing */);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Destroys object
+ ///
+ /// Flag, allowing destruction of managed objects contained in fields of class
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_disposedFlag.Set())
+ {
+ _debugStackFrameSniffer32 = null;
+ _activeScriptDebug32 = null;
+ _activeScriptParse32 = null;
+
+ DisposeUnmanagedResources();
+ base.Dispose(true);
+ }
+ }
+ else
+ {
+ DisposeUnmanagedResources();
+ base.Dispose(false);
+ }
+ }
+
+ private void DisposeUnmanagedResources()
+ {
+ ComHelpers.ReleaseAndEmpty(ref _pDebugStackFrameSniffer32);
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScriptDebug32);
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScriptParse32);
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper64.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper64.cs
new file mode 100644
index 0000000..bff66b4
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapper64.cs
@@ -0,0 +1,179 @@
+#if NETFRAMEWORK
+using System;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// 64-bit Active Script wrapper
+ ///
+ internal sealed class ActiveScriptWrapper64 : ActiveScriptWrapperBase
+ {
+ ///
+ /// Pointer to an instance of 64-bit Active Script parser
+ ///
+ private IntPtr _pActiveScriptParse64;
+
+ ///
+ /// Pointer to an instance of 64-bit Active Script debugger
+ ///
+ private IntPtr _pActiveScriptDebug64;
+
+ ///
+ /// Pointer to an instance of 64-bit debug stack frame sniffer
+ ///
+ private IntPtr _pDebugStackFrameSniffer64;
+
+ ///
+ /// Instance of 64-bit Active Script parser
+ ///
+ private IActiveScriptParse64 _activeScriptParse64;
+
+ ///
+ /// Instance of 64-bit Active Script debugger
+ ///
+ private IActiveScriptDebug64 _activeScriptDebug64;
+
+ ///
+ /// Instance of 64-bit debug stack frame sniffer
+ ///
+ private IDebugStackFrameSnifferEx64 _debugStackFrameSniffer64;
+
+
+ ///
+ /// Constructs an instance of the 64-bit Active Script wrapper
+ ///
+ /// CLSID of JS engine
+ /// Version of script language
+ /// Flag for whether to enable script debugging features
+ public ActiveScriptWrapper64(string clsid, ScriptLanguageVersion languageVersion, bool enableDebugging)
+ : base(clsid, languageVersion, enableDebugging)
+ {
+ _pActiveScriptParse64 = ComHelpers.QueryInterface(_pActiveScript);
+ _activeScriptParse64 = (IActiveScriptParse64)_activeScript;
+
+ if (_enableDebugging)
+ {
+ _pActiveScriptDebug64 = ComHelpers.QueryInterface(_pActiveScript);
+ _activeScriptDebug64 = (IActiveScriptDebug64)_activeScript;
+
+ _pDebugStackFrameSniffer64 = ComHelpers.QueryInterfaceNoThrow(
+ _pActiveScript);
+ _debugStackFrameSniffer64 = _activeScript as IDebugStackFrameSnifferEx64;
+ }
+ }
+
+ ///
+ /// Destructs an instance of the 64-bit Active Script wrapper
+ ///
+ ~ActiveScriptWrapper64()
+ {
+ Dispose(false);
+ }
+
+
+ #region ActiveScriptWrapperBase overrides
+
+ protected override uint InnerEnumCodeContextsOfPosition(UIntPtr sourceContext, uint offset,
+ uint length, out IEnumDebugCodeContexts enumContexts)
+ {
+ uint result = _activeScriptDebug64.EnumCodeContextsOfPosition(sourceContext.ToUInt64(),
+ offset, length, out enumContexts);
+
+ return result;
+ }
+
+ #region IActiveScriptWrapper implementation
+
+ public override void InitNew()
+ {
+ _activeScriptParse64.InitNew();
+ }
+
+ public override object ParseScriptText(string code, string itemName, object context,
+ string delimiter, UIntPtr sourceContextCookie, uint startingLineNumber, ScriptTextFlags flags)
+ {
+ object result;
+ EXCEPINFO exceptionInfo;
+
+ _activeScriptParse64.ParseScriptText(
+ code,
+ itemName,
+ context,
+ delimiter,
+ sourceContextCookie,
+ startingLineNumber,
+ flags,
+ out result,
+ out exceptionInfo);
+
+ return result;
+ }
+
+ public override void EnumStackFrames(out IEnumDebugStackFrames enumFrames)
+ {
+ if (_debugStackFrameSniffer64 is not null)
+ {
+ _debugStackFrameSniffer64.EnumStackFrames(out enumFrames);
+ }
+ else
+ {
+ enumFrames = new NullEnumDebugStackFrames();
+ }
+ }
+
+ #endregion
+
+ #region IDisposable implementation
+
+ ///
+ /// Destroys object
+ ///
+ public override void Dispose()
+ {
+ Dispose(true /* disposing */);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Destroys object
+ ///
+ /// Flag, allowing destruction of managed objects contained in fields of class
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_disposedFlag.Set())
+ {
+ _debugStackFrameSniffer64 = null;
+ _activeScriptDebug64 = null;
+ _activeScriptParse64 = null;
+
+ DisposeUnmanagedResources();
+ base.Dispose(true);
+ }
+ }
+ else
+ {
+ DisposeUnmanagedResources();
+ base.Dispose(false);
+ }
+ }
+
+ private void DisposeUnmanagedResources()
+ {
+ ComHelpers.ReleaseAndEmpty(ref _pDebugStackFrameSniffer64);
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScriptDebug64);
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScriptParse64);
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapperBase.cs b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapperBase.cs
new file mode 100644
index 0000000..dc9bb3f
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ActiveScriptWrapperBase.cs
@@ -0,0 +1,265 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Resources;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Base class of the Active Script wrapper
+ ///
+ internal abstract class ActiveScriptWrapperBase : IActiveScriptWrapper
+ {
+ ///
+ /// Flag for whether to enable script debugging features
+ ///
+ protected readonly bool _enableDebugging;
+
+ ///
+ /// Pointer to an instance of Active Script engine
+ ///
+ protected IntPtr _pActiveScript;
+
+ ///
+ /// Pointer to an instance of Active Script garbage collector
+ ///
+ private IntPtr _pActiveScriptGarbageCollector;
+
+ ///
+ /// Instance of Active Script engine
+ ///
+ protected IActiveScript _activeScript;
+
+ ///
+ /// Instance of Active Script garbage collector
+ ///
+ private IActiveScriptGarbageCollector _activeScriptGarbageCollector;
+
+ ///
+ /// Flag that object is destroyed
+ ///
+ protected StatedFlag _disposedFlag = new StatedFlag();
+
+
+ ///
+ /// Constructs an instance of the Active Script wrapper
+ ///
+ /// CLSID of JS engine
+ /// Version of script language
+ /// Flag for whether to enable script debugging features
+ protected ActiveScriptWrapperBase(string clsid, ScriptLanguageVersion languageVersion,
+ bool enableDebugging)
+ {
+ _enableDebugging = enableDebugging;
+
+ _pActiveScript = ComHelpers.CreateInstanceByClsid(clsid);
+ _activeScript = (IActiveScript)Marshal.GetObjectForIUnknown(_pActiveScript);
+
+ _pActiveScriptGarbageCollector = ComHelpers.QueryInterfaceNoThrow(
+ _pActiveScript);
+ _activeScriptGarbageCollector = _activeScript as IActiveScriptGarbageCollector;
+
+ if (languageVersion != ScriptLanguageVersion.None)
+ {
+ var activeScriptProperty = _activeScript as IActiveScriptProperty;
+ if (activeScriptProperty is not null)
+ {
+ object scriptLanguageVersion = (int)languageVersion;
+ uint result = activeScriptProperty.SetProperty((uint)ScriptProperty.InvokeVersioning,
+ IntPtr.Zero, ref scriptLanguageVersion);
+ if (result != ComErrorCode.S_OK)
+ {
+ throw new InvalidOperationException(
+ string.Format(NetFrameworkStrings.Engine_ActiveScriptLanguageVersionSelectionFailed,
+ languageVersion)
+ );
+ }
+ }
+ }
+ }
+
+
+ protected abstract uint InnerEnumCodeContextsOfPosition(UIntPtr sourceContext, uint offset,
+ uint length, out IEnumDebugCodeContexts enumContexts);
+
+ #region IActiveScriptWrapper implementation
+
+ ///
+ /// Informs the scripting engine of the interface site
+ /// provided by the host. Call this method before any other
+ /// interface methods is used.
+ ///
+ /// The host-supplied script site to be associated with this instance
+ /// of the scripting engine. The site must be uniquely assigned to this scripting engine
+ /// instance; it cannot be shared with other scripting engines.
+ public void SetScriptSite(IActiveScriptSite site)
+ {
+ _activeScript.SetScriptSite(site);
+ }
+
+ ///
+ /// Puts the scripting engine into the given state. This method can be called from non-base
+ /// threads without resulting in a non-base callout to host objects or to the
+ /// interface.
+ ///
+ /// Sets the scripting engine to the given state
+ public void SetScriptState(ScriptState state)
+ {
+ _activeScript.SetScriptState(state);
+ }
+
+ ///
+ /// Adds the name of a root-level item to the scripting engine's name space. A root-level item
+ /// is an object with properties and methods, an event source, or all three.
+ ///
+ /// The name of the item as viewed from the script. The name must be unique
+ /// and persistable
+ /// Flags associated with an item
+ public void AddNamedItem(string name, ScriptItemFlags flags)
+ {
+ _activeScript.AddNamedItem(name, flags);
+ }
+
+ ///
+ /// Gets a script dispatch
+ ///
+ /// The object associated with the script's global methods and properties
+ public object GetScriptDispatch()
+ {
+ object dispatch;
+ _activeScript.GetScriptDispatch(null, out dispatch);
+
+ return dispatch;
+ }
+
+ ///
+ /// Initializes the scripting engine
+ ///
+ public abstract void InitNew();
+
+ ///
+ /// Parses the given code scriptlet, adding declarations into the namespace and
+ /// evaluating code as appropriate
+ ///
+ /// The scriptlet text to evaluate. The interpretation of this
+ /// string depends on the scripting language
+ /// The item name that gives the context in which the
+ /// scriptlet is to be evaluated. If this parameter is null , the code is evaluated
+ /// in the scripting engine's global context
+ /// The context object. This object is reserved for use in a
+ /// debugging environment, where such a context may be provided by the debugger to
+ /// represent an active run-time context. If this parameter is null , the engine
+ /// uses to identify the context.
+ /// The end-of-scriptlet delimiter. When
+ /// is parsed from a stream of text, the host typically uses a delimiter, such as two
+ /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// specifies the delimiter that the host used, allowing the scripting engine to provide
+ /// some conditional primitive preprocessing (for example, replacing a single quotation
+ /// mark ['] with two single quotation marks for use as a delimiter). Exactly how
+ /// (and if) the scripting engine makes use of this information depends on the
+ /// scripting engine. Set this parameter to null if the host did not use a delimiter
+ /// to mark the end of the scriptlet.
+ /// Application-defined value that is used for
+ /// debugging purposes
+ /// Zero-based value that specifies which line the
+ /// parsing will begin at
+ /// Flags associated with the scriptlet
+ /// The results of scriptlet processing, or null if the caller expects no
+ /// result (that is, the value is not set)
+ public abstract object ParseScriptText(string code, string itemName, object context, string delimiter,
+ UIntPtr sourceContextCookie, uint startingLineNumber, ScriptTextFlags flags);
+
+ ///
+ /// Used by a smart host to delegate the method
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script text
+ /// Number of characters in this context
+ /// An enumerator of the code contexts in the specified range
+ public void EnumCodeContextsOfPosition(UIntPtr sourceContext, uint offset, uint length,
+ out IEnumDebugCodeContexts enumContexts)
+ {
+ if (_enableDebugging)
+ {
+ uint result = InnerEnumCodeContextsOfPosition(sourceContext, offset, length, out enumContexts);
+ ComHelpers.HResult.Check(result);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ public abstract void EnumStackFrames(out IEnumDebugStackFrames enumFrames);
+
+ ///
+ /// Interrupts the execution of a running script thread (an event sink, an immediate execution,
+ /// or a macro invocation). This method can be used to terminate a script that is stuck (for
+ /// example, in an infinite loop). It can be called from non-base threads without resulting in
+ /// a non-base callout to host objects or to the method.
+ ///
+ /// Identifier of the thread to interrupt
+ /// The error information that should be reported to the aborted script
+ /// Option flags associated with the interruption
+ public void InterruptScriptThread(uint scriptThreadId, ref EXCEPINFO exceptionInfo,
+ ScriptInterruptFlags flags)
+ {
+ _activeScript.InterruptScriptThread(scriptThreadId, ref exceptionInfo, flags);
+ }
+
+ ///
+ /// The Active Script host calls this method to start garbage collection
+ ///
+ /// The type of garbage collection
+ public void CollectGarbage(ScriptGCType type)
+ {
+ if (_activeScriptGarbageCollector is not null)
+ {
+ _activeScriptGarbageCollector.CollectGarbage(type);
+ }
+ }
+
+ #endregion
+
+ #region IDisposable implementation
+
+ ///
+ /// Destroys object
+ ///
+ public abstract void Dispose();
+
+ ///
+ /// Destroys object
+ ///
+ /// Flag, allowing destruction of managed objects contained in fields of class
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _activeScriptGarbageCollector = null;
+
+ if (_activeScript is not null)
+ {
+ _activeScript.Close();
+ Marshal.FinalReleaseComObject(_activeScript);
+ _activeScript = null;
+ }
+ }
+
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScriptGarbageCollector);
+ ComHelpers.ReleaseAndEmpty(ref _pActiveScript);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.ScriptSite.cs b/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.ScriptSite.cs
new file mode 100644
index 0000000..7a4fcb3
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.ScriptSite.cs
@@ -0,0 +1,58 @@
+#if NETFRAMEWORK
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Resources;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ internal sealed partial class ChakraActiveScriptJsEngine
+ {
+ ///
+ /// Chakra Active Script site
+ ///
+ private sealed class ScriptSite : ScriptSiteBase, IActiveScriptSiteInterruptPoll
+ {
+ ///
+ /// Constructs an instance of the Chakra Active Script site
+ ///
+ /// Instance of the Active Script JS engine
+ public ScriptSite(ChakraActiveScriptJsEngine jsEngine)
+ : base(jsEngine)
+ { }
+
+
+ #region IActiveScriptSiteInterruptPoll implementation
+
+ public uint QueryContinue()
+ {
+ int hResult;
+
+ if (InterruptRequested)
+ {
+ hResult = ComErrorCode.E_ABORT;
+ string category = JsErrorCategory.Interrupted;
+ string description = CommonStrings.Runtime_ScriptInterrupted;
+ string message = description;
+
+ var activeScriptException = new ActiveScriptException(message)
+ {
+ ErrorCode = hResult,
+ Category = category,
+ Description = description
+ };
+
+ LastException = activeScriptException;
+ }
+ else
+ {
+ hResult = ComErrorCode.S_OK;
+ }
+
+ return NumericHelpers.SignedAsUnsigned(hResult);
+ }
+
+ #endregion
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.cs b/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.cs
index 54a2829..1240edb 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.cs
@@ -1,43 +1,140 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using Constants;
+#if NETFRAMEWORK
+using System.Collections.Generic;
+
+using MsieJavaScriptEngine.Constants;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// ActiveScript version of Chakra JavaScript engine
+ /// Active Script version of Chakra JS engine
///
- internal sealed class ChakraActiveScriptJsEngine : ActiveScriptJsEngineBase
+ internal sealed partial class ChakraActiveScriptJsEngine : ActiveScriptJsEngineBase
{
- private const string CHAKRA_CLSID = "{16d51579-a30b-4c8b-a276-0ff4dc41e755}";
-
///
- /// Flag indicating whether this JavaScript engine is supported
+ /// Flag indicating whether this JS engine is supported
///
private static bool? _isSupported;
///
/// Support synchronizer
///
- private static object _supportSynchronizer = new object();
+ private static Lock _supportSynchronizer = new Lock();
+
+ ///
+ /// Mapping of error numbers and types
+ ///
+ private static readonly Dictionary _runtimeErrorTypeMap = new Dictionary
+ {
+ { JScriptRuntimeErrorNumber.OutOfStackSpace, JsErrorType.Common },
+ { JScriptRuntimeErrorNumber.CannotAssignToThisKeyword, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.NumberExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.FunctionExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.CannotAssignToFunctionResult, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.StringExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.DateObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.IllegalAssignment, string.Empty },
+ { JScriptRuntimeErrorNumber.UndefinedIdentifier, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.BooleanExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ObjectMemberExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.VbArrayExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.JavaScriptObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.EnumeratorObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.RegularExpressionObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.SyntaxErrorInRegularExpression, JsErrorType.Syntax },
+ { JScriptRuntimeErrorNumber.UnexpectedQuantifier, JsErrorType.Syntax },
+ { JScriptRuntimeErrorNumber.ExpectedRightSquareBracketInRegularExpression, JsErrorType.Syntax },
+ { JScriptRuntimeErrorNumber.ExpectedRightParenthesisInRegularExpression, JsErrorType.Syntax },
+ { JScriptRuntimeErrorNumber.InvalidRangeInCharacterSet, JsErrorType.Syntax },
+ { JScriptRuntimeErrorNumber.ExceptionThrownAndNotCaught, string.Empty },
+ { JScriptRuntimeErrorNumber.FunctionDoesNotHaveValidPrototypeObject, string.Empty },
+ { JScriptRuntimeErrorNumber.UriToBeEncodedContainsInvalidCharacter, JsErrorType.URI },
+ { JScriptRuntimeErrorNumber.UriToBeDecodedIsNotValidEncoding, JsErrorType.URI },
+ { JScriptRuntimeErrorNumber.NumberOfFractionalDigitsIsOutOfRange, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.PrecisionOutOfRange, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.ArrayOrArgumentsObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ArrayLengthMustBeFinitePositiveInteger, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.ArrayLengthMustBeAssignedFinitePositiveNumber, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.CircularReferenceInValueArgumentNotSupported, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.InvalidReplacerArgument, string.Empty }
+ };
///
- /// Constructs instance of the Chakra ActiveScript JavaScript engine
+ /// Constructs an instance of the Chakra Active Script engine
///
- public ChakraActiveScriptJsEngine()
- : base(CHAKRA_CLSID, JsEngineMode.ChakraActiveScript, "9",
- ScriptLanguageVersion.EcmaScript5, false, false)
+ /// JS engine settings
+ public ChakraActiveScriptJsEngine(JsEngineSettings settings)
+ : base(settings, ClassId.Chakra, ScriptLanguageVersion.EcmaScript5, "9", "JavaScript ")
{ }
///
- /// Checks a support of the Chakra ActiveScript JavaScript engine on the machine
+ /// Checks a support of the Chakra Active Script engine on the machine
///
- /// Result of check (true - supports; false - does not support)
+ /// Result of check (true - supports; false - does not support)
public static bool IsSupported()
{
- bool isSupported = IsSupported(CHAKRA_CLSID, ref _isSupported, ref _supportSynchronizer);
+ bool isSupported = IsSupported(ClassId.Chakra, ref _isSupported, ref _supportSynchronizer);
return isSupported;
}
+
+ #region ActiveScriptJsEngineBase overrides
+
+ ///
+ /// Creates a instance of the Active Script site
+ ///
+ /// Instance of the Active Script site
+ protected override ScriptSiteBase CreateScriptSite()
+ {
+ return new ScriptSite(this);
+ }
+
+ ///
+ /// Initializes a script context
+ ///
+ protected override void InitScriptContext()
+ {
+ _interruptRequested = false;
+ }
+
+ ///
+ /// Gets a error type by number
+ ///
+ /// Error number
+ /// Error type
+ protected override string GetErrorTypeByNumber(int errorNumber)
+ {
+ return ActiveScriptJsErrorHelpers.GetErrorTypeByNumber(errorNumber, _runtimeErrorTypeMap);
+ }
+
+ protected override void InnerRemoveVariable(string variableName)
+ {
+ InnerSetVariableValue(variableName, null);
+
+ if (_hostItems.ContainsKey(variableName))
+ {
+ _hostItems.Remove(variableName);
+ }
+ }
+
+ #region IInnerJsEngine implementation
+
+ public override bool SupportsScriptPrecompilation
+ {
+ get { return false; }
+ }
+
+
+ public override void Interrupt()
+ {
+ _interruptRequested = true;
+ }
+
+ #endregion
+
+ #endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.ScriptSite.cs b/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.ScriptSite.cs
new file mode 100644
index 0000000..0c5143f
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.ScriptSite.cs
@@ -0,0 +1,141 @@
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ internal sealed partial class ClassicActiveScriptJsEngine
+ {
+ ///
+ /// Classic Active Script site
+ ///
+ private sealed class ScriptSite : ScriptSiteBase
+ {
+ ///
+ /// Constructs an instance of the Classic Active Script site
+ ///
+ /// Instance of the Active Script JS engine
+ public ScriptSite(ActiveScriptJsEngineBase jsEngine)
+ : base(jsEngine)
+ { }
+
+
+ #region ScriptSiteBase overrides
+
+ ///
+ /// Gets a flag that indicates if the script interruption is requested
+ ///
+ public override bool InterruptRequested
+ {
+ get { return false; }
+ }
+
+
+ ///
+ /// Processes a Active Script error
+ ///
+ /// Instance of
+ protected override void ProcessActiveScriptError(IActiveScriptError error)
+ {
+ var activeScriptException = CreateActiveScriptException(error);
+ if (activeScriptException.ErrorCode == ComErrorCode.E_ABORT)
+ {
+ // Script execution was interrupted explicitly. At this point the script
+ // engine might be in an odd state; the following call seems to get it back
+ // to normal.
+ ActiveScriptWrapper.SetScriptState(ScriptState.Started);
+ }
+
+ LastException = activeScriptException;
+ }
+
+ ///
+ /// Gets a array of instances
+ ///
+ /// An array of instances
+ protected override CallStackItem[] GetCallStackItems()
+ {
+ var callStackItems = new List();
+ IEnumDebugStackFrames enumFrames;
+ ActiveScriptWrapper.EnumStackFrames(out enumFrames);
+
+ while (true)
+ {
+ DebugStackFrameDescriptor descriptor;
+ uint countFetched;
+ enumFrames.Next(1, out descriptor, out countFetched);
+ if (countFetched < 1)
+ {
+ break;
+ }
+
+ try
+ {
+ IDebugStackFrame stackFrame = descriptor.Frame;
+
+ string functionName;
+ stackFrame.GetDescriptionString(true, out functionName);
+
+ string shortFunctionName = ActiveScriptJsErrorHelpers.ShortenErrorItemName(
+ functionName, "JScript ");
+
+ IDebugCodeContext codeContext;
+ stackFrame.GetCodeContext(out codeContext);
+
+ IDebugDocumentContext documentContext;
+ codeContext.GetDocumentContext(out documentContext);
+
+ string documentName = string.Empty;
+ uint lineNumber = 0;
+ uint columnNumber = 0;
+
+ if (documentContext is not null)
+ {
+ IDebugDocument document;
+ documentContext.GetDocument(out document);
+
+ document.GetName(DocumentNameType.Title, out documentName);
+
+ var documentText = (IDebugDocumentText)document;
+
+ uint position;
+ uint length;
+ documentText.GetPositionOfContext(documentContext, out position, out length);
+
+ uint offsetInLine;
+ documentText.GetLineOfPosition(position, out lineNumber, out offsetInLine);
+ columnNumber = offsetInLine + 1;
+ }
+
+ CallStackItem callStackItem = new CallStackItem
+ {
+ FunctionName = shortFunctionName,
+ DocumentName = documentName,
+ LineNumber = (int)lineNumber,
+ ColumnNumber = (int)columnNumber
+ };
+ callStackItems.Add(callStackItem);
+ }
+ finally
+ {
+ if (descriptor.pFinalObject != IntPtr.Zero)
+ {
+ Marshal.Release(descriptor.pFinalObject);
+ }
+ }
+ }
+
+ return callStackItems.ToArray();
+ }
+
+ #endregion
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.cs b/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.cs
index 245cdd1..d9309fe 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.cs
@@ -1,45 +1,141 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using Constants;
+#if NETFRAMEWORK
+using System.Collections.Generic;
+
+using MsieJavaScriptEngine.Constants;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// Classic MSIE JavaScript engine
+ /// Active Script version of Classic JS engine
///
- internal sealed class ClassicActiveScriptJsEngine : ActiveScriptJsEngineBase
+ internal sealed partial class ClassicActiveScriptJsEngine : ActiveScriptJsEngineBase
{
- private const string CLASSIC_CLSID = "{f414c260-6ac0-11cf-b6d1-00aa00bbbb58}";
-
///
- /// Flag indicating whether this JavaScript engine is supported
+ /// Flag indicating whether this JS engine is supported
///
private static bool? _isSupported;
///
/// Support synchronizer
///
- private static object _supportSynchronizer = new object();
+ private static Lock _supportSynchronizer = new Lock();
+
+ ///
+ /// Mapping of error numbers and types
+ ///
+ private static readonly Dictionary _runtimeErrorTypeMap = new Dictionary
+ {
+ { JScriptRuntimeErrorNumber.OutOfStackSpace, JsErrorType.Common },
+ { JScriptRuntimeErrorNumber.CannotAssignToThisKeyword, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.NumberExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.FunctionExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.CannotAssignToFunctionResult, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.StringExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.DateObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.IllegalAssignment, JsErrorType.Reference },
+ { JScriptRuntimeErrorNumber.UndefinedIdentifier, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.BooleanExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ObjectMemberExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.VbArrayExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.JavaScriptObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.EnumeratorObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.RegularExpressionObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.SyntaxErrorInRegularExpression, JsErrorType.RegExp },
+ { JScriptRuntimeErrorNumber.UnexpectedQuantifier, JsErrorType.RegExp },
+ { JScriptRuntimeErrorNumber.ExpectedRightSquareBracketInRegularExpression, JsErrorType.RegExp },
+ { JScriptRuntimeErrorNumber.ExpectedRightParenthesisInRegularExpression, JsErrorType.RegExp },
+ { JScriptRuntimeErrorNumber.InvalidRangeInCharacterSet, JsErrorType.RegExp },
+ { JScriptRuntimeErrorNumber.ExceptionThrownAndNotCaught, string.Empty },
+ { JScriptRuntimeErrorNumber.FunctionDoesNotHaveValidPrototypeObject, string.Empty },
+ { JScriptRuntimeErrorNumber.UriToBeEncodedContainsInvalidCharacter, JsErrorType.URI },
+ { JScriptRuntimeErrorNumber.UriToBeDecodedIsNotValidEncoding, JsErrorType.URI },
+ { JScriptRuntimeErrorNumber.NumberOfFractionalDigitsIsOutOfRange, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.PrecisionOutOfRange, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.ArrayOrArgumentsObjectExpected, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.ArrayLengthMustBeFinitePositiveInteger, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.ArrayLengthMustBeAssignedFinitePositiveNumber, JsErrorType.Range },
+ { JScriptRuntimeErrorNumber.CircularReferenceInValueArgumentNotSupported, JsErrorType.Type },
+ { JScriptRuntimeErrorNumber.InvalidReplacerArgument, string.Empty }
+ };
///
- /// Constructs instance of the Classic MSIE JavaScript engine
+ /// Constructs an instance of the Classic Active Script engine
///
- /// Flag for whether to use the ECMAScript 5 Polyfill
- /// Flag for whether to use the JSON2 library
- public ClassicActiveScriptJsEngine(bool useEcmaScript5Polyfill, bool useJson2Library)
- : base(CLASSIC_CLSID, JsEngineMode.Classic, "6",
- ScriptLanguageVersion.None, useEcmaScript5Polyfill, useJson2Library)
+ /// JS engine settings
+ public ClassicActiveScriptJsEngine(JsEngineSettings settings)
+ : base(settings, ClassId.Classic, ScriptLanguageVersion.None, "6", "Microsoft JScript ")
{ }
///
- /// Checks a support of the Classic MSIE JavaScript engine on the machine
+ /// Checks a support of the Classic Active Script engine on the machine
///
- /// Result of check (true - supports; false - does not support)
+ /// Result of check (true - supports; false - does not support)
public static bool IsSupported()
{
- bool isSupported = IsSupported(CLASSIC_CLSID, ref _isSupported, ref _supportSynchronizer);
+ bool isSupported = IsSupported(ClassId.Classic, ref _isSupported, ref _supportSynchronizer);
return isSupported;
}
+
+ ///
+ /// Gets a error type by number
+ ///
+ /// Error number
+ /// Error type
+ protected override string GetErrorTypeByNumber(int errorNumber)
+ {
+ return ActiveScriptJsErrorHelpers.GetErrorTypeByNumber(errorNumber, _runtimeErrorTypeMap);
+ }
+
+ #region ActiveScriptJsEngineBase overrides
+
+ ///
+ /// Creates a instance of the Active Script site
+ ///
+ /// Instance of the Active Script site
+ protected override ScriptSiteBase CreateScriptSite()
+ {
+ return new ScriptSite(this);
+ }
+
+ protected override void InnerRemoveVariable(string variableName)
+ {
+ if (_hostItems.ContainsKey(variableName))
+ {
+ _hostItems.Remove(variableName);
+ }
+ else
+ {
+ InnerSetVariableValue(variableName, null);
+ }
+ }
+
+ #region IInnerJsEngine implementation
+
+ public override bool SupportsScriptPrecompilation
+ {
+ get { return false; }
+ }
+
+
+ public override void Interrupt()
+ {
+ var exceptionInfo = new EXCEPINFO
+ {
+ scode = ComErrorCode.E_ABORT
+ };
+ _activeScriptWrapper.InterruptScriptThread(ScriptThreadId.Base, ref exceptionInfo,
+ ScriptInterruptFlags.None);
+ }
+
+ #endregion
+
+ #endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/AppBreakFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/AppBreakFlags.cs
new file mode 100644
index 0000000..f18226d
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/AppBreakFlags.cs
@@ -0,0 +1,62 @@
+#if NETFRAMEWORK
+using System;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Indicate the current debug state for applications and threads
+ ///
+ [Flags]
+ internal enum AppBreakFlags : uint
+ {
+ None = 0,
+
+ ///
+ /// Language engine should break immediately on all threads with
+ ///
+ ///
+ DebuggerBlock = 0x00000001,
+
+ ///
+ /// Language engine should break immediately with
+ ///
+ DebuggerHalt = 0x00000002,
+
+ ///
+ /// Language engine should break immediately in the stepping thread with
+ ///
+ ///
+ Step = 0x00010000,
+
+ ///
+ /// The application is in nested execution on a breakpoint
+ ///
+ Nested = 0x00020000,
+
+ ///
+ /// The debugger is stepping at the source level
+ ///
+ StepTypeSource = 0x00000000,
+
+ ///
+ /// The debugger is stepping at the byte code level
+ ///
+ StepTypeByteCode = 0x00100000,
+
+ ///
+ /// The debugger is stepping at the machine level
+ ///
+ StepTypeMachine = 0x00200000,
+
+ ///
+ /// Mask for factoring out the step types
+ ///
+ StepTypeMask = 0x00F00000,
+
+ ///
+ /// A breakpoint is in progress
+ ///
+ InBreakpoint = 0x80000000
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakReason.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakReason.cs
new file mode 100644
index 0000000..e632c22
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakReason.cs
@@ -0,0 +1,50 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Indicates what caused the break
+ ///
+ internal enum BreakReason
+ {
+ ///
+ /// The language engine is in the stepping mode
+ ///
+ Step,
+
+ ///
+ /// The language engine encountered an explicit breakpoint
+ ///
+ Breakpoint,
+
+ ///
+ /// The language engine encountered a debugger block on another thread
+ ///
+ DebuggerBlock,
+
+ ///
+ /// The host requested a break
+ ///
+ HostInitiated,
+
+ ///
+ /// The language engine requested a break
+ ///
+ LanguageInitiated,
+
+ ///
+ /// The debugger IDE requested a break
+ ///
+ DebuggerHalt,
+
+ ///
+ /// An execution error caused the break
+ ///
+ Error,
+
+ ///
+ /// Caused by JIT Debugging startup
+ ///
+ Jit
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakResumeAction.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakResumeAction.cs
new file mode 100644
index 0000000..67ba243
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakResumeAction.cs
@@ -0,0 +1,45 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Describes ways to continue from a breakpoint
+ ///
+ internal enum BreakResumeAction
+ {
+ ///
+ /// Aborts the application
+ ///
+ Abort,
+
+ ///
+ /// Continues running
+ ///
+ Continue,
+
+ ///
+ /// Steps into a procedure
+ ///
+ StepInto,
+
+ ///
+ /// Steps over a procedure
+ ///
+ StepOver,
+
+ ///
+ /// Steps out of the current procedure
+ ///
+ StepOut,
+
+ ///
+ /// Continues running with state
+ ///
+ Ignore,
+
+ ///
+ /// Steps to the next document
+ ///
+ StepDocument
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakpointState.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakpointState.cs
new file mode 100644
index 0000000..71824dd
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/BreakpointState.cs
@@ -0,0 +1,25 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Indicates the state of a breakpoint
+ ///
+ internal enum BreakpointState
+ {
+ ///
+ /// The breakpoint no longer exists, but there are still references to it
+ ///
+ Deleted,
+
+ ///
+ /// The breakpoint exists but is disabled
+ ///
+ Disabled,
+
+ ///
+ /// The breakpoint exists and is enabled
+ ///
+ Enabled
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugApplicationWrapper.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugApplicationWrapper.cs
new file mode 100644
index 0000000..e58dd18
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugApplicationWrapper.cs
@@ -0,0 +1,143 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Wrapper for debug application
+ ///
+ internal sealed class DebugApplicationWrapper
+ {
+ ///
+ /// Flag that the current debug application is a 64-bit
+ ///
+ private readonly bool _is64Bit;
+
+ ///
+ /// Instance of 32-bit debug application
+ ///
+ private readonly IDebugApplication32 _debugApplication32;
+
+ ///
+ /// Instance of 64-bit debug application
+ ///
+ private readonly IDebugApplication64 _debugApplication64;
+
+ ///
+ /// Gets a instance of 32-bit debug application
+ ///
+ public IDebugApplication32 DebugApplication32
+ {
+ get { return _debugApplication32; }
+ }
+
+ ///
+ /// Gets a instance of 64-bit debug application
+ ///
+ public IDebugApplication64 DebugApplication64
+ {
+ get { return _debugApplication64; }
+ }
+
+
+ ///
+ /// Constructs an instance of the wrapper for debug application
+ ///
+ /// Instance of 32-bit debug application
+ public DebugApplicationWrapper(IDebugApplication32 debugApplication)
+ {
+ _is64Bit = false;
+ _debugApplication32 = debugApplication;
+ }
+
+ ///
+ /// Constructs an instance of the wrapper for debug application
+ ///
+ /// Instance of 64-bit debug application
+ public DebugApplicationWrapper(IDebugApplication64 debugApplication)
+ {
+ _is64Bit = true;
+ _debugApplication64 = debugApplication;
+ }
+
+
+ ///
+ /// Sets the name of the application
+ ///
+ /// The name of the application
+ public void SetName(string name)
+ {
+ if (_is64Bit)
+ {
+ _debugApplication64.SetName(name);
+ }
+ else
+ {
+ _debugApplication32.SetName(name);
+ }
+ }
+
+ ///
+ /// Returns the application node under which all nodes associated with the application are added
+ ///
+ /// The debug application node under which all nodes associated with
+ /// the application are added
+ public void GetRootNode(out IDebugApplicationNode node)
+ {
+ if (_is64Bit)
+ {
+ _debugApplication64.GetRootNode(out node);
+ }
+ else
+ {
+ _debugApplication32.GetRootNode(out node);
+ }
+ }
+
+ ///
+ /// Creates a new application node that is associated with a specific document provider
+ ///
+ /// The application node associated with this document provider
+ public void CreateApplicationNode(out IDebugApplicationNode node)
+ {
+ if (_is64Bit)
+ {
+ _debugApplication64.CreateApplicationNode(out node);
+ }
+ else
+ {
+ _debugApplication32.CreateApplicationNode(out node);
+ }
+ }
+
+ ///
+ /// Returns the current debugger connected to the application
+ ///
+ /// The current debugger connected to the application
+ /// The method returns an HRESULT
+ public uint GetDebugger(out IApplicationDebugger debugger)
+ {
+ uint result = _is64Bit ?
+ _debugApplication64.GetDebugger(out debugger)
+ :
+ _debugApplication32.GetDebugger(out debugger)
+ ;
+
+ return result;
+ }
+
+ ///
+ /// Causes this application to release all references and enter an inactive state
+ ///
+ public void Close()
+ {
+ if (_is64Bit)
+ {
+ _debugApplication64.Close();
+ }
+ else
+ {
+ _debugApplication32.Close();
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocument.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocument.cs
new file mode 100644
index 0000000..7c7137d
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocument.cs
@@ -0,0 +1,253 @@
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Debug document
+ ///
+ internal sealed class DebugDocument : IDebugDocumentInfo, IDebugDocumentProvider, IDebugDocument,
+ IDebugDocumentText
+ {
+ ///
+ /// Active Script wrapper
+ ///
+ private readonly IActiveScriptWrapper _activeScriptWrapper;
+
+ ///
+ /// Wrapper for debug application
+ ///
+ private readonly DebugApplicationWrapper _debugApplicationWrapper;
+
+ ///
+ /// Source context
+ ///
+ private readonly UIntPtr _sourceContext;
+
+ ///
+ /// Document name
+ ///
+ private readonly string _name;
+
+ ///
+ /// Script text
+ ///
+ private readonly string _code;
+
+ ///
+ /// List of source code lines
+ ///
+ private readonly List _lines = new List();
+
+ ///
+ /// Debug application node
+ ///
+ private IDebugApplicationNode _node;
+
+ ///
+ /// Gets a script text
+ ///
+ public string Code
+ {
+ get { return _code; }
+ }
+
+
+ ///
+ /// Constructs an instance of the debug document
+ ///
+ /// Active Script wrapper
+ /// Wrapper for debug application
+ /// Source context
+ /// Document name
+ /// Script text
+ public DebugDocument(IActiveScriptWrapper activeScriptWrapper,
+ DebugApplicationWrapper debugApplicationWrapper, UIntPtr sourceContext, string name,
+ string code)
+ {
+ _activeScriptWrapper = activeScriptWrapper;
+ _debugApplicationWrapper = debugApplicationWrapper;
+ _sourceContext = sourceContext;
+ _name = name;
+ _code = code;
+
+ Initialize();
+ }
+
+
+ ///
+ /// Initializes a debug document
+ ///
+ private void Initialize()
+ {
+ int documentStartPosition = 0;
+ int documentEndPosition = _code.Length - 1;
+ int lineBreakPosition = int.MinValue;
+ int lineBreakLength = 0;
+ uint lineNumber = 1;
+
+ do
+ {
+ int linePosition = lineBreakPosition == int.MinValue ?
+ documentStartPosition : lineBreakPosition + lineBreakLength;
+ int remainderLength = documentEndPosition - linePosition + 1;
+
+ TextHelpers.FindNextLineBreak(_code, linePosition, remainderLength,
+ out lineBreakPosition, out lineBreakLength);
+
+ int lineLength = lineBreakPosition != -1 ? lineBreakPosition - linePosition : 0;
+
+ _lines.Add(new DebugLineInfo(lineNumber, (uint)linePosition, (uint)lineLength, (uint)lineBreakLength));
+ lineNumber++;
+ }
+ while (lineBreakPosition != -1 && lineBreakPosition <= documentEndPosition);
+
+ _debugApplicationWrapper.CreateApplicationNode(out _node);
+ _node.SetDocumentProvider(this);
+
+ IDebugApplicationNode rootNode;
+ _debugApplicationWrapper.GetRootNode(out rootNode);
+ _node.Attach(rootNode);
+ }
+
+ ///
+ /// Closes a debug document
+ ///
+ public void Close()
+ {
+ if (_node is not null)
+ {
+ _node.Detach();
+ _node.Close();
+ _node = null;
+ }
+
+ if (_lines is not null)
+ {
+ _lines.Clear();
+ }
+ }
+
+ #region IDebugDocumentInfo implementation
+
+ public void GetName(DocumentNameType type, out string documentName)
+ {
+ documentName = _name;
+ }
+
+ public void GetDocumentClassId(out Guid clsid)
+ {
+ clsid = Guid.Empty;
+ }
+
+ #endregion
+
+ #region IDebugDocumentProvider implementation
+
+ public void GetDocument(out IDebugDocument document)
+ {
+ document = this;
+ }
+
+ #endregion
+
+ #region IDebugDocumentText implementation
+
+ public void GetDocumentAttributes(out TextDocAttrs attrs)
+ {
+ attrs = TextDocAttrs.ReadOnly;
+ }
+
+ public void GetSize(out uint numLines, out uint length)
+ {
+ numLines = (uint)_lines.Count;
+ length = (uint)_code.Length;
+ }
+
+ public void GetPositionOfLine(uint lineNumber, out uint position)
+ {
+ position = 0;
+ int lineCount = _lines.Count;
+
+ if (lineNumber == 0 || lineNumber > lineCount)
+ {
+ throw new ArgumentOutOfRangeException("lineNumber");
+ }
+
+ if (lineCount > 0)
+ {
+ int lineIndex = (int)lineNumber - 1;
+ position = _lines[lineIndex].Position;
+ }
+ }
+
+ public void GetLineOfPosition(uint position, out uint lineNumber, out uint offsetInLine)
+ {
+ if (position >= _code.Length)
+ {
+ throw new ArgumentOutOfRangeException("position");
+ }
+
+ lineNumber = 0;
+ offsetInLine = position;
+ int lineCount = _lines.Count;
+
+ for (int lineIndex = 0; lineIndex < lineCount; lineIndex++)
+ {
+ DebugLineInfo line = _lines[lineIndex];
+ lineNumber = line.Number;
+ uint fullLineLength = line.Length + line.BreakLength;
+
+ if (offsetInLine < fullLineLength)
+ {
+ break;
+ }
+
+ offsetInLine -= fullLineLength;
+ }
+ }
+
+ public void GetText(uint position, IntPtr pChars, IntPtr pAttrs, ref uint length, uint maxChars)
+ {
+ var codeLength = (uint)_code.Length;
+ if (position < codeLength)
+ {
+ length = Math.Min(codeLength - position, maxChars);
+
+ if (pChars != IntPtr.Zero)
+ {
+ Marshal.Copy(_code.ToCharArray((int)position, (int)length), 0, pChars, (int)length);
+ }
+
+ if (pAttrs != IntPtr.Zero)
+ {
+ short[] attrs = Enumerable.Repeat((short)SourceTextAttrs.None, (int)length).ToArray();
+ Marshal.Copy(attrs, 0, pAttrs, (int)length);
+ }
+ }
+ }
+
+ public void GetPositionOfContext(IDebugDocumentContext context, out uint position, out uint length)
+ {
+ var documentContext = (DebugDocumentContext)context;
+ position = documentContext.Position;
+ length = documentContext.Length;
+ }
+
+ public void GetContextOfPosition(uint position, uint length, out IDebugDocumentContext context)
+ {
+ IEnumDebugCodeContexts enumCodeContexts;
+ _activeScriptWrapper.EnumCodeContextsOfPosition(_sourceContext, position, length,
+ out enumCodeContexts);
+ context = new DebugDocumentContext(this, position, length, enumCodeContexts);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocumentContext.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocumentContext.cs
new file mode 100644
index 0000000..832ced4
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugDocumentContext.cs
@@ -0,0 +1,78 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Debug document context
+ ///
+ internal sealed class DebugDocumentContext : IDebugDocumentContext
+ {
+ ///
+ /// Debug document
+ ///
+ private readonly DebugDocument _document;
+
+ ///
+ /// Position
+ ///
+ private readonly uint _position;
+
+ ///
+ /// Length
+ ///
+ private readonly uint _length;
+
+ ///
+ /// Code context enumerator
+ ///
+ private readonly IEnumDebugCodeContexts _enumCodeContexts;
+
+ ///
+ /// Gets a position
+ ///
+ public uint Position
+ {
+ get { return _position; }
+ }
+
+ ///
+ /// Gets a length
+ ///
+ public uint Length
+ {
+ get { return _length; }
+ }
+
+
+ ///
+ /// Constructs an instance of the debug document context
+ ///
+ /// Debug document
+ /// Position
+ /// Length
+ /// Code context enumerator
+ public DebugDocumentContext(DebugDocument document, uint position, uint length,
+ IEnumDebugCodeContexts enumCodeContexts)
+ {
+ _document = document;
+ _position = position;
+ _length = length;
+ _enumCodeContexts = enumCodeContexts;
+ }
+
+
+ #region IDebugDocumentContext implementation
+
+ public void GetDocument(out IDebugDocument debugDocument)
+ {
+ debugDocument = _document;
+ }
+
+ public void EnumCodeContexts(out IEnumDebugCodeContexts enumContexts)
+ {
+ _enumCodeContexts.Clone(out enumContexts);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugLineInfo.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugLineInfo.cs
new file mode 100644
index 0000000..7300bde
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugLineInfo.cs
@@ -0,0 +1,46 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Information about line of source code
+ ///
+ internal struct DebugLineInfo
+ {
+ ///
+ /// Gets a line number
+ ///
+ public readonly uint Number;
+
+ ///
+ /// Gets a position of line
+ ///
+ public readonly uint Position;
+
+ ///
+ /// Gets a length of line
+ ///
+ public readonly uint Length;
+
+ ///
+ /// Gets a length of line break
+ ///
+ public readonly uint BreakLength;
+
+
+ ///
+ /// Constructs an instance of the information about line of source code
+ ///
+ /// Line number
+ /// Position of line
+ /// Length of line
+ /// Length of line break
+ public DebugLineInfo(uint number, uint position, uint length, uint breakLength)
+ {
+ Number = number;
+ Position = position;
+ Length = length;
+ BreakLength = breakLength;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugStackFrameDescriptor.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugStackFrameDescriptor.cs
new file mode 100644
index 0000000..4823b28
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DebugStackFrameDescriptor.cs
@@ -0,0 +1,49 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates stack frames and merges output from several enumerators on the same thread
+ ///
+ ///
+ /// The process debug manager uses this structure to sort the stack frames from
+ /// multiple script engines. By convention, stacks grow down. Consequently, on architectures
+ /// where stacks grow up, the addresses should be twos-complemented.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DebugStackFrameDescriptor
+ {
+ ///
+ /// The stack frame object
+ ///
+ [MarshalAs(UnmanagedType.Interface)]
+ public IDebugStackFrame Frame;
+
+ ///
+ /// A machine-dependent representation of the lower range of physical addresses
+ /// associated with this stack frame
+ ///
+ public uint Minimum;
+
+ ///
+ /// A machine-dependent representation of the upper range of physical addresses
+ /// associated with this stack frame
+ ///
+ public uint Limit;
+
+ ///
+ /// Flag that indicates that the frame is being processed
+ ///
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool IsFinal;
+
+ ///
+ /// If this parameter is not null , the current enumerator merging should stop and
+ /// a new one should be started. The object indicates how to start the new enumeration.
+ ///
+ public IntPtr pFinalObject;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/DocumentNameType.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DocumentNameType.cs
new file mode 100644
index 0000000..9353c03
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/DocumentNameType.cs
@@ -0,0 +1,35 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Describes which type to get for a document
+ ///
+ internal enum DocumentNameType
+ {
+ ///
+ /// Gets the name as it appears in the application tree
+ ///
+ AppNode,
+
+ ///
+ /// Gets the name as it appears on the viewer title bar
+ ///
+ Title,
+
+ ///
+ /// Gets the file name without a path
+ ///
+ FileTail,
+
+ ///
+ /// Gets the URL of the document
+ ///
+ Url,
+
+ ///
+ /// Gets the title appended with enumeration for identification
+ ///
+ UniqueTitle
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/ErrorResumeAction.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ErrorResumeAction.cs
new file mode 100644
index 0000000..c294997
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ErrorResumeAction.cs
@@ -0,0 +1,25 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Describes how to continue from a runtime error
+ ///
+ internal enum ErrorResumeAction
+ {
+ ///
+ /// Re-executes the statement that produced the error
+ ///
+ ReexecuteErrorStatement,
+
+ ///
+ /// Lets the language engine handle the error
+ ///
+ AbortCallAndReturnErrorToCaller,
+
+ ///
+ /// Resumes execution in the code following the statement that produced the error
+ ///
+ SkipErrorStatement
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug32.cs
new file mode 100644
index 0000000..21c2a6e
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug32.cs
@@ -0,0 +1,66 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Implemented by script engines that support debugging
+ ///
+ [ComImport]
+ [Guid("51973c10-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptDebug32
+ {
+ ///
+ /// Returns the text attributes for an arbitrary block of script text
+ ///
+ /// The script block text
+ /// The number of characters in the script block text
+ /// End of script block delimiter
+ /// Flags associated with the script block
+ /// Buffer to contain the returned attributes
+ void GetScriptTextAttributes(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string code,
+ [In] uint length,
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
+ [In] ScriptTextFlags flags,
+ [In] [Out] ref IntPtr pAttrs
+ );
+
+ ///
+ /// Returns the text attributes for an arbitrary scriptlet
+ ///
+ /// The scriptlet text
+ /// The number of characters in the scriptlet text
+ /// End of scriptlet delimiter
+ /// Flags associated with the scriptlet
+ /// Buffer to contain the returned attributes
+ void GetScriptletTextAttributes(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string code,
+ [In] uint length,
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
+ [In] ScriptTextFlags flags,
+ [In] [Out] ref IntPtr pAttrs
+ );
+
+ ///
+ /// Used by a smart host to delegate the method
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script text
+ /// Number of characters in this context
+ /// An enumerator of the code contexts in the specified range
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint EnumCodeContextsOfPosition(
+ [In] uint sourceContext,
+ [In] uint offset,
+ [In] uint length,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugCodeContexts enumContexts
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug64.cs
new file mode 100644
index 0000000..0a23f42
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptDebug64.cs
@@ -0,0 +1,66 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Implemented by script engines that support debugging
+ ///
+ [ComImport]
+ [Guid("bc437e23-f5b8-47f4-bb79-7d1ce5483b86")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptDebug64
+ {
+ ///
+ /// Returns the text attributes for an arbitrary block of script text
+ ///
+ /// The script block text
+ /// The number of characters in the script block text
+ /// End of script block delimiter
+ /// Flags associated with the script block
+ /// Buffer to contain the returned attributes
+ void GetScriptTextAttributes(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string code,
+ [In] uint length,
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
+ [In] ScriptTextFlags flags,
+ [In] [Out] ref IntPtr pAttrs
+ );
+
+ ///
+ /// Returns the text attributes for an arbitrary scriptlet
+ ///
+ /// The scriptlet text
+ /// The number of characters in the scriptlet text
+ /// End of scriptlet delimiter
+ /// Flags associated with the scriptlet
+ /// Buffer to contain the returned attributes
+ void GetScriptletTextAttributes(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string code,
+ [In] uint length,
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
+ [In] ScriptTextFlags flags,
+ [In] [Out] ref IntPtr pAttrs
+ );
+
+ ///
+ /// Used by a smart host to delegate the method
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script text
+ /// Number of characters in this context
+ /// An enumerator of the code contexts in the specified range
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint EnumCodeContextsOfPosition(
+ [In] ulong sourceContext,
+ [In] uint offset,
+ [In] uint length,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugCodeContexts enumContexts
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptErrorDebug.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptErrorDebug.cs
new file mode 100644
index 0000000..6932036
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptErrorDebug.cs
@@ -0,0 +1,52 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides document context information for compile-time errors and run-time exceptions
+ ///
+ [ComImport]
+ [Guid("51973c12-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptErrorDebug // : IActiveScriptError
+ {
+ #region IActiveScriptError methods
+
+ ///
+ /// Retrieves information about an error that occurred while the scripting engine was running a script
+ ///
+ /// An EXCEPINFO structure that receives error information
+ void GetExceptionInfo(
+ [Out] out EXCEPINFO exceptionInfo
+ );
+
+ ///
+ /// Retrieves the location in the source code where an error occurred while the scripting engine
+ /// was running a script
+ ///
+ /// A cookie that identifies the context. The interpretation of
+ /// this parameter depends on the host application.
+ /// The line number in the source file where the error occurred
+ /// The character position in the line where the error occurred
+ void GetSourcePosition(
+ [Out] out uint sourceContext,
+ [Out] out uint lineNumber,
+ [Out] out int characterPosition
+ );
+
+ ///
+ /// Retrieves the line in the source file where an error occurred while a scripting engine
+ /// was running a script
+ ///
+ /// The line of source code in which the error occurred
+ void GetSourceLineText(
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string sourceLine
+ );
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug32.cs
new file mode 100644
index 0000000..a7c0618
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug32.cs
@@ -0,0 +1,64 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Smart hosts implement the interface to perform document management
+ /// and to participate in debugging
+ ///
+ [ComImport]
+ [Guid("51973c11-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptSiteDebug32
+ {
+ ///
+ /// Used by the language engine to delegate
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script block or scriptlet
+ /// Number of characters in this context
+ /// The document context corresponding to this character-position
+ /// range
+ void GetDocumentContextFromPosition(
+ [In] uint sourceContext,
+ [In] uint offset,
+ [In] uint length,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocumentContext documentContext
+ );
+
+ ///
+ /// Returns the debug application object associated with this script site
+ ///
+ /// The debug application object associated with the script site
+ void GetApplication(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplication32 application
+ );
+
+ ///
+ /// Gets the application node under which script documents should be added
+ ///
+ /// The debug application node that holds script documents
+ void GetRootApplicationNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Allows a smart host to determine how to handle run-time errors
+ ///
+ /// The run-time error that occurred
+ /// Flag indicating whether to pass the error to the debugger to
+ /// do JIT debugging
+ /// Flag indicating whether to call
+ /// when the user decides to continue without
+ /// debugging
+ void OnScriptErrorDebug(
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptErrorDebug errorDebug,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool enterDebugger,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool callOnScriptErrorWhenContinuing
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug64.cs
new file mode 100644
index 0000000..0cec490
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebug64.cs
@@ -0,0 +1,64 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Smart hosts implement the interface to perform document management
+ /// and to participate in debugging
+ ///
+ [ComImport]
+ [Guid("d6b96b0a-7463-402c-92ac-89984226942f")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptSiteDebug64
+ {
+ ///
+ /// Used by the language engine to delegate IDebugCodeContext.GetSourceContext
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script block or scriptlet
+ /// Number of characters in this context
+ /// The document context corresponding to this character-position
+ /// range
+ void GetDocumentContextFromPosition(
+ [In] ulong sourceContext,
+ [In] uint offset,
+ [In] uint length,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocumentContext documentContext
+ );
+
+ ///
+ /// Returns the debug application object associated with this script site
+ ///
+ /// The debug application object associated with the script site
+ void GetApplication(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplication64 application
+ );
+
+ ///
+ /// Gets the application node under which script documents should be added
+ ///
+ /// The debug application node that holds script documents
+ void GetRootApplicationNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Allows a smart host to determine how to handle run-time errors
+ ///
+ /// The run-time error that occurred
+ /// Flag indicating whether to pass the error to the debugger to
+ /// do JIT debugging
+ /// Flag indicating whether to call
+ /// when the user decides to continue without
+ /// debugging
+ void OnScriptErrorDebug(
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptErrorDebug errorDebug,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool enterDebugger,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool callOnScriptErrorWhenContinuing
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebugEx.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebugEx.cs
new file mode 100644
index 0000000..b44c9fd
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IActiveScriptSiteDebugEx.cs
@@ -0,0 +1,35 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Implement this interface along with the
+ /// or interface if you are writing a host that needs
+ /// to get a notification of a run-time error in an application and optionally attach to
+ /// the application for debugging. The Process Debug Manager provides notification through
+ /// or if a Just-In-Time
+ /// script debugger is found on the computer. If no Just-In-Time script debugger is found,
+ /// the PDM provides notification through instead.
+ ///
+ [ComImport]
+ [Guid("bb722ccb-6ad2-41c6-b780-af9c03ee69f5")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptSiteDebugEx
+ {
+ ///
+ /// Informs the host about a script run-time error when the Process Debug Manager does not
+ /// find a Just In Time script debugger
+ ///
+ /// The run-time error that occurred
+ /// Whether to call
+ /// or
+ /// if the user decides to
+ /// continue without debugging
+ void OnCanNotJitScriptErrorDebug(
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptErrorDebug errorDebug,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool callOnScriptErrorWhenContinuing
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IApplicationDebugger.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IApplicationDebugger.cs
new file mode 100644
index 0000000..e72e43d
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IApplicationDebugger.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The primary interface exposed by a debugger
+ ///
+ [ComImport]
+ [Guid("51973c2a-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IApplicationDebugger
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication32.cs
new file mode 100644
index 0000000..87a78c3
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication32.cs
@@ -0,0 +1,303 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Exposes non-remote debugging methods for use by language engines and hosts
+ ///
+ [ComImport]
+ [Guid("51973C32-CB0C-11d0-B5C9-00A0244A0E7A")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugApplication32 // : IRemoteDebugApplication
+ {
+#if NETFRAMEWORK
+ #region IRemoteDebugApplication methods
+
+ ///
+ /// Continues an application that is currently in a breakpoint
+ ///
+ /// For stepping modes, the thread which is to be affected by the stepping mode
+ /// The action to take upon resuming the application
+ /// The action to take in the case that the application stopped because of an error
+ void ResumeFromBreakPoint(
+ [In] [MarshalAs(UnmanagedType.Interface)] IRemoteDebugApplicationThread thread,
+ [In] BreakResumeAction breakResumeAction,
+ [In] ErrorResumeAction errorResumeAction
+ );
+
+ ///
+ /// Causes the application to break into the debugger at the earliest opportunity
+ ///
+ void CauseBreak();
+
+ ///
+ /// Connects a debugger to this application
+ ///
+ /// The debugger to attach to this application
+ void ConnectDebugger(
+ [In] [MarshalAs(UnmanagedType.Interface)] IApplicationDebugger debugger
+ );
+
+ ///
+ /// Disconnects the current debugger from the application
+ ///
+ void DisconnectDebugger();
+
+ ///
+ /// Returns the current debugger connected to the application
+ ///
+ /// The current debugger connected to the application
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint GetDebugger(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IApplicationDebugger debugger
+ );
+
+ ///
+ /// Allows the creation of objects in the application process by code that is out-of-process
+ /// to the application
+ ///
+ /// Class identifier (CLSID) of the object to create
+ /// The aggregate object's IUnknown interface
+ /// Context for running executable code
+ /// The interface identifier used to communicate with the object
+ /// Variable that receives the interface pointer requested in
+ void CreateInstanceAtApplication(
+ [In] ref Guid clsid,
+ [In] [MarshalAs(UnmanagedType.IUnknown)] object outer,
+ [In] uint clsContext,
+ [In] ref Guid iid,
+ [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 3)] out object instance
+ );
+
+ ///
+ /// Indicates if the application is responsive
+ ///
+ void QueryAlive();
+
+ ///
+ /// Enumerates all threads known to be associated with the application
+ ///
+ /// Enumerator that lists all threads known to be associated with
+ /// the application
+ void EnumThreads(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumRemoteDebugApplicationThreads enumThreads
+ );
+
+ ///
+ /// Returns the name of this application node
+ ///
+ /// Name of this application node
+ void GetName(
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns the application node under which all nodes associated with the application are added
+ ///
+ /// The debug application node under which all nodes associated with
+ /// the application are added
+ void GetRootNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Enumerates the global expression contexts for all languages running in this application
+ ///
+ /// Enumerator that lists the global expression contexts for all
+ /// languages running in this application
+ void EnumGlobalExpressionContexts(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugExpressionContexts enumContexts
+ );
+
+ #endregion
+
+ ///
+ /// Sets the name of the application
+ ///
+ /// The name of the application
+ void SetName(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string name
+ );
+
+ ///
+ /// Notifies the process debug manager that a language engine in single-step mode is about
+ /// to return to its caller
+ ///
+ void StepOutComplete();
+
+ ///
+ /// Causes the given string to be displayed by the debugger IDE
+ ///
+ /// String to display in the debugger
+ void DebugOutput(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string str
+ );
+
+ ///
+ /// Starts the default debugger IDE and attaches a debug session to this application, if one
+ /// is not already attached
+ ///
+ void StartDebugSession();
+
+ ///
+ /// Causes the current thread to block and sends a notification of the breakpoint to the debugger IDE
+ ///
+ /// The reason for the break
+ /// Action to take when the debugger resumes the application
+ void HandleBreakPoint(
+ [In] BreakReason reason,
+ [Out] out BreakResumeAction resumeAction
+ );
+
+ ///
+ /// Causes this application to release all references and enter an inactive state
+ ///
+ void Close();
+
+ ///
+ /// Returns the current break flags for the application
+ ///
+ /// The current break flags for the application
+ /// The currently running thread
+ void GetBreakFlags(
+ [Out] out AppBreakFlags flags,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IRemoteDebugApplicationThread thread
+ );
+
+ ///
+ /// Returns the thread associated with the currently running thread
+ ///
+ /// The thread associated with the currently running thread
+ void GetCurrentThread(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationThread thread
+ );
+
+ ///
+ /// Provides asynchronous access to a given synchronous debug operation
+ ///
+ /// The synchronous debug operation object
+ /// The asynchronous debug operation object
+ void CreateAsyncDebugOperation(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugSyncOperation syncOperation,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugAsyncOperation asyncOperation
+ );
+
+ ///
+ /// Adds a stack frame enumerator provider to this application
+ ///
+ /// The stack frame enumerator provider to add to this application
+ /// A cookie that is used to remove this stack frame enumerator provider
+ /// from the application
+ void AddStackFrameSniffer(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugStackFrameSniffer sniffer,
+ [Out] out uint cookie
+ );
+
+ ///
+ /// Removes a stack frame enumerator provider from this application
+ ///
+ /// The cookie returned by the method
+ /// when the stack frame enumerator provider was added
+ void RemoveStackFrameSniffer(
+ [In] uint cookie
+ );
+
+ ///
+ /// Determines if the current running thread is the debugger thread
+ ///
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint QueryCurrentThreadIsDebuggerThread();
+
+ ///
+ /// Provides a mechanism for the caller to run code in the debugger thread
+ ///
+ /// The object to call
+ /// First parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ /// Second parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ /// Third parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ void SynchronousCallInDebuggerThread(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugThreadCall32 call,
+ [In] uint param1,
+ [In] uint param2,
+ [In] uint param3
+ );
+
+ ///
+ /// Creates a new application node that is associated with a specific document provider
+ ///
+ /// The application node associated with this document provider
+ void CreateApplicationNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Fires a generic event to the debugger's interface
+ ///
+ /// A GUID for the object
+ /// An event object to pass to the debugger
+ void FireDebuggerEvent(
+ [In] ref Guid iid,
+ [In] [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] object eventObject
+ );
+
+ ///
+ /// Causes the current thread to block and sends a notification of the error to the debugger IDE
+ ///
+ /// The error that occurred
+ /// The script site of the thread
+ /// Action to take when the debugger resumes the application
+ /// Action to take when the debugger resumes the application
+ /// if there is an error
+ /// Flag which is true if the engine should call
+ /// the method
+ void HandleRuntimeError(
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptErrorDebug errorDebug,
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptSite scriptSite,
+ [Out] out BreakResumeAction breakResumeAction,
+ [Out] out ErrorResumeAction errorResumeAction,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool callOnScriptError
+ );
+
+ ///
+ /// Determines if a JIT debugger is registered
+ ///
+ /// If the method succeeds and a JIT debugger is registered, the method returns true .
+ /// Otherwise, it returns false .
+ [PreserveSig]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ bool FCanJitDebug();
+
+ ///
+ /// Determines if a JIT debugger is registered to auto-debug dumb hosts
+ ///
+ /// If the method succeeds and a JIT debugger is registered to auto-debug dumb hosts,
+ /// the method returns true . Otherwise, it returns false .
+ [PreserveSig]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ bool FIsAutoJitDebugEnabled();
+
+ ///
+ /// Adds a global expression context provider to this application
+ ///
+ /// The global context provider to add to this application
+ /// A cookie that is used to remove this global expression context provider
+ /// from the application
+ void AddGlobalExpressionContextProvider(
+ [In] [MarshalAs(UnmanagedType.Interface)] IProvideExpressionContexts provider,
+ [Out] out uint cookie
+ );
+
+ ///
+ /// Removes a global expression context provider from this application
+ ///
+ /// The cookie returned by the method
+ /// when the global context provider was added
+ void RemoveGlobalExpressionContextProvider(
+ [In] uint cookie
+ );
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication64.cs
new file mode 100644
index 0000000..6f1993c
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplication64.cs
@@ -0,0 +1,303 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Exposes non-remote debugging methods for use by language engines and hosts
+ ///
+ [ComImport]
+ [Guid("4dedc754-04c7-4f10-9e60-16a390fe6e62")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugApplication64 // : IRemoteDebugApplication
+ {
+#if NETFRAMEWORK
+ #region IRemoteDebugApplication methods
+
+ ///
+ /// Continues an application that is currently in a breakpoint
+ ///
+ /// For stepping modes, the thread which is to be affected by the stepping mode
+ /// The action to take upon resuming the application
+ /// The action to take in the case that the application stopped because of an error
+ void ResumeFromBreakPoint(
+ [In] [MarshalAs(UnmanagedType.Interface)] IRemoteDebugApplicationThread thread,
+ [In] BreakResumeAction breakResumeAction,
+ [In] ErrorResumeAction errorResumeAction
+ );
+
+ ///
+ /// Causes the application to break into the debugger at the earliest opportunity
+ ///
+ void CauseBreak();
+
+ ///
+ /// Connects a debugger to this application
+ ///
+ /// The debugger to attach to this application
+ void ConnectDebugger(
+ [In] [MarshalAs(UnmanagedType.Interface)] IApplicationDebugger debugger
+ );
+
+ ///
+ /// Disconnects the current debugger from the application
+ ///
+ void DisconnectDebugger();
+
+ ///
+ /// Returns the current debugger connected to the application
+ ///
+ /// The current debugger connected to the application
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint GetDebugger(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IApplicationDebugger debugger
+ );
+
+ ///
+ /// Allows the creation of objects in the application process by code that is out-of-process
+ /// to the application
+ ///
+ /// Class identifier (CLSID) of the object to create
+ /// The aggregate object's IUnknown interface
+ /// Context for running executable code
+ /// The interface identifier used to communicate with the object
+ /// Variable that receives the interface pointer requested in
+ void CreateInstanceAtApplication(
+ [In] ref Guid clsid,
+ [In] [MarshalAs(UnmanagedType.IUnknown)] object outer,
+ [In] uint clsContext,
+ [In] ref Guid iid,
+ [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 3)] out object instance
+ );
+
+ ///
+ /// Indicates if the application is responsive
+ ///
+ void QueryAlive();
+
+ ///
+ /// Enumerates all threads known to be associated with the application
+ ///
+ /// Enumerator that lists all threads known to be associated with
+ /// the application
+ void EnumThreads(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumRemoteDebugApplicationThreads enumThreads
+ );
+
+ ///
+ /// Returns the name of this application node
+ ///
+ /// Name of this application node
+ void GetName(
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns the application node under which all nodes associated with the application are added
+ ///
+ /// The debug application node under which all nodes associated with
+ /// the application are added
+ void GetRootNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Enumerates the global expression contexts for all languages running in this application
+ ///
+ /// Enumerator that lists the global expression contexts for all
+ /// languages running in this application
+ void EnumGlobalExpressionContexts(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugExpressionContexts enumContexts
+ );
+
+ #endregion
+
+ ///
+ /// Sets the name of the application
+ ///
+ /// The name of the application
+ void SetName(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string name
+ );
+
+ ///
+ /// Notifies the process debug manager that a language engine in single-step mode is about
+ /// to return to its caller
+ ///
+ void StepOutComplete();
+
+ ///
+ /// Causes the given string to be displayed by the debugger IDE
+ ///
+ /// String to display in the debugger
+ void DebugOutput(
+ [In] [MarshalAs(UnmanagedType.LPWStr)] string str
+ );
+
+ ///
+ /// Starts the default debugger IDE and attaches a debug session to this application, if one
+ /// is not already attached
+ ///
+ void StartDebugSession();
+
+ ///
+ /// Causes the current thread to block and sends a notification of the breakpoint to the debugger IDE
+ ///
+ /// The reason for the break
+ /// Action to take when the debugger resumes the application
+ void HandleBreakPoint(
+ [In] BreakReason reason,
+ [Out] out BreakResumeAction resumeAction
+ );
+
+ ///
+ /// Causes this application to release all references and enter an inactive state
+ ///
+ void Close();
+
+ ///
+ /// Returns the current break flags for the application
+ ///
+ /// The current break flags for the application
+ /// The currently running thread
+ void GetBreakFlags(
+ [Out] out AppBreakFlags flags,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IRemoteDebugApplicationThread thread
+ );
+
+ ///
+ /// Returns the thread associated with the currently running thread
+ ///
+ /// The thread associated with the currently running thread
+ void GetCurrentThread(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationThread thread
+ );
+
+ ///
+ /// Provides asynchronous access to a given synchronous debug operation
+ ///
+ /// The synchronous debug operation object
+ /// The asynchronous debug operation object
+ void CreateAsyncDebugOperation(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugSyncOperation syncOperation,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugAsyncOperation asyncOperation
+ );
+
+ ///
+ /// Adds a stack frame enumerator provider to this application
+ ///
+ /// The stack frame enumerator provider to add to this application
+ /// A cookie that is used to remove this stack frame enumerator provider
+ /// from the application
+ void AddStackFrameSniffer(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugStackFrameSniffer sniffer,
+ [Out] out uint cookie
+ );
+
+ ///
+ /// Removes a stack frame enumerator provider from this application
+ ///
+ /// The cookie returned by the method
+ /// when the stack frame enumerator provider was added
+ void RemoveStackFrameSniffer(
+ [In] uint cookie
+ );
+
+ ///
+ /// Determines if the current running thread is the debugger thread
+ ///
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint QueryCurrentThreadIsDebuggerThread();
+
+ ///
+ /// Provides a mechanism for the caller to run code in the debugger thread
+ ///
+ /// The object to call
+ /// First parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ /// Second parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ /// Third parameter to pass to the IDebugThreadCall.ThreadCallHandler method
+ void SynchronousCallInDebuggerThread(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugThreadCall64 call,
+ [In] ulong param1,
+ [In] ulong param2,
+ [In] ulong param3
+ );
+
+ ///
+ /// Creates a new application node that is associated with a specific document provider
+ ///
+ /// The application node associated with this document provider
+ void CreateApplicationNode(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Fires a generic event to the debugger's interface
+ ///
+ /// A GUID for the object
+ /// An event object to pass to the debugger
+ void FireDebuggerEvent(
+ [In] ref Guid iid,
+ [In] [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] object eventObject
+ );
+
+ ///
+ /// Causes the current thread to block and sends a notification of the error to the debugger IDE
+ ///
+ /// The error that occurred
+ /// The script site of the thread
+ /// Action to take when the debugger resumes the application
+ /// Action to take when the debugger resumes the application
+ /// if there is an error
+ /// Flag which is true if the engine should call
+ /// the method
+ void HandleRuntimeError(
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptErrorDebug errorDebug,
+ [In] [MarshalAs(UnmanagedType.Interface)] IActiveScriptSite scriptSite,
+ [Out] out BreakResumeAction breakResumeAction,
+ [Out] out ErrorResumeAction errorResumeAction,
+ [Out] [MarshalAs(UnmanagedType.Bool)] out bool callOnScriptError
+ );
+
+ ///
+ /// Determines if a JIT debugger is registered
+ ///
+ /// If the method succeeds and a JIT debugger is registered, the method returns true .
+ /// Otherwise, it returns false .
+ [PreserveSig]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ bool FCanJitDebug();
+
+ ///
+ /// Determines if a JIT debugger is registered to auto-debug dumb hosts
+ ///
+ /// If the method succeeds and a JIT debugger is registered to auto-debug dumb hosts,
+ /// the method returns true . Otherwise, it returns false .
+ [PreserveSig]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ bool FIsAutoJitDebugEnabled();
+
+ ///
+ /// Adds a global expression context provider to this application
+ ///
+ /// The global context provider to add to this application
+ /// A cookie that is used to remove this global expression context provider
+ /// from the application
+ void AddGlobalExpressionContextProvider(
+ [In] [MarshalAs(UnmanagedType.Interface)] IProvideExpressionContexts provider,
+ [Out] out uint cookie
+ );
+
+ ///
+ /// Removes a global expression context provider from this application
+ ///
+ /// The cookie returned by the method
+ /// when the global context provider was added
+ void RemoveGlobalExpressionContextProvider(
+ [In] uint cookie
+ );
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationNode.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationNode.cs
new file mode 100644
index 0000000..0b892ae
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationNode.cs
@@ -0,0 +1,93 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The interface extends the functionality of
+ /// the interface by providing a context within a project tree
+ ///
+ [ComImport]
+ [Guid("51973c34-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugApplicationNode // : IDebugDocumentProvider
+ {
+ #region IDebugDocumentProvider methods
+
+ #region IDebugDocumentInfo methods
+
+ ///
+ /// Returns the specified document name
+ ///
+ /// The type of document name to return
+ /// String containing the name
+ void GetName(
+ [In] DocumentNameType type,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns a CLSID identifying the document type
+ ///
+ /// A CLSID identifying the document type
+ void GetDocumentClassId(
+ [Out] out Guid clsid
+ );
+
+ #endregion
+
+ ///
+ /// Causes the document to be instantiated if it does not already exist
+ ///
+ /// The debug document corresponding to the document
+ void GetDocument(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocument document
+ );
+
+ #endregion
+
+ ///
+ /// Enumerates the child nodes of this application node
+ ///
+ /// The enumeration of this node's child nodes
+ void EnumChildren(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugApplicationNodes enumNodes
+ );
+
+ ///
+ /// Returns the parent node of this application node
+ ///
+ /// Parent application node of this application node
+ void GetParent(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationNode node
+ );
+
+ ///
+ /// Sets the document provider for this application node
+ ///
+ /// The document provider for this application node
+ void SetDocumentProvider(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugDocumentProvider provider
+ );
+
+ ///
+ /// Causes this application to release all references and enter an inactive state
+ ///
+ void Close();
+
+ ///
+ /// Adds this application node to the specified project tree
+ ///
+ /// The project tree where this application node is to be added
+ void Attach(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugApplicationNode node
+ );
+
+ ///
+ /// Removes this application node from the project tree
+ ///
+ void Detach();
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationThread.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationThread.cs
new file mode 100644
index 0000000..c8fc7de
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugApplicationThread.cs
@@ -0,0 +1,17 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Allows language engines and hosts to provide thread synchronization and to maintain
+ /// thread-specific debug state information. This interface extends
+ /// the interface to provide non-remote access to the thread.
+ ///
+ [ComImport]
+ [Guid("51973c38-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugApplicationThread // : IRemoteDebugApplicationThread
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugAsyncOperation.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugAsyncOperation.cs
new file mode 100644
index 0000000..68cfd16
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugAsyncOperation.cs
@@ -0,0 +1,19 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The Process Debug Manager implements the interface.
+ /// A language engine calls the IDebugApplication.CreateAsyncDebugOperation method
+ /// to obtain a reference to this interface. The language engine can use
+ /// the interface to provide asynchronous access to a synchronous
+ /// debug operation.
+ ///
+ [ComImport]
+ [Guid("51973c1b-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugAsyncOperation
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugCodeContext.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugCodeContext.cs
new file mode 100644
index 0000000..18e0c86
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugCodeContext.cs
@@ -0,0 +1,31 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// An abstraction that represents a position in executable code
+ ///
+ [ComImport]
+ [Guid("51973c13-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugCodeContext
+ {
+ ///
+ /// Returns the document context associated with this code context
+ ///
+ /// The document context associated with this code context
+ void GetDocumentContext(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocumentContext context
+ );
+
+ ///
+ /// Sets or clears a breakpoint at this code context
+ ///
+ /// Specifies the breakpoint state for this code context
+ void SetBreakPoint(
+ [In] BreakpointState state
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocument.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocument.cs
new file mode 100644
index 0000000..e70f7f4
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocument.cs
@@ -0,0 +1,38 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The base interface for all debug documents
+ ///
+ [ComImport]
+ [Guid("51973c21-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocument // : IDebugDocumentInfo
+ {
+ #region IDebugDocumentInfo methods
+
+ ///
+ /// Returns the specified document name
+ ///
+ /// The type of document name to return
+ /// String containing the name
+ void GetName(
+ [In] DocumentNameType type,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns a CLSID identifying the document type
+ ///
+ /// A CLSID identifying the document type
+ void GetDocumentClassId(
+ [Out] out Guid clsid
+ );
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentContext.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentContext.cs
new file mode 100644
index 0000000..3fe7cc1
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentContext.cs
@@ -0,0 +1,32 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides an abstract representation of a portion of the document being debugged.
+ /// For text documents, this representation consists of a character-position range
+ ///
+ [ComImport]
+ [Guid("51973c28-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentContext
+ {
+ ///
+ /// Returns the document that contains this context
+ ///
+ /// The document that contains this context
+ void GetDocument(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocument document
+ );
+
+ ///
+ /// Enumerates the code contexts associated with this document context
+ ///
+ /// The code contexts associated with this document context
+ void EnumCodeContexts(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugCodeContexts enumContexts
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper32.cs
new file mode 100644
index 0000000..958df77
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper32.cs
@@ -0,0 +1,15 @@
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provide implementations for many interfaces necessary for smart hosting, such as
+ /// the IDebugDocument , IDebugDocumentContext , IDebugDocumentProvider ,
+ /// IDebugDocumentText and IDebugDocumentTextEvents interfaces
+ ///
+ [ComImport]
+ [Guid("51973C26-CB0C-11d0-B5C9-00A0244A0E7A")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentHelper32
+ { }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper64.cs
new file mode 100644
index 0000000..4925b95
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentHelper64.cs
@@ -0,0 +1,15 @@
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provide implementations for many interfaces necessary for smart hosting, such as
+ /// the IDebugDocument , IDebugDocumentContext , IDebugDocumentProvider ,
+ /// IDebugDocumentText and IDebugDocumentTextEvents interfaces
+ ///
+ [ComImport]
+ [Guid("c4c7363c-20fd-47f9-bd82-4855e0150871")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentHelper64
+ { }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentInfo.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentInfo.cs
new file mode 100644
index 0000000..488e9ea
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentInfo.cs
@@ -0,0 +1,34 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides information on a document, which may or may not be instantiated
+ ///
+ [ComImport]
+ [Guid("51973c1f-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentInfo
+ {
+ ///
+ /// Returns the specified document name
+ ///
+ /// The type of document name to return
+ /// String containing the name
+ void GetName(
+ [In] DocumentNameType type,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns a CLSID identifying the document type
+ ///
+ /// A CLSID identifying the document type
+ void GetDocumentClassId(
+ [Out] out Guid clsid
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentProvider.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentProvider.cs
new file mode 100644
index 0000000..c749b6a
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentProvider.cs
@@ -0,0 +1,46 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides the means for instantiating a document on demand
+ ///
+ [ComImport]
+ [Guid("51973c20-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentProvider // : IDebugDocumentInfo
+ {
+ #region IDebugDocumentInfo methods
+
+ ///
+ /// Returns the specified document name
+ ///
+ /// The type of document name to return
+ /// String containing the name
+ void GetName(
+ [In] DocumentNameType type,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns a CLSID identifying the document type
+ ///
+ /// A CLSID identifying the document type
+ void GetDocumentClassId(
+ [Out] out Guid clsid
+ );
+
+ #endregion
+
+ ///
+ /// Causes the document to be instantiated if it does not already exist
+ ///
+ /// The debug document corresponding to the document
+ void GetDocument(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocument document
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentText.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentText.cs
new file mode 100644
index 0000000..af74329
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugDocumentText.cs
@@ -0,0 +1,132 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides access to a text-only version of the debug document
+ ///
+ [ComImport]
+ [Guid("51973c22-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugDocumentText // : IDebugDocument
+ {
+ #region IDebugDocument methods
+
+ #region IDebugDocumentInfo methods
+
+ ///
+ /// Returns the specified document name
+ ///
+ /// The type of document name to return
+ /// String containing the name
+ void GetName(
+ [In] DocumentNameType type,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string name
+ );
+
+ ///
+ /// Returns a CLSID identifying the document type
+ ///
+ /// A CLSID identifying the document type
+ void GetDocumentClassId(
+ [Out] out Guid clsid
+ );
+
+ #endregion
+
+ #endregion
+
+ ///
+ /// Returns the attributes of the document
+ ///
+ /// The text attributes of the document
+ void GetDocumentAttributes(
+ [Out] out TextDocAttrs attrs
+ );
+
+ ///
+ /// Returns the number of lines and number of characters in the document
+ ///
+ /// Number of lines in the document. If this parameter is null ,
+ /// the method does not return a value
+ /// Number of characters in the document. If this parameter is null ,
+ /// the method does not return a value
+ void GetSize(
+ [Out] out uint numLines,
+ [Out] out uint length
+ );
+
+ ///
+ /// Returns the character-position corresponding to the first character of a line
+ ///
+ /// The line number
+ /// The character position within the document of the start of
+ /// line
+ void GetPositionOfLine(
+ [In] uint lineNumber,
+ [Out] out uint position
+ );
+
+ ///
+ /// Returns the line number and, optionally, the character offset within the line that corresponds
+ /// to the given character-position
+ ///
+ /// Start location of the character position range
+ /// The line number of the range
+ /// The character offset of the range within line .
+ /// If this parameter is null , the method does not return a value
+ void GetLineOfPosition(
+ [In] uint position,
+ [Out] out uint lineNumber,
+ [Out] out uint offsetInLine
+ );
+
+ ///
+ /// Retrieves the characters and/or the character attributes associated with a character-position range
+ ///
+ /// Start location of the character position range
+ /// A character text buffer. The buffer must be large enough to hold
+ /// characters. If this parameter is null , the method does not return characters.
+ /// A character attribute buffer. The buffer must be large enough to hold
+ /// characters. If this parameter is null , the method does not return attributes.
+ /// The number of characters/attributes returned. This parameter must be set to
+ /// zero before calling this method.
+ /// Number of characters in the character position range. Also specifies
+ /// the maximum number of characters to return.
+ void GetText(
+ [In] uint position,
+ [In] IntPtr pChars,
+ [In] IntPtr pAttrs,
+ [In] [Out] ref uint length,
+ [In] uint maxChars
+ );
+
+ ///
+ /// Returns the character-position range corresponding to a document context
+ ///
+ /// The document context object
+ /// Start location of the character position range
+ /// Number of characters in the range
+ void GetPositionOfContext(
+ [In] [MarshalAs(UnmanagedType.Interface)] IDebugDocumentContext context,
+ [Out] out uint position,
+ [Out] out uint length
+ );
+
+ ///
+ /// Creates a document context object corresponding to the provided character position range
+ ///
+ /// Start location of the character position range
+ /// Number of characters in the range
+ /// The document context object corresponding to the specified character
+ /// position range
+ void GetContextOfPosition(
+ [In] uint position,
+ [In] uint length,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugDocumentContext context
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugProperty.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugProperty.cs
new file mode 100644
index 0000000..7e8df16
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugProperty.cs
@@ -0,0 +1,17 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Used to describe any hierarchical property of the entity being debugged that has a name, type, and value.
+ /// Most commonly, is used to describe the result of expression evaluation,
+ /// statement evaluation, or register evaluation.
+ ///
+ [ComImport]
+ [Guid("51973c50-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugProperty
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrame.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrame.cs
new file mode 100644
index 0000000..9c62495
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrame.cs
@@ -0,0 +1,61 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Represents a logical stack frame on the thread stack
+ ///
+ [ComImport]
+ [Guid("51973c17-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugStackFrame
+ {
+ ///
+ /// Returns the current code context associated with the stack frame
+ ///
+ /// The code context associated with the stack frame
+ void GetCodeContext(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugCodeContext context
+ );
+
+ ///
+ /// Returns a short or long textual description of the stack frame
+ ///
+ /// Flag, where true returns a long description and
+ /// false returns a short description
+ /// The description of the stack frame
+ void GetDescriptionString(
+ [In] [MarshalAs(UnmanagedType.Bool)] bool longString,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string description
+ );
+
+ ///
+ /// Returns a short or long textual description of the language
+ ///
+ /// Flag, where true returns a long description and
+ /// false returns a short description
+ /// The description of the language
+ void GetLanguageString(
+ [In] [MarshalAs(UnmanagedType.Bool)] bool longString,
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string language
+ );
+
+ ///
+ /// Returns the thread associated with this stack frame
+ ///
+ /// The thread associated with this stack frame
+ void GetThread(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugApplicationThread thread
+ );
+
+ ///
+ /// Returns a property browser for the current frame
+ ///
+ /// A property browser for the current frame
+ void GetDebugProperty(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugProperty property
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSniffer.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSniffer.cs
new file mode 100644
index 0000000..e107105
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSniffer.cs
@@ -0,0 +1,25 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides a way to enumerate the logical stack frames known by a component. Script engines typically
+ /// implement this interface. The process debug manager uses this interface to find all stack frames
+ /// associated with a given thread.
+ ///
+ [ComImport]
+ [Guid("51973c18-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugStackFrameSniffer
+ {
+ ///
+ /// Returns an enumerator of stack frames for the current thread
+ ///
+ /// Enumerator of stack frames for the current thread
+ void EnumStackFrames(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx32.cs
new file mode 100644
index 0000000..8c301ab
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx32.cs
@@ -0,0 +1,34 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides a way to enumerate the logical stack frames known by a component. Script engines typically
+ /// implement this interface. The process debug manager uses this interface to find all stack frames
+ /// associated with a given thread.
+ ///
+ [ComImport]
+ [Guid("51973c19-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugStackFrameSnifferEx32 // : IDebugStackFrameSniffer
+ {
+ #region IDebugStackFrameSniffer methods
+
+ ///
+ /// Returns an enumerator of stack frames for the current thread
+ ///
+ /// Enumerator of stack frames for the current thread
+ void EnumStackFrames(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+
+ #endregion
+
+ void EnumStackFramesEx32(
+ [In] uint minimum,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx64.cs
new file mode 100644
index 0000000..3aa6d91
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugStackFrameSnifferEx64.cs
@@ -0,0 +1,34 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides a way to enumerate the logical stack frames known by a component. Script engines typically
+ /// implement this interface. The process debug manager uses this interface to find all stack frames
+ /// associated with a given thread.
+ ///
+ [ComImport]
+ [Guid("8cd12af4-49c1-4d52-8d8a-c146f47581aa")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugStackFrameSnifferEx64 // : IDebugStackFrameSniffer
+ {
+ #region IDebugStackFrameSniffer methods
+
+ ///
+ /// Returns an enumerator of stack frames for the current thread
+ ///
+ /// Enumerator of stack frames for the current thread
+ void EnumStackFrames(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+
+ #endregion
+
+ void EnumStackFramesEx64(
+ [In] ulong minimum,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugSyncOperation.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugSyncOperation.cs
new file mode 100644
index 0000000..64c872f
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugSyncOperation.cs
@@ -0,0 +1,17 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Allows a script engine to abstract an operation (such as expression evaluation) that needs to be
+ /// performed while nested in a particular blocked thread. The interface also provides a mechanism for
+ /// canceling unresponsive operations.
+ ///
+ [ComImport]
+ [Guid("51973c1a-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugSyncOperation
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall32.cs
new file mode 100644
index 0000000..270c035
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall32.cs
@@ -0,0 +1,17 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The interface is typically implemented by a component that makes
+ /// cross-thread calls with the IDebugThread marshalling implementation provided by
+ /// the process debug manager (PDM).
+ ///
+ [ComImport]
+ [Guid("51973c36-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugThreadCall32
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall64.cs
new file mode 100644
index 0000000..2a87b8e
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IDebugThreadCall64.cs
@@ -0,0 +1,17 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// The interface is typically implemented by a component that makes
+ /// cross-thread calls with the IDebugThread marshalling implementation provided by
+ /// the process debug manager (PDM).
+ ///
+ [ComImport]
+ [Guid("cb3fa335-e979-42fd-9fcf-a7546a0f3905")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IDebugThreadCall64
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugApplicationNodes.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugApplicationNodes.cs
new file mode 100644
index 0000000..7c311fe
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugApplicationNodes.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates child nodes of a node associated with an application
+ ///
+ [ComImport]
+ [Guid("51973c3a-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IEnumDebugApplicationNodes
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugCodeContexts.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugCodeContexts.cs
new file mode 100644
index 0000000..93bb198
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugCodeContexts.cs
@@ -0,0 +1,50 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates the code contexts that correspond to a document context
+ ///
+ [ComImport]
+ [Guid("51973c1d-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IEnumDebugCodeContexts
+ {
+ ///
+ /// Retrieves a specified number of segments in the enumeration sequence
+ ///
+ /// The number of segments to retrieve
+ /// Returns an array of interfaces that
+ /// represents the segments being retrieved
+ /// The actual number of segments fetched by the enumerator
+ void Next(
+ [In] uint count,
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IDebugCodeContext[] contexts,
+ [Out] out uint countFetched
+ );
+
+ ///
+ /// Skips a specified number of segments in an enumeration sequence
+ ///
+ /// Number of segments in the enumeration sequence to skip
+ void Skip(
+ [In] uint count
+ );
+
+ ///
+ /// Resets an enumeration sequence to the beginning
+ ///
+ void Reset();
+
+ ///
+ /// Creates an enumerator that contains the same state as the current enumerator
+ ///
+ /// Returns the interface of
+ /// the clone of the enumerator
+ void Clone(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugCodeContexts enumContexts
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugExpressionContexts.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugExpressionContexts.cs
new file mode 100644
index 0000000..fcc7d9d
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugExpressionContexts.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates a collection of IDebugExpressionContexts objects
+ ///
+ [ComImport]
+ [Guid("51973c40-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IEnumDebugExpressionContexts
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugStackFrames.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugStackFrames.cs
new file mode 100644
index 0000000..6c75645
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumDebugStackFrames.cs
@@ -0,0 +1,50 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates the stack frames corresponding to a thread
+ ///
+ [ComImport]
+ [Guid("51973c1e-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IEnumDebugStackFrames
+ {
+ ///
+ /// Retrieves a specified number of segments in the enumeration sequence
+ ///
+ /// The number of segments to retrieve
+ /// Returns an array of
+ /// interfaces that represents the segments being retrieved
+ /// The actual number of segments fetched by the enumerator
+ void Next(
+ [In] uint count,
+ [Out] out DebugStackFrameDescriptor descriptor,
+ [Out] out uint countFetched
+ );
+
+ ///
+ /// Skips a specified number of segments in an enumeration sequence
+ ///
+ /// Number of segments in the enumeration sequence to skip
+ void Skip(
+ [In] uint count
+ );
+
+ ///
+ /// Resets an enumeration sequence to the beginning
+ ///
+ void Reset();
+
+ ///
+ /// Creates an enumerator that contains the same state as the current enumerator
+ ///
+ /// Returns the interface of
+ /// the clone of the enumerator
+ void Clone(
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IEnumDebugStackFrames enumFrames
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumRemoteDebugApplicationThreads.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumRemoteDebugApplicationThreads.cs
new file mode 100644
index 0000000..e4121a9
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IEnumRemoteDebugApplicationThreads.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Enumerates the running threads in an application
+ ///
+ [ComImport]
+ [Guid("51973c3c-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IEnumRemoteDebugApplicationThreads
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager32.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager32.cs
similarity index 77%
rename from src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager32.cs
rename to src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager32.cs
index fee3744..1983b60 100644
--- a/src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager32.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager32.cs
@@ -1,10 +1,13 @@
-namespace MsieJavaScriptEngine.JsRt.Ie
-{
- using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
///
- /// IProcessDebugManager32 COM interface
+ /// Primary interface to the process debug manager. This interface can create, add, or
+ /// remove a virtual application from a process. It can enumerate stack frames and
+ /// application threads.
///
+ [ComImport]
[Guid("51973C2f-CB0C-11d0-B5C9-00A0244A0E7A")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IProcessDebugManager32
@@ -26,7 +29,7 @@ internal interface IProcessDebugManager32
///
/// The new debug application
/// An engine-defined cookie
- void AddApplication(IDebugApplication32 debugApplication, out uint cookie);
+ uint AddApplication(IDebugApplication32 debugApplication, out uint cookie);
///
/// Removes a debug application
diff --git a/src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager64.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager64.cs
similarity index 77%
rename from src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager64.cs
rename to src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager64.cs
index 413576f..f572297 100644
--- a/src/MsieJavaScriptEngine/JsRt/Ie/IProcessDebugManager64.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProcessDebugManager64.cs
@@ -1,10 +1,13 @@
-namespace MsieJavaScriptEngine.JsRt.Ie
-{
- using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
///
- /// IProcessDebugManager64 COM interface
+ /// Primary interface to the process debug manager. This interface can create, add, or
+ /// remove a virtual application from a process. It can enumerate stack frames and
+ /// application threads.
///
+ [ComImport]
[Guid("56b9fC1C-63A9-4CC1-AC21-087D69A17FAB")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IProcessDebugManager64
@@ -26,7 +29,7 @@ internal interface IProcessDebugManager64
///
/// The new debug application
/// An engine-defined cookie
- void AddApplication(IDebugApplication64 debugApplication, out uint cookie);
+ uint AddApplication(IDebugApplication64 debugApplication, out uint cookie);
///
/// Removes a debug application
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProvideExpressionContexts.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProvideExpressionContexts.cs
new file mode 100644
index 0000000..de68303
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IProvideExpressionContexts.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Provides a way to enumerate expression contexts known by a certain component
+ ///
+ [ComImport]
+ [Guid("51973c41-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IProvideExpressionContexts
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/IRemoteDebugApplicationThread.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IRemoteDebugApplicationThread.cs
new file mode 100644
index 0000000..0cd3e26
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/IRemoteDebugApplicationThread.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Represents a thread of execution within a particular application
+ ///
+ [ComImport]
+ [Guid("51973c37-cb0c-11d0-b5c9-00a0244a0e7a")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IRemoteDebugApplicationThread
+ { }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/NullEnumDebugStackFrames.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/NullEnumDebugStackFrames.cs
new file mode 100644
index 0000000..5cb29a8
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/NullEnumDebugStackFrames.cs
@@ -0,0 +1,30 @@
+#if NETFRAMEWORK
+using System;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ internal class NullEnumDebugStackFrames : IEnumDebugStackFrames
+ {
+ #region IEnumDebugStackFrames implementation
+
+ public void Next(uint count, out DebugStackFrameDescriptor descriptor, out uint countFetched)
+ {
+ descriptor = default(DebugStackFrameDescriptor);
+ countFetched = 0;
+ }
+
+ public void Skip(uint count)
+ { }
+
+ public void Reset()
+ { }
+
+ public void Clone(out IEnumDebugStackFrames enumFrames)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Ie/ProcessDebugManager.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManager.cs
similarity index 52%
rename from src/MsieJavaScriptEngine/JsRt/Ie/ProcessDebugManager.cs
rename to src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManager.cs
index 602032b..2550fa9 100644
--- a/src/MsieJavaScriptEngine/JsRt/Ie/ProcessDebugManager.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManager.cs
@@ -1,9 +1,9 @@
-namespace MsieJavaScriptEngine.JsRt.Ie
-{
- using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
///
- /// ProcessDebugManager COM interface
+ /// Process debug manager
///
[ComImport]
[Guid("78A51822-51F4-11D0-8F20-00805F2CD064")]
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManagerWrapper.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManagerWrapper.cs
new file mode 100644
index 0000000..8ae8f24
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/ProcessDebugManagerWrapper.cs
@@ -0,0 +1,145 @@
+#if NETFRAMEWORK
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Wrapper for process debug manager
+ ///
+ internal sealed class ProcessDebugManagerWrapper
+ {
+ ///
+ /// Flag that the current process debug manager is a 64-bit
+ ///
+ private readonly bool _is64Bit;
+
+ ///
+ /// Instance of 32-bit process debug manager
+ ///
+ private readonly IProcessDebugManager32 _processDebugManager32;
+
+ ///
+ /// Instance of 64-bit process debug manager
+ ///
+ private readonly IProcessDebugManager64 _processDebugManager64;
+
+
+ ///
+ /// Constructs an instance of the wrapper for process debug manager
+ ///
+ /// Instance of 32-bit process debug manager
+ public ProcessDebugManagerWrapper(IProcessDebugManager32 processDebugManager)
+ {
+ _is64Bit = false;
+ _processDebugManager32 = processDebugManager;
+ }
+
+ ///
+ /// Constructs an instance of the wrapper for process debug manager
+ ///
+ /// Instance of 64-bit process debug manager
+ public ProcessDebugManagerWrapper(IProcessDebugManager64 processDebugManager)
+ {
+ _is64Bit = true;
+ _processDebugManager64 = processDebugManager;
+ }
+
+
+ ///
+ /// Creates a wrapper for the process debug manager. A return value indicates whether
+ /// the creation succeeded.
+ ///
+ /// Wrapper for process debug manager
+ /// true if the wrapper was created successfully; otherwise, false .
+ public static bool TryCreate(out ProcessDebugManagerWrapper wrapper)
+ {
+ const string progId = "ProcessDebugManager";
+
+ if (Utils.Is64BitProcess())
+ {
+ IProcessDebugManager64 processDebugManager64;
+ if (ComHelpers.TryCreateComObject(progId, null, out processDebugManager64))
+ {
+ wrapper = new ProcessDebugManagerWrapper(processDebugManager64);
+ return true;
+ }
+ }
+ else
+ {
+ IProcessDebugManager32 processDebugManager32;
+ if (ComHelpers.TryCreateComObject(progId, null, out processDebugManager32))
+ {
+ wrapper = new ProcessDebugManagerWrapper(processDebugManager32);
+ return true;
+ }
+ }
+
+ wrapper = null;
+ return false;
+ }
+
+ ///
+ /// Creates a wrapper for new debug application
+ ///
+ /// The wrapper for new debug application
+ public void CreateApplication(out DebugApplicationWrapper applicationWrapper)
+ {
+ if (_is64Bit)
+ {
+ IDebugApplication64 debugApplication64;
+ _processDebugManager64.CreateApplication(out debugApplication64);
+ applicationWrapper = new DebugApplicationWrapper(debugApplication64);
+ }
+ else
+ {
+ IDebugApplication32 debugApplication32;
+ _processDebugManager32.CreateApplication(out debugApplication32);
+ applicationWrapper = new DebugApplicationWrapper(debugApplication32);
+ }
+ }
+
+ ///
+ /// Adds a new debug application. A return value indicates whether the adding succeeded.
+ ///
+ /// Wrapper for debug application
+ /// An engine-defined cookie
+ /// true if the debug application was added successfully; otherwise, false .
+ public bool TryAddApplication(DebugApplicationWrapper applicationWrapper, out uint cookie)
+ {
+ uint result;
+
+ if (_is64Bit)
+ {
+ IDebugApplication64 application64 = applicationWrapper.DebugApplication64;
+ result = _processDebugManager64.AddApplication(application64, out cookie);
+ }
+ else
+ {
+ IDebugApplication32 application32 = applicationWrapper.DebugApplication32;
+ result = _processDebugManager32.AddApplication(application32, out cookie);
+ }
+
+ bool isSucceeded = ComHelpers.HResult.Succeeded(result);
+
+ return isSucceeded;
+ }
+
+ ///
+ /// Removes a debug application
+ ///
+ /// The cookie of the debug application to remove
+ public void RemoveApplication(uint cookie)
+ {
+ if (_is64Bit)
+ {
+ _processDebugManager64.RemoveApplication(cookie);
+ }
+ else
+ {
+ _processDebugManager32.RemoveApplication(cookie);
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/SourceTextAttrs.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/SourceTextAttrs.cs
new file mode 100644
index 0000000..149e0d2
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/SourceTextAttrs.cs
@@ -0,0 +1,55 @@
+#if NETFRAMEWORK
+using System;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Describe the attributes of a single character of source text
+ ///
+ [Flags]
+ internal enum SourceTextAttrs : ushort
+ {
+ None = 0,
+
+ ///
+ /// The character is part of a language keyword
+ /// (for example, the JavaScript keyword while )
+ ///
+ Keyword = 0x0001,
+
+ ///
+ /// The character is part of a comment block
+ ///
+ Comment = 0x0002,
+
+ ///
+ /// The character is not part of compiled language source text
+ /// (for example, the HTML surrounding a script block)
+ ///
+ NonSource = 0x0004,
+
+ ///
+ /// The character is part of a language operator
+ /// (for example, the arithmetic operator + )
+ ///
+ Operator = 0x0008,
+
+ ///
+ /// The character is part of a language numeric constant
+ /// (for example, the constant 3.14159 )
+ ///
+ Number = 0x0010,
+
+ ///
+ /// The character is part of a language string constant
+ /// (for example, the string "Hello World" )
+ ///
+ String = 0x0020,
+
+ ///
+ /// The character indicates the start of a function block
+ ///
+ FunctionStart = 0x0040
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/Debugging/TextDocAttrs.cs b/src/MsieJavaScriptEngine/ActiveScript/Debugging/TextDocAttrs.cs
new file mode 100644
index 0000000..a402865
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/Debugging/TextDocAttrs.cs
@@ -0,0 +1,35 @@
+#if NETFRAMEWORK
+using System;
+
+namespace MsieJavaScriptEngine.ActiveScript.Debugging
+{
+ ///
+ /// Describe the attributes of the document
+ ///
+ [Flags]
+ internal enum TextDocAttrs : uint
+ {
+ None = 0,
+
+ ///
+ /// The document is read-only
+ ///
+ ReadOnly = 0x00000001,
+
+ ///
+ /// The document is the primary file of this document tree
+ ///
+ TypePrimary = 0x00000002,
+
+ ///
+ /// The document is a worker
+ ///
+ TypeWorker = 0x00000004,
+
+ ///
+ /// The document is a script file
+ ///
+ TypeScript = 0x00000008
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/HostItemBase.cs b/src/MsieJavaScriptEngine/ActiveScript/HostItemBase.cs
new file mode 100644
index 0000000..1df3cf7
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/HostItemBase.cs
@@ -0,0 +1,318 @@
+#if NETFRAMEWORK
+using System;
+#if NET45_OR_GREATER
+using System.Buffers;
+#endif
+using System.Globalization;
+using System.Reflection;
+#if NET40
+
+using PolyfillsForOldDotNet.System.Buffers;
+#endif
+
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Base class of item, that implements interface
+ ///
+ internal abstract class HostItemBase : IReflect
+ {
+ ///
+ /// Target type
+ ///
+ protected readonly Type _type;
+
+ ///
+ /// Target object
+ ///
+ protected readonly object _target;
+
+ ///
+ /// JS engine mode
+ ///
+ protected readonly JsEngineMode _engineMode;
+
+ ///
+ /// Flag for whether to allow the usage of reflection API in the script code
+ ///
+ protected readonly bool _allowReflection;
+
+ ///
+ /// List of fields
+ ///
+ private readonly FieldInfo[] _fields;
+
+ ///
+ /// List of properties
+ ///
+ private readonly PropertyInfo[] _properties;
+
+ ///
+ /// List of methods
+ ///
+ private readonly MethodInfo[] _methods;
+
+ ///
+ /// Gets a target object
+ ///
+ public object Target
+ {
+ get { return _target; }
+ }
+
+
+ ///
+ /// Constructs an instance of the wrapper for item, that implements interface
+ ///
+ /// Target type
+ /// Target object
+ /// JS engine mode
+ /// Flag for whether to allow the usage of reflection API in the script code
+ /// Flag for whether to allow access to members of the instance
+ protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool allowReflection, bool instance)
+ {
+ _type = type;
+ _target = target;
+ _allowReflection = allowReflection;
+ _engineMode = engineMode;
+
+ BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
+ FieldInfo[] fields = _type.GetFields(defaultBindingFlags);
+ PropertyInfo[] properties = _type.GetProperties(defaultBindingFlags);
+ if (properties.Length > 0 && !allowReflection)
+ {
+ properties = GetAvailableProperties(properties);
+ }
+ MethodInfo[] methods = _type.GetMethods(defaultBindingFlags);
+ if (methods.Length > 0 && (properties.Length > 0 || !allowReflection))
+ {
+ methods = GetAvailableMethods(methods, allowReflection);
+ }
+
+ _fields = fields;
+ _properties = properties;
+ _methods = methods;
+ }
+
+
+ private static PropertyInfo[] GetAvailableProperties(PropertyInfo[] properties)
+ {
+ int propertyCount = properties.Length;
+ PropertyInfo[] availableProperties = null;
+ int availablePropertyCount = 0;
+
+ var propertyArrayPool = ArrayPool.Shared;
+ PropertyInfo[] buffer = propertyArrayPool.Rent(propertyCount);
+
+ try
+ {
+ foreach (PropertyInfo property in properties)
+ {
+ if (ReflectionHelpers.IsAllowedProperty(property))
+ {
+ availablePropertyCount++;
+
+ int availablePropertyIndex = availablePropertyCount - 1;
+ buffer[availablePropertyIndex] = property;
+ }
+ }
+
+ if (availablePropertyCount < propertyCount)
+ {
+ if (availablePropertyCount == 0)
+ {
+ return [];
+ }
+
+ availableProperties = new PropertyInfo[availablePropertyCount];
+ Array.Copy(buffer, availableProperties, availablePropertyCount);
+ }
+ else
+ {
+ availableProperties = properties;
+ }
+ }
+ finally
+ {
+ bool clearArray = availablePropertyCount > 0;
+ propertyArrayPool.Return(buffer, clearArray);
+ }
+
+ return availableProperties;
+ }
+
+ private static MethodInfo[] GetAvailableMethods(MethodInfo[] methods, bool allowReflection)
+ {
+ int methodCount = methods.Length;
+ MethodInfo[] availableMethods = null;
+ int availableMethodCount = 0;
+
+ var methodArrayPool = ArrayPool.Shared;
+ MethodInfo[] buffer = methodArrayPool.Rent(methodCount);
+
+ try
+ {
+ foreach (MethodInfo method in methods)
+ {
+ if (ReflectionHelpers.IsFullyFledgedMethod(method)
+ && (allowReflection || ReflectionHelpers.IsAllowedMethod(method)))
+ {
+ availableMethodCount++;
+
+ int availableMethodIndex = availableMethodCount - 1;
+ buffer[availableMethodIndex] = method;
+ }
+ }
+
+ if (availableMethodCount < methodCount)
+ {
+ if (availableMethodCount == 0)
+ {
+ return [];
+ }
+
+ availableMethods = new MethodInfo[availableMethodCount];
+ Array.Copy(buffer, availableMethods, availableMethodCount);
+ }
+ else
+ {
+ availableMethods = methods;
+ }
+ }
+ finally
+ {
+ bool clearArray = availableMethodCount > 0;
+ methodArrayPool.Return(buffer, clearArray);
+ }
+
+ return availableMethods;
+ }
+
+ private FieldInfo GetField(string name)
+ {
+ foreach (FieldInfo field in _fields)
+ {
+ if (field.Name.Equals(name, StringComparison.Ordinal))
+ {
+ return field;
+ }
+ }
+
+ return null;
+ }
+
+ protected abstract object InnerInvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
+ object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters);
+
+ protected object InvokeStandardMember(string name, BindingFlags invokeAttr, Binder binder, object target,
+ object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
+ {
+ BindingFlags processedInvokeAttr = invokeAttr;
+ if (processedInvokeAttr.HasFlag(BindingFlags.GetProperty)
+ || processedInvokeAttr.HasFlag(BindingFlags.SetProperty)
+ || processedInvokeAttr.HasFlag(BindingFlags.PutDispProperty))
+ {
+ FieldInfo field = GetField(name);
+ if (field is not null)
+ {
+ if (processedInvokeAttr.HasFlag(BindingFlags.GetProperty))
+ {
+ processedInvokeAttr &= ~BindingFlags.GetProperty;
+ processedInvokeAttr |= BindingFlags.GetField;
+ }
+ else if (processedInvokeAttr.HasFlag(BindingFlags.SetProperty))
+ {
+ processedInvokeAttr &= ~BindingFlags.SetProperty;
+ processedInvokeAttr |= BindingFlags.SetField;
+ }
+ else if (processedInvokeAttr.HasFlag(BindingFlags.PutDispProperty))
+ {
+ if (field.IsInitOnly)
+ {
+ // Prevents a setting of value to the read-only field
+ return null;
+ }
+
+ processedInvokeAttr &= ~BindingFlags.PutDispProperty;
+ processedInvokeAttr |= BindingFlags.SetField;
+ }
+ }
+ }
+
+ object result = _type.InvokeMember(name, processedInvokeAttr, binder, target,
+ args, modifiers, culture, namedParameters);
+
+ return result;
+ }
+
+ #region IReflect implementation
+
+ Type IReflect.UnderlyingSystemType
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+
+ FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
+ {
+ return _fields;
+ }
+
+ MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotImplementedException();
+ }
+
+ MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
+ {
+ return _methods;
+ }
+
+ PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr)
+ {
+ return _properties;
+ }
+
+ PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder,
+ Type returnType, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotImplementedException();
+ }
+
+ object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
+ object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
+ {
+ return InnerInvokeMember(name, invokeAttr, binder,target, args, modifiers, culture, namedParameters);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/HostObject.cs b/src/MsieJavaScriptEngine/ActiveScript/HostObject.cs
new file mode 100644
index 0000000..ea4dce8
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/HostObject.cs
@@ -0,0 +1,98 @@
+#if NETFRAMEWORK
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Wrapper for object, that implements interface
+ ///
+ internal sealed class HostObject : HostItemBase
+ {
+ ///
+ /// Number of delegate parameters
+ ///
+ private int _delegateParameterCount = int.MinValue;
+
+
+ ///
+ /// Constructs an instance of the wrapper for object, that implements interface
+ ///
+ /// Target object
+ /// JS engine mode
+ /// Flag for whether to allow the usage of reflection API in the script code
+ public HostObject(object target, JsEngineMode engineMode, bool allowReflection)
+ : base(target.GetType(), target, engineMode, allowReflection, true)
+ {
+ var del = _target as Delegate;
+ if (del is not null)
+ {
+ _delegateParameterCount = del.Method.GetParameters().Length;
+ }
+ }
+
+
+ #region HostItemBase overrides
+
+ protected override object InnerInvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
+ object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
+ {
+ object result;
+ object processedTarget = TypeMappingHelpers.MapToHostType(target);
+
+ if (name == SpecialMemberName.Default && processedTarget is Delegate)
+ {
+ var del = (Delegate)processedTarget;
+ int argCount = args.Length;
+ int skippedArgCount = 0;
+ int parameterCount = _delegateParameterCount;
+
+ if (_engineMode == JsEngineMode.Classic && argCount > 0
+ && (argCount - parameterCount) > 0)
+ {
+ skippedArgCount = 1;
+ }
+
+ int processedArgCount = argCount >= skippedArgCount ? argCount - skippedArgCount : 0;
+ if (processedArgCount > parameterCount)
+ {
+ processedArgCount = parameterCount;
+ }
+
+ object[] processedArgs;
+ if (processedArgCount > 0)
+ {
+ processedArgs = args
+ .Skip(skippedArgCount)
+ .Take(processedArgCount)
+ .Select(TypeMappingHelpers.MapToHostType)
+ .ToArray()
+ ;
+ }
+ else
+ {
+ processedArgs = [];
+ }
+
+ result = del.DynamicInvoke(processedArgs);
+ }
+ else
+ {
+ object[] processedArgs = TypeMappingHelpers.MapToHostType(args);
+
+ result = InvokeStandardMember(name, invokeAttr, binder, processedTarget,
+ processedArgs, modifiers, culture, namedParameters);
+ }
+
+ return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/HostType.cs b/src/MsieJavaScriptEngine/ActiveScript/HostType.cs
similarity index 59%
rename from src/MsieJavaScriptEngine/HostType.cs
rename to src/MsieJavaScriptEngine/ActiveScript/HostType.cs
index 4cdbf31..855d02d 100644
--- a/src/MsieJavaScriptEngine/HostType.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/HostType.cs
@@ -1,13 +1,14 @@
-namespace MsieJavaScriptEngine
-{
- using System;
- using System.Globalization;
- using System.Linq;
- using System.Reflection;
+#if NETFRAMEWORK
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
- using Constants;
- using Helpers;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
/// Wrapper for type, that implements interface
///
@@ -17,38 +18,44 @@ internal sealed class HostType : HostItemBase
/// Constructs an instance of the wrapper for type, that implements interface
///
/// Target type
- /// JavaScript engine mode
- public HostType(Type type, JsEngineMode engineMode)
- : base(type, null, engineMode, false)
+ /// JS engine mode
+ /// Flag for whether to allow the usage of reflection API in the script code
+ public HostType(Type type, JsEngineMode engineMode, bool allowReflection)
+ : base(type, null, engineMode, allowReflection, false)
{ }
- #region HostItemBase implementation
+ #region HostItemBase overrides
protected override object InnerInvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
{
- object[] processedArgs = TypeMappingHelpers.MapToHostType(args);
object result;
if (name == SpecialMemberName.Default && invokeAttr.HasFlag(BindingFlags.CreateInstance))
{
+ object[] processedArgs = args;
+
if (_engineMode != JsEngineMode.Classic && processedArgs.Length > 0)
{
processedArgs = processedArgs.Skip(1).ToArray();
}
+ processedArgs = TypeMappingHelpers.MapToHostType(processedArgs);
result = Activator.CreateInstance(_type, processedArgs);
}
else
{
+ object[] processedArgs = TypeMappingHelpers.MapToHostType(args);
+
result = InvokeStandardMember(name, invokeAttr, binder, target,
processedArgs, modifiers, culture, namedParameters);
}
- return TypeMappingHelpers.MapToScriptType(result, _engineMode);
+ return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
}
#endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScript.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScript.cs
index 8fee946..4ce72e2 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScript.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScript.cs
@@ -1,13 +1,15 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// Provides the methods necessary to initialize the scripting engine. The scripting engine must
- /// implement the IActiveScript interface
+ /// Provides the methods necessary to initialize the scripting engine. The scripting engine
+ /// must implement the interface.
///
[ComImport]
[Guid("bb1a2ae1-a4f9-11cf-8f20-00805f2cd064")]
@@ -15,68 +17,76 @@
internal interface IActiveScript
{
///
- /// Informs the scripting engine of the IActiveScriptSite interface site provided by the host.
- /// Call this method before any other IActiveScript interface methods is used
+ /// Informs the scripting engine of the interface site
+ /// provided by the host. Call this method before any other
+ /// interface methods is used.
///
/// The host-supplied script site to be associated with this instance
/// of the scripting engine. The site must be uniquely assigned to this scripting engine
/// instance; it cannot be shared with other scripting engines.
void SetScriptSite(
- [In] IActiveScriptSite site);
+ [In] IActiveScriptSite site
+ );
///
- /// Retrieves the site object associated with the Windows Script engine
+ /// Retrieves the site object associated with the script engine
///
/// Identifier of the requested interface
/// The host's site object
void GetScriptSite(
[In] Guid iid,
- [Out] [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] out IActiveScriptSite site);
+ [Out] [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] out IActiveScriptSite site
+ );
///
/// Puts the scripting engine into the given state. This method can be called from non-base
- /// threads without resulting in a non-base callout to host objects or to the IActiveScriptSite
- /// interface.
+ /// threads without resulting in a non-base callout to host objects or to the
+ /// interface.
///
/// Sets the scripting engine to the given state
void SetScriptState(
- [In] ScriptState state);
+ [In] ScriptState state
+ );
///
/// Retrieves the current state of the scripting engine. This method can be called from
/// non-base threads without resulting in a non-base callout to host objects or to the
- /// IActiveScriptSite interface.
+ /// interface.
///
/// The value indicates the current state of the scripting engine
/// associated with the calling thread
void GetScriptState(
- [Out] out ScriptState state);
+ [Out] out ScriptState state
+ );
///
/// Causes the scripting engine to abandon any currently loaded script, lose its state, and
/// release any interface pointers it has to other objects, thus entering a closed state.
- /// Event sinks, immediately executed script text, and macro invocations that are already in
- /// progress are completed before the state changes (use IActiveScript::InterruptScriptThread to
- /// cancel a running script thread). This method must be called by the creating host before the
- /// interface is released to prevent circular reference problems.
+ /// Event sinks, immediately executed script text, and macro invocations that are already
+ /// in progress are completed before the state changes (use
+ /// to cancel a running script thread).
+ /// This method must be called by the creating host before the interface is released to
+ /// prevent circular reference problems.
///
void Close();
///
/// Adds the name of a root-level item to the scripting engine's name space. A root-level item
- /// is an object with properties and methods, an event source, or all three
+ /// is an object with properties and methods, an event source, or all three.
///
/// The name of the item as viewed from the script. The name must be unique
/// and persistable
/// Flags associated with an item
void AddNamedItem(
[In] [MarshalAs(UnmanagedType.LPWStr)] string name,
- [In] ScriptItemFlags flags);
+ [In] ScriptItemFlags flags
+ );
///
- /// Adds a type library to the name space for the script. This is similar to the #include
- /// directive in C/C++. It allows a set of predefined items such as class definitions, typedefs,
- /// and named constants to be added to the run-time environment available to the script.
+ /// Adds a type library to the name space for the script. This is similar to the
+ /// #include directive in C/C++. It allows a set of predefined items such as
+ /// class definitions, typedefs , and named constants to be added to the run-time
+ /// environment available to the script.
///
/// CLSID of the type library to add
/// Major version number
@@ -86,85 +96,91 @@ void AddTypeLib(
[In] Guid clsId,
[In] uint majorVersion,
[In] uint minorVersion,
- [In] ScriptTypeLibFlags typeLibFlags);
+ [In] ScriptTypeLibFlags typeLibFlags
+ );
///
- /// Retrieves the IDispatch interface for the methods and properties associated with the
- /// currently running script
+ /// Retrieves the IDispatch interface for the methods and properties associated
+ /// with the currently running script
///
/// The name of the item for which the caller needs the associated
- /// dispatch object. If this parameter is NULL, the dispatch object contains as its members
- /// all of the global methods and properties defined by the script. Through the IDispatch
- /// interface and the associated ITypeInfo interface, the host can invoke script methods
- /// or view and modify script variables.
+ /// dispatch object. If this parameter is null , the dispatch object contains as its members
+ /// all of the global methods and properties defined by the script. Through the
+ /// IDispatch interface and the associated interface,
+ /// the host can invoke script methods or view and modify script variables.
/// The object associated with the script's global methods and
- /// properties. If the scripting engine does not support such an object, NULL is returned.
+ /// properties. If the scripting engine does not support such an object, null is returned.
void GetScriptDispatch(
[In] [MarshalAs(UnmanagedType.LPWStr)] string itemName,
- [Out] [MarshalAs(UnmanagedType.IDispatch)] out object dispatch);
+ [Out] [MarshalAs(UnmanagedType.IDispatch)] out object dispatch
+ );
///
/// Retrieves a scripting-engine-defined identifier for the currently executing thread.
- /// The identifier can be used in subsequent calls to script thread execution-control
- /// methods such as the IActiveScript.InterruptScriptThread method.
+ /// The identifier can be used in subsequent calls to script thread execution-control methods
+ /// such as the method.
///
/// The script thread identifier associated with the current thread.
- /// The interpretation of this identifier is left to the scripting engine, but it can be
- /// just a copy of the Windows thread identifier. If the Win32 thread terminates, this
- /// identifier becomes unassigned and can subsequently be assigned to another thread.
+ /// The interpretation of this identifier is left to the scripting engine, but it can be just
+ /// a copy of the Windows thread identifier. If the Win32 thread terminates, this identifier
+ /// becomes unassigned and can subsequently be assigned to another thread.
void GetCurrentScriptThreadId(
- [Out] out uint threadId);
+ [Out] out uint threadId
+ );
///
- /// Retrieves a scripting-engine-defined identifier for the thread associated with the
- /// given Win32 thread
+ /// Retrieves a scripting-engine-defined identifier for the thread associated with the given
+ /// Win32 thread
///
- /// Thread identifier of a running Win32 thread in the
- /// current process. Use the IActiveScript::GetCurrentScriptThreadID function to
- /// retrieve the thread identifier of the currently executing thread
- /// The script thread identifier associated with the given
- /// Win32 thread. The interpretation of this identifier is left to the scripting engine,
- /// but it can be just a copy of the Windows thread identifier. Note that if the Win32
- /// thread terminates, this identifier becomes unassigned and may subsequently be
- /// assigned to another thread.
+ /// Thread identifier of a running Win32 thread in the current
+ /// process. Use the function to retrieve
+ /// the thread identifier of the currently executing thread.
+ /// The script thread identifier associated with the given Win32
+ /// thread. The interpretation of this identifier is left to the scripting engine, but it can
+ /// be just a copy of the Windows thread identifier. Note that if the Win32 thread terminates,
+ /// this identifier becomes unassigned and may subsequently be assigned to another thread.
void GetScriptThreadId(
[In] uint win32ThreadId,
- [Out] out uint scriptThreadId);
+ [Out] out uint scriptThreadId
+ );
///
/// Retrieves the current state of a script thread
///
/// Identifier of the thread for which the state is desired
- /// Thread state
+ /// The state of the indicated thread
void GetScriptThreadState(
[In] uint scriptThreadId,
- [Out] out ScriptThreadState threadState);
+ [Out] out ScriptThreadState threadState
+ );
///
- /// Interrupts the execution of a running script thread (an event sink, an immediate
- /// execution, or a macro invocation). This method can be used to terminate a script that
- /// is stuck (for example, in an infinite loop). It can be called from non-base threads
- /// without resulting in a non-base callout to host objects or to the IActiveScriptSite method.
+ /// Interrupts the execution of a running script thread (an event sink, an immediate execution,
+ /// or a macro invocation). This method can be used to terminate a script that is stuck (for
+ /// example, in an infinite loop). It can be called from non-base threads without resulting in
+ /// a non-base callout to host objects or to the method.
///
- /// Identifier of the thread to interrupt, or one of the
- /// special thread identifier values
- /// The error information that should be reported to the aborted script.
+ /// Identifier of the thread to interrupt
+ /// The error information that should be reported to the aborted script
/// Option flags associated with the interruption
void InterruptScriptThread(
[In] uint scriptThreadId,
- [In] EXCEPINFO exceptionInfo,
- [In] ScriptInterruptFlags flags);
+ [In] ref EXCEPINFO exceptionInfo,
+ [In] ScriptInterruptFlags flags
+ );
///
/// Clones the current scripting engine (minus any current execution state), returning
- /// a loaded scripting engine that has no site in the current thread. The properties of
- /// this new scripting engine will be identical to the properties the original scripting
+ /// a loaded scripting engine that has no site in the current thread. The properties
+ /// of this new scripting engine will be identical to the properties the original scripting
/// engine would be in if it were transitioned back to the initialized state.
///
- /// The cloned scripting engine. The host must create a site and
- /// call the IActiveScript.SetScriptSite method on the new scripting engine before it
+ /// The cloned scripting engine. The host must create a site and call
+ /// the method on the new scripting engine before it
/// will be in the initialized state and, therefore, usable.
void Clone(
- [Out] [MarshalAs(UnmanagedType.Interface)] out IActiveScript script);
+ [Out] [MarshalAs(UnmanagedType.Interface)] out IActiveScript script
+ );
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptError.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptError.cs
index 412d4bd..10d8244 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptError.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptError.cs
@@ -1,11 +1,12 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// An object implementing this interface is passed to the IActiveScriptSite.OnScriptError method
+ /// An object implementing this interface is passed to the method
/// whenever the scripting engine encounters an unhandled error. The host then calls methods on
/// this object to obtain information about the error that occurred.
///
@@ -18,13 +19,14 @@ internal interface IActiveScriptError
/// Retrieves information about an error that occurred while the scripting engine was running
/// a script
///
- /// An EXCEPINFO structure that receives error information
+ /// An EXCEPINFO structure that receives error information
void GetExceptionInfo(
- [Out] out EXCEPINFO exceptionInfo);
+ [Out] out EXCEPINFO exceptionInfo
+ );
///
/// Retrieves the location in the source code where an error occurred while the scripting engine
- /// was running a script.
+ /// was running a script
///
/// A cookie that identifies the context. The interpretation of
/// this parameter depends on the host application.
@@ -33,7 +35,8 @@ void GetExceptionInfo(
void GetSourcePosition(
[Out] out uint sourceContext,
[Out] out uint lineNumber,
- [Out] out int characterPosition);
+ [Out] out int characterPosition
+ );
///
/// Retrieves the line in the source file where an error occurred while a scripting engine
@@ -41,6 +44,8 @@ void GetSourcePosition(
///
/// The line of source code in which the error occurred
void GetSourceLineText(
- [Out] [MarshalAs(UnmanagedType.BStr)] out string sourceLine);
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string sourceLine
+ );
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptGarbageCollector.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptGarbageCollector.cs
new file mode 100644
index 0000000..937e164
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptGarbageCollector.cs
@@ -0,0 +1,24 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Provides a method to start garbage collection. This interface should be implemented by
+ /// Active Script engines that want to clean up their resources.
+ ///
+ [ComImport]
+ [Guid("6aa2c4a0-2b53-11d4-a2a0-00104bd35090")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptGarbageCollector
+ {
+ ///
+ /// The Active Script host calls this method to start garbage collection
+ ///
+ /// The type of garbage collection
+ void CollectGarbage(
+ [In] ScriptGCType type
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse32.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse32.cs
index 919a818..39c5f0f 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse32.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse32.cs
@@ -1,26 +1,23 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// If the Windows Script engine allows raw text code scriptlets to be added to the script
+ /// If the Active Script engine allows raw text code scriptlets to be added to the script
/// or allows expression text to be evaluated at run time, it implements the
- /// IActiveScriptParse interface. For interpreted scripting languages that have no
- /// independent authoring environment, such as VBScript, this provides an alternate
- /// mechanism (other than IPersist*) to get script code into the scripting engine, and
- /// to attach script fragments to various object events.
+ /// interface.
///
///
- /// Before the scripting engine can be used, one of the following methods must be called
- /// : IPersist*::Load, IPersist*::InitNew, or IActiveScriptParse::InitNew. The semantics
- /// of this method are identical to IPersistStreamInit::InitNew, in that this method tells
- /// the scripting engine to initialize itself. Note that it is not valid to call both
- /// IPersist*::InitNew or IActiveScriptParse::InitNew and IPersist*::Load, nor is it valid
- /// to call IPersist*::InitNew, IActiveScriptParse::InitNew, or IPersist*::Load more
- /// than once.
+ /// Before the scripting engine can be used, one of the following methods must be called:
+ /// IPersist.Load , IPersist.InitNew , or . The semantics of
+ /// this method are identical to IPersistStreamInit.InitNew , in that this method tells the scripting
+ /// engine to initialize itself. Note that it is not valid to call both IPersist.InitNew or
+ /// and IPersist.Load , nor is it valid to call
+ /// IPersist.InitNew , , or IPersist.Load more than once.
///
[ComImport]
[Guid("bb1a2ae2-a4f9-11cf-8f20-00805f2cd064")]
@@ -35,35 +32,36 @@ internal interface IActiveScriptParse32
///
/// Adds a code scriptlet to the script. This method is used in environments where the
/// persistent state of the script is intertwined with the host document and the host
- /// is responsible for restoring the script, rather than through an IPersist* interface.
+ /// is responsible for restoring the script, rather than through an IPersist interface.
/// The primary examples are HTML scripting languages that allow scriptlets of code
/// embedded in the HTML document to be attached to intrinsic events (for instance,
- /// ONCLICK="button1.text='Exit'").
+ /// ONCLICK="button1.text='Exit'" ).
///
/// The default name to associate with the scriptlet. If the
- /// scriptlet does not contain naming information (as in the ONCLICK example above),
- /// this name will be used to identify the scriptlet. If this parameter is NULL, the
+ /// scriptlet does not contain naming information (as in the ONCLICK example above),
+ /// this name will be used to identify the scriptlet. If this parameter is null , the
/// scripting engine manufactures a unique name, if necessary.
/// The scriptlet text to add. The interpretation of this string
/// depends on the scripting language.
/// The item name associated with this scriptlet. This parameter,
- /// in addition to pstrSubItemName, identifies the object for which the scriptlet is
- /// an event handler.
+ /// in addition to , identifies the object for which the
+ /// scriptlet is an event handler.
/// The name of a subobject of the named item with which this
/// scriptlet is associated; this name must be found in the named item's type
- /// information. This parameter is NULL if the scriptlet is to be associated with the
- /// named item instead of a subitem. This parameter, in addition to pstrItemName,
- /// identifies the specific object for which the scriptlet is an event handler.
+ /// information. This parameter is null if the scriptlet is to be associated with the
+ /// named item instead of a subitem. This parameter, in addition to
+ /// , identifies the specific object for which the scriptlet
+ /// is an event handler.
/// The name of the event for which the scriptlet is an event
/// handler
- /// The end-of-scriptlet delimiter. When the pstrCode parameter
- /// is parsed from a stream of text, the host typically uses a delimiter, such as two
- /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// The end-of-scriptlet delimiter. When the
+ /// parameter is parsed from a stream of text, the host typically uses a delimiter, such as
+ /// two single quotation marks (''), to detect the end of the scriptlet. This parameter
/// specifies the delimiter that the host used, allowing the scripting engine to
/// provide some conditional primitive preprocessing (for example, replacing a single
/// quotation mark ['] with two single quotation marks for use as a delimiter).
/// Exactly how (and if) the scripting engine makes use of this information depends
- /// on the scripting engine. Set this parameter to NULL if the host did not use a
+ /// on the scripting engine. Set this parameter to null if the host did not use a
/// delimiter to mark the end of the scriptlet.
/// Application-defined value that is used for
/// debugging purposes
@@ -72,10 +70,10 @@ internal interface IActiveScriptParse32
/// Flags associated with the scriptlet
/// Actual name used to identify the scriptlet. This is to be in
/// order of preference: a name explicitly specified in the scriptlet text, the
- /// default name provided in pstrDefaultName, or a unique name synthesized by the
- /// scripting engine.
+ /// default name provided in , or a unique name
+ /// synthesized by the scripting engine.
/// Exception information. This structure should be
- /// filled in if DISP_E_EXCEPTION is returned
+ /// filled in if DISP_E_EXCEPTION is returned
void AddScriptlet(
[In] [MarshalAs(UnmanagedType.LPWStr)] string defaultName,
[In] [MarshalAs(UnmanagedType.LPWStr)] string code,
@@ -87,7 +85,8 @@ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
[In] uint startingLineNumber,
[In] ScriptTextFlags flags,
[Out] [MarshalAs(UnmanagedType.BStr)] out string name,
- [Out] out EXCEPINFO exceptionInfo);
+ [Out] out EXCEPINFO exceptionInfo
+ );
///
/// Parses the given code scriptlet, adding declarations into the namespace and
@@ -96,39 +95,42 @@ [Out] [MarshalAs(UnmanagedType.BStr)] out string name,
/// The scriptlet text to evaluate. The interpretation of this
/// string depends on the scripting language
/// The item name that gives the context in which the
- /// scriptlet is to be evaluated. If this parameter is NULL, the code is evaluated
+ /// scriptlet is to be evaluated. If this parameter is null , the code is evaluated
/// in the scripting engine's global context
/// The context object. This object is reserved for use in a
/// debugging environment, where such a context may be provided by the debugger to
- /// represent an active run-time context. If this parameter is NULL, the engine
- /// uses pstrItemName to identify the context.
- /// The end-of-scriptlet delimiter. When pstrCode is parsed
- /// from a stream of text, the host typically uses a delimiter, such as two single
- /// quotation marks (''), to detect the end of the scriptlet. This parameter specifies
- /// the delimiter that the host used, allowing the scripting engine to provide some
- /// conditional primitive preprocessing (for example, replacing a single quotation
+ /// represent an active run-time context. If this parameter is null , the engine
+ /// uses to identify the context.
+ /// The end-of-scriptlet delimiter. When
+ /// is parsed from a stream of text, the host typically uses a delimiter, such as two
+ /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// specifies the delimiter that the host used, allowing the scripting engine to provide
+ /// some conditional primitive preprocessing (for example, replacing a single quotation
/// mark ['] with two single quotation marks for use as a delimiter). Exactly how
/// (and if) the scripting engine makes use of this information depends on the
- /// scripting engine. Set this parameter to NULL if the host did not use a delimiter
+ /// scripting engine. Set this parameter to null if the host did not use a delimiter
/// to mark the end of the scriptlet.
/// Application-defined value that is used for
/// debugging purposes
/// Zero-based value that specifies which line the
/// parsing will begin at
/// Flags associated with the scriptlet
- /// The results of scriptlet processing, or NULL if the caller
- /// expects no result (that is, the SCRIPTTEXT_ISEXPRESSION value is not set)
- /// The exception information. This structure is filled
- /// if IActiveScriptParse::ParseScriptText returns DISP_E_EXCEPTION.
+ /// The results of scriptlet processing, or null if the caller
+ /// expects no result (that is, the value is
+ /// not set)
+ /// The exception information. This structure is filled if
+ /// returns DISP_E_EXCEPTION .
void ParseScriptText(
[In] [MarshalAs(UnmanagedType.LPWStr)] string code,
[In] [MarshalAs(UnmanagedType.LPWStr)] string itemName,
[In] [MarshalAs(UnmanagedType.IUnknown)] object context,
[In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
- [In] IntPtr pSourceContextCookie,
+ [In] UIntPtr pSourceContextCookie,
[In] uint startingLineNumber,
[In] ScriptTextFlags flags,
[Out] out object result,
- [Out] out EXCEPINFO exceptionInfo);
+ [Out] out EXCEPINFO exceptionInfo
+ );
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse64.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse64.cs
index 9eb9d78..bb98f86 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse64.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParse64.cs
@@ -1,26 +1,23 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// If the Windows Script engine allows raw text code scriptlets to be added to the script
+ /// If the Active Script engine allows raw text code scriptlets to be added to the script
/// or allows expression text to be evaluated at run time, it implements the
- /// IActiveScriptParse interface. For interpreted scripting languages that have no
- /// independent authoring environment, such as VBScript, this provides an alternate
- /// mechanism (other than IPersist*) to get script code into the scripting engine, and
- /// to attach script fragments to various object events.
+ /// interface.
///
///
- /// Before the scripting engine can be used, one of the following methods must be called
- /// : IPersist*::Load, IPersist*::InitNew, or IActiveScriptParse::InitNew. The semantics
- /// of this method are identical to IPersistStreamInit::InitNew, in that this method tells
- /// the scripting engine to initialize itself. Note that it is not valid to call both
- /// IPersist*::InitNew or IActiveScriptParse::InitNew and IPersist*::Load, nor is it valid
- /// to call IPersist*::InitNew, IActiveScriptParse::InitNew, or IPersist*::Load more
- /// than once.
+ /// Before the scripting engine can be used, one of the following methods must be called:
+ /// IPersist.Load , IPersist.InitNew , or . The semantics of
+ /// this method are identical to IPersistStreamInit.InitNew , in that this method tells the scripting
+ /// engine to initialize itself. Note that it is not valid to call both IPersist.InitNew or
+ /// and IPersist.Load , nor is it valid to call
+ /// IPersist.InitNew , , or IPersist.Load more than once.
///
[ComImport]
[Guid("c7ef7658-e1ee-480e-97ea-d52cb4d76d17")]
@@ -35,35 +32,36 @@ internal interface IActiveScriptParse64
///
/// Adds a code scriptlet to the script. This method is used in environments where the
/// persistent state of the script is intertwined with the host document and the host
- /// is responsible for restoring the script, rather than through an IPersist* interface.
+ /// is responsible for restoring the script, rather than through an IPersist interface.
/// The primary examples are HTML scripting languages that allow scriptlets of code
/// embedded in the HTML document to be attached to intrinsic events (for instance,
- /// ONCLICK="button1.text='Exit'").
+ /// ONCLICK="button1.text='Exit'" ).
///
/// The default name to associate with the scriptlet. If the
- /// scriptlet does not contain naming information (as in the ONCLICK example above),
- /// this name will be used to identify the scriptlet. If this parameter is NULL, the
+ /// scriptlet does not contain naming information (as in the ONCLICK example above),
+ /// this name will be used to identify the scriptlet. If this parameter is null , the
/// scripting engine manufactures a unique name, if necessary.
/// The scriptlet text to add. The interpretation of this string
/// depends on the scripting language.
/// The item name associated with this scriptlet. This parameter,
- /// in addition to pstrSubItemName, identifies the object for which the scriptlet is
- /// an event handler.
+ /// in addition to , identifies the object for which the
+ /// scriptlet is an event handler.
/// The name of a subobject of the named item with which this
/// scriptlet is associated; this name must be found in the named item's type
- /// information. This parameter is NULL if the scriptlet is to be associated with the
- /// named item instead of a subitem. This parameter, in addition to pstrItemName,
- /// identifies the specific object for which the scriptlet is an event handler.
+ /// information. This parameter is null if the scriptlet is to be associated with the
+ /// named item instead of a subitem. This parameter, in addition to
+ /// , identifies the specific object for which the scriptlet
+ /// is an event handler.
/// The name of the event for which the scriptlet is an event
/// handler
- /// The end-of-scriptlet delimiter. When the pstrCode parameter
- /// is parsed from a stream of text, the host typically uses a delimiter, such as two
- /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// The end-of-scriptlet delimiter. When the
+ /// parameter is parsed from a stream of text, the host typically uses a delimiter, such as
+ /// two single quotation marks (''), to detect the end of the scriptlet. This parameter
/// specifies the delimiter that the host used, allowing the scripting engine to
/// provide some conditional primitive preprocessing (for example, replacing a single
/// quotation mark ['] with two single quotation marks for use as a delimiter).
/// Exactly how (and if) the scripting engine makes use of this information depends
- /// on the scripting engine. Set this parameter to NULL if the host did not use a
+ /// on the scripting engine. Set this parameter to null if the host did not use a
/// delimiter to mark the end of the scriptlet.
/// Application-defined value that is used for
/// debugging purposes
@@ -72,10 +70,10 @@ internal interface IActiveScriptParse64
/// Flags associated with the scriptlet
/// Actual name used to identify the scriptlet. This is to be in
/// order of preference: a name explicitly specified in the scriptlet text, the
- /// default name provided in pstrDefaultName, or a unique name synthesized by the
- /// scripting engine.
+ /// default name provided in , or a unique name
+ /// synthesized by the scripting engine.
/// Exception information. This structure should be
- /// filled in if DISP_E_EXCEPTION is returned
+ /// filled in if DISP_E_EXCEPTION is returned
void AddScriptlet(
[In] [MarshalAs(UnmanagedType.LPWStr)] string defaultName,
[In] [MarshalAs(UnmanagedType.LPWStr)] string code,
@@ -87,7 +85,8 @@ [In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
[In] uint startingLineNumber,
[In] ScriptTextFlags flags,
[Out] [MarshalAs(UnmanagedType.BStr)] out string name,
- [Out] out EXCEPINFO exceptionInfo);
+ [Out] out EXCEPINFO exceptionInfo
+ );
///
/// Parses the given code scriptlet, adding declarations into the namespace and
@@ -96,39 +95,42 @@ [Out] [MarshalAs(UnmanagedType.BStr)] out string name,
/// The scriptlet text to evaluate. The interpretation of this
/// string depends on the scripting language
/// The item name that gives the context in which the
- /// scriptlet is to be evaluated. If this parameter is NULL, the code is evaluated
+ /// scriptlet is to be evaluated. If this parameter is null , the code is evaluated
/// in the scripting engine's global context
/// The context object. This object is reserved for use in a
/// debugging environment, where such a context may be provided by the debugger to
- /// represent an active run-time context. If this parameter is NULL, the engine
- /// uses pstrItemName to identify the context.
- /// The end-of-scriptlet delimiter. When pstrCode is parsed
- /// from a stream of text, the host typically uses a delimiter, such as two single
- /// quotation marks (''), to detect the end of the scriptlet. This parameter specifies
- /// the delimiter that the host used, allowing the scripting engine to provide some
- /// conditional primitive preprocessing (for example, replacing a single quotation
+ /// represent an active run-time context. If this parameter is null , the engine
+ /// uses to identify the context.
+ /// The end-of-scriptlet delimiter. When
+ /// is parsed from a stream of text, the host typically uses a delimiter, such as two
+ /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// specifies the delimiter that the host used, allowing the scripting engine to provide
+ /// some conditional primitive preprocessing (for example, replacing a single quotation
/// mark ['] with two single quotation marks for use as a delimiter). Exactly how
/// (and if) the scripting engine makes use of this information depends on the
- /// scripting engine. Set this parameter to NULL if the host did not use a delimiter
+ /// scripting engine. Set this parameter to null if the host did not use a delimiter
/// to mark the end of the scriptlet.
/// Application-defined value that is used for
/// debugging purposes
/// Zero-based value that specifies which line the
/// parsing will begin at
/// Flags associated with the scriptlet
- /// The results of scriptlet processing, or NULL if the caller
- /// expects no result (that is, the SCRIPTTEXT_ISEXPRESSION value is not set)
- /// The exception information. This structure is filled
- /// if IActiveScriptParse::ParseScriptText returns DISP_E_EXCEPTION.
+ /// The results of scriptlet processing, or null if the caller
+ /// expects no result (that is, the value is
+ /// not set)
+ /// The exception information. This structure is filled if
+ /// returns DISP_E_EXCEPTION .
void ParseScriptText(
[In] [MarshalAs(UnmanagedType.LPWStr)] string code,
[In] [MarshalAs(UnmanagedType.LPWStr)] string itemName,
[In] [MarshalAs(UnmanagedType.IUnknown)] object context,
[In] [MarshalAs(UnmanagedType.LPWStr)] string delimiter,
- [In] IntPtr pSourceContextCookie,
+ [In] UIntPtr pSourceContextCookie,
[In] uint startingLineNumber,
[In] ScriptTextFlags flags,
[Out] out object result,
- [Out] out EXCEPINFO exceptionInfo);
+ [Out] out EXCEPINFO exceptionInfo
+ );
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParseWrapper.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParseWrapper.cs
deleted file mode 100644
index af07d7b..0000000
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptParseWrapper.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
-
- ///
- /// If the Windows Script engine allows raw text code scriptlets to be added to the script
- /// or allows expression text to be evaluated at run time, it implements the
- /// IActiveScriptParse interface. For interpreted scripting languages that have no
- /// independent authoring environment, such as VBScript, this provides an alternate
- /// mechanism (other than IPersist*) to get script code into the scripting engine, and
- /// to attach script fragments to various object events.
- ///
- ///
- /// Before the scripting engine can be used, one of the following methods must be called
- /// : IPersist*::Load, IPersist*::InitNew, or IActiveScriptParse::InitNew. The semantics
- /// of this method are identical to IPersistStreamInit::InitNew, in that this method tells
- /// the scripting engine to initialize itself. Note that it is not valid to call both
- /// IPersist*::InitNew or IActiveScriptParse::InitNew and IPersist*::Load, nor is it valid
- /// to call IPersist*::InitNew, IActiveScriptParse::InitNew, or IPersist*::Load more
- /// than once.
- ///
- [ComVisible(false)]
- internal interface IActiveScriptParseWrapper : IDisposable
- {
- ///
- /// Initializes the scripting engine.
- ///
- void InitNew();
-
- ///
- /// Adds a code scriptlet to the script. This method is used in environments where the
- /// persistent state of the script is intertwined with the host document and the host
- /// is responsible for restoring the script, rather than through an IPersist* interface.
- /// The primary examples are HTML scripting languages that allow scriptlets of code
- /// embedded in the HTML document to be attached to intrinsic events (for instance,
- /// ONCLICK="button1.text='Exit'").
- ///
- /// The default name to associate with the scriptlet. If the
- /// scriptlet does not contain naming information (as in the ONCLICK example above),
- /// this name will be used to identify the scriptlet. If this parameter is NULL, the
- /// scripting engine manufactures a unique name, if necessary.
- /// The scriptlet text to add. The interpretation of this string
- /// depends on the scripting language
- /// The item name associated with this scriptlet. This parameter,
- /// in addition to pstrSubItemName, identifies the object for which the scriptlet is
- /// an event handler
- /// The name of a subobject of the named item with which this
- /// scriptlet is associated; this name must be found in the named item's type
- /// information. This parameter is NULL if the scriptlet is to be associated with the
- /// named item instead of a subitem. This parameter, in addition to pstrItemName,
- /// identifies the specific object for which the scriptlet is an event handler.
- /// The name of the event for which the scriptlet is an event
- /// handler
- /// The end-of-scriptlet delimiter. When the pstrCode parameter
- /// is parsed from a stream of text, the host typically uses a delimiter, such as two
- /// single quotation marks (''), to detect the end of the scriptlet. This parameter
- /// specifies the delimiter that the host used, allowing the scripting engine to
- /// provide some conditional primitive preprocessing (for example, replacing a single
- /// quotation mark ['] with two single quotation marks for use as a delimiter).
- /// Exactly how (and if) the scripting engine makes use of this information depends
- /// on the scripting engine. Set this parameter to NULL if the host did not use a
- /// delimiter to mark the end of the scriptlet.
- /// Application-defined value that is used for
- /// debugging purposes
- /// Zero-based value that specifies which line the
- /// parsing will begin at
- /// Flags associated with the scriptlet.
- /// Actual name used to identify the scriptlet. This is to be in
- /// order of preference: a name explicitly specified in the scriptlet text, the
- /// default name provided in pstrDefaultName, or a unique name synthesized by the
- /// scripting engine
- string AddScriptlet(
- string defaultName,
- string code,
- string itemName,
- string subItemName,
- string eventName,
- string delimiter,
- IntPtr sourceContextCookie,
- uint startingLineNumber,
- ScriptTextFlags flags);
-
- ///
- /// Parses the given code scriptlet, adding declarations into the namespace and
- /// evaluating code as appropriate
- ///
- /// The scriptlet text to evaluate. The interpretation of this
- /// string depends on the scripting language
- /// The item name that gives the context in which the
- /// scriptlet is to be evaluated. If this parameter is NULL, the code is evaluated
- /// in the scripting engine's global context.
- /// The context object. This object is reserved for use in a
- /// debugging environment, where such a context may be provided by the debugger to
- /// represent an active run-time context. If this parameter is NULL, the engine
- /// uses pstrItemName to identify the context
- /// The end-of-scriptlet delimiter. When pstrCode is parsed
- /// from a stream of text, the host typically uses a delimiter, such as two single
- /// quotation marks (''), to detect the end of the scriptlet. This parameter specifies
- /// the delimiter that the host used, allowing the scripting engine to provide some
- /// conditional primitive preprocessing (for example, replacing a single quotation
- /// mark ['] with two single quotation marks for use as a delimiter). Exactly how
- /// (and if) the scripting engine makes use of this information depends on the
- /// scripting engine. Set this parameter to NULL if the host did not use a delimiter
- /// to mark the end of the scriptlet.
- /// Application-defined value that is used for
- /// debugging purposes
- /// Zero-based value that specifies which line the
- /// parsing will begin at
- /// Flags associated with the scriptlet
- /// The results of scriptlet processing, or NULL if the caller
- /// expects no result (that is, the SCRIPTTEXT_ISEXPRESSION value is not set)
- object ParseScriptText(
- string code,
- string itemName,
- object context,
- string delimiter,
- IntPtr sourceContextCookie,
- uint startingLineNumber,
- ScriptTextFlags flags);
- }
-}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptProperty.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptProperty.cs
index f08db94..0cc4785 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptProperty.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptProperty.cs
@@ -1,23 +1,45 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// The interface is used to get and set
+ /// configuration properties
+ ///
[ComImport]
[Guid("4954e0d0-fbc7-11d1-8410-006008c3fbfc")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IActiveScriptProperty
{
+ ///
+ /// Gets the property that is specified by the parameter
+ ///
+ /// The property value to get
+ /// Not used
+ /// The value of the property
+ /// The method returns an HRESULT
[PreserveSig]
uint GetProperty(
[In] uint dwProperty,
[In] IntPtr pvarIndex,
- [Out] out object pvarValue);
+ [Out] out object pvarValue
+ );
+ ///
+ /// Sets the property that is specified by the parameter
+ ///
+ /// The property value to set
+ /// Not used
+ /// The value of the property
+ /// The method returns an HRESULT
[PreserveSig]
uint SetProperty(
[In] uint dwProperty,
[In] IntPtr pvarIndex,
- [In] [Out] ref object pvarValue);
+ [In] [Out] ref object pvarValue
+ );
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSite.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSite.cs
index 65301ea..494dff0 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSite.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSite.cs
@@ -1,15 +1,17 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
- using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
- /// Implemented by the host to create a site for the Windows Script engine. Usually, this site
- /// will be associated with the container of all the objects that are visible to the script
- /// (for example, the ActiveX Controls). Typically, this container will correspond to the document
- /// or page being viewed. Microsoft Internet Explorer, for example, would create such a container
+ /// Implemented by the host to create a site for the Active Script engine. Usually, this site
+ /// will be associated with the container of all the objects that are visible to the script (for
+ /// example, the ActiveX Controls). Typically, this container will correspond to the document or
+ /// page being viewed. Microsoft Internet Explorer, for example, would create such a container
/// for each HTML page being displayed. Each ActiveX control (or other automation object) on the
/// page, and the scripting engine itself, would be enumerable within this container.
///
@@ -26,84 +28,92 @@ internal interface IActiveScriptSite
/// A variable that receives the locale identifier for user-interface
/// elements displayed by the scripting engine
void GetLcid(
- [Out] out int lcid);
+ [Out] out int lcid
+ );
///
/// Allows the scripting engine to obtain information about an item added with the
- /// IActiveScript.AddNamedItem method
+ /// method
///
/// The name associated with the item, as specified in the
- /// IActiveScript.AddNamedItem method
+ /// method
/// A bit mask specifying what information about the item should be
/// returned. The scripting engine should request the minimum amount of information possible
- /// because some of the return parameters (for example, ITypeInfo) can take considerable
- /// time to load or generate.
- /// A variable that receives a pointer to the IUnknown interface associated
- /// with the given item. The scripting engine can use the IUnknown.QueryInterface method to
- /// obtain the IDispatch interface for the item. This parameter receives null if mask
- /// does not include the ScriptInfo.IUnknown value. Also, it receives null if there is no
- /// object associated with the item name; this mechanism is used to create a simple class when
- /// the named item was added with the ScriptItem.CodeOnly flag set in the
- /// IActiveScript.AddNamedItem method.
- /// A variable that receives a pointer to the ITypeInfo interface
- /// associated with the item. This parameter receives null if mask does not include the
- /// ScriptInfo.ITypeInfo value, or if type information is not available for this item. If type
- /// information is not available, the object cannot source events, and name binding must be
- /// realized with the IDispatch.GetIDsOfNames method. Note that the ITypeInfo interface
- /// retrieved describes the item's coclass (TKIND_COCLASS) because the object may support
- /// multiple interfaces and event interfaces. If the item supports the IProvideMultipleTypeInfo
- /// interface, the ITypeInfo interface retrieved is the same as the index zero ITypeInfo that
- /// would be obtained using the IProvideMultipleTypeInfo.GetInfoOfIndex method.
+ /// because some of the return parameters (for example, ) can take
+ /// considerable time to load or generate.
+ /// A variable that receives a pointer to the IUnknown interface
+ /// associated with the given item. The scripting engine can use the IUnknown.QueryInterface
+ /// method to obtain the IDispatch interface for the item. This parameter receives null if
+ /// mask does not include the value. Also, it receives
+ /// null if there is no object associated with the item name; this mechanism is used to create
+ /// a simple class when the named item was added with the
+ /// flag set in the method.
+ /// A variable that receives a pointer to the
+ /// interface associated with the item. This parameter receives null if mask does not include
+ /// the value, or if type information is not available
+ /// for this item. If type information is not available, the object cannot source events, and
+ /// name binding must be realized with the IDispatch.GetIDsOfNames method. Note that the
+ /// interface retrieved describes the item's coclass (TKIND_COCLASS )
+ /// because the object may support multiple interfaces and event interfaces. If the item supports
+ /// the IProvideMultipleTypeInfo interface, the interface retrieved is
+ /// the same as the index zero that would be obtained using the
+ /// IProvideMultipleTypeInfo.GetInfoOfIndex method.
void GetItemInfo(
[In] [MarshalAs(UnmanagedType.LPWStr)] string name,
[In] ScriptInfoFlags mask,
[In] [Out] ref IntPtr pUnkItem,
- [In] [Out] ref IntPtr pTypeInfo);
+ [In] [Out] ref IntPtr pTypeInfo
+ );
///
/// Retrieves a host-defined string that uniquely identifies the current document version. If
- /// the related document has changed outside the scope of Windows Script (as in the case of an
+ /// the related document has changed outside the scope of Active Script (as in the case of an
/// HTML page being edited with Notepad), the scripting engine can save this along with its
/// persisted state, forcing a recompile the next time the script is loaded.
///
/// The host-defined document version string
void GetDocVersionString(
- [Out] [MarshalAs(UnmanagedType.BStr)] out string version);
+ [Out] [MarshalAs(UnmanagedType.BStr)] out string version
+ );
///
- /// Informs the host that the script has completed execution.
+ /// Informs the host that the script has completed execution
///
- /// A variable that contains the script result, or null if the script
- /// produced no result.
+ /// A variable that contains the script result, or null if the script
+ /// produced no result
/// Contains exception information generated when the script
- /// terminated, or null if no exception was generated
+ /// terminated, or null if no exception was generated
void OnScriptTerminate(
[In] object result,
- [In] EXCEPINFO exceptionInfo);
+ [In] EXCEPINFO exceptionInfo
+ );
///
- /// Informs the host that the scripting engine has changed states.
+ /// Informs the host that the scripting engine has changed states
///
- /// Indicates the new script state.
+ /// Indicates the new script state
void OnStateChange(
- [In] ScriptState state);
+ [In] ScriptState state
+ );
///
- /// Informs the host that an execution error occurred while the engine was running the script.
+ /// Informs the host that an execution error occurred while the engine was running the script
///
/// A host can use this interface to obtain information about the
- /// execution error.
+ /// execution error
void OnScriptError(
- [In] IActiveScriptError error);
+ [In] IActiveScriptError error
+ );
///
- /// Informs the host that the scripting engine has begun executing the script code.
+ /// Informs the host that the scripting engine has begun executing the script code
///
void OnEnterScript();
///
- /// Informs the host that the scripting engine has returned from executing script code.
+ /// Informs the host that the scripting engine has returned from executing script code
///
void OnLeaveScript();
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSiteInterruptPoll.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSiteInterruptPoll.cs
new file mode 100644
index 0000000..42aeb21
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSiteInterruptPoll.cs
@@ -0,0 +1,23 @@
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// The interface allows a host to specify
+ /// that ascript should terminate
+ ///
+ [ComImport]
+ [Guid("539698a0-cdca-11cf-a5eb-00aa0047a063")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IActiveScriptSiteInterruptPoll
+ {
+ ///
+ /// Allows a host to specify that a script should terminate
+ ///
+ /// The method returns an HRESULT
+ [PreserveSig]
+ uint QueryContinue();
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptWrapper.cs b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptWrapper.cs
new file mode 100644
index 0000000..fb1bcd1
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/IActiveScriptWrapper.cs
@@ -0,0 +1,139 @@
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices.ComTypes;
+
+using MsieJavaScriptEngine.ActiveScript.Debugging;
+
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ internal interface IActiveScriptWrapper : IDisposable
+ {
+ ///
+ /// Informs the scripting engine of the interface site
+ /// provided by the host. Call this method before any other
+ /// interface methods is used.
+ ///
+ /// The host-supplied script site to be associated with this instance
+ /// of the scripting engine. The site must be uniquely assigned to this scripting engine
+ /// instance; it cannot be shared with other scripting engines.
+ void SetScriptSite(
+ IActiveScriptSite site
+ );
+
+ ///
+ /// Puts the scripting engine into the given state. This method can be called from non-base
+ /// threads without resulting in a non-base callout to host objects or to the
+ /// interface.
+ ///
+ /// Sets the scripting engine to the given state
+ void SetScriptState(
+ ScriptState state
+ );
+
+ ///
+ /// Adds the name of a root-level item to the scripting engine's name space. A root-level item
+ /// is an object with properties and methods, an event source, or all three.
+ ///
+ /// The name of the item as viewed from the script. The name must be unique
+ /// and persistable
+ /// Flags associated with an item
+ void AddNamedItem(
+ string name,
+ ScriptItemFlags flags
+ );
+
+ ///
+ /// Gets a script dispatch
+ ///
+ /// The object associated with the script's global methods and properties
+ object GetScriptDispatch();
+
+ ///
+ /// Initializes the scripting engine
+ ///
+ void InitNew();
+
+ ///
+ /// Parses the given code scriptlet, adding declarations into the namespace and
+ /// evaluating code as appropriate
+ ///
+ /// The scriptlet text to evaluate. The interpretation of this
+ /// string depends on the scripting language
+ /// The item name that gives the context in which the
+ /// scriptlet is to be evaluated. If this parameter is null , the code is evaluated
+ /// in the scripting engine's global context
+ /// The context object. This object is reserved for use in a
+ /// debugging environment, where such a context may be provided by the debugger to
+ /// represent an active run-time context. If this parameter is null , the engine
+ /// uses to identify the context.
+ /// The end-of-scriptlet delimiter. When
+ /// is parsed from a stream of text, the host typically uses a delimiter, such as two
+ /// single quotation marks (''), to detect the end of the scriptlet. This parameter
+ /// specifies the delimiter that the host used, allowing the scripting engine to provide
+ /// some conditional primitive preprocessing (for example, replacing a single quotation
+ /// mark ['] with two single quotation marks for use as a delimiter). Exactly how
+ /// (and if) the scripting engine makes use of this information depends on the
+ /// scripting engine. Set this parameter to null if the host did not use a delimiter
+ /// to mark the end of the scriptlet.
+ /// Application-defined value that is used for
+ /// debugging purposes
+ /// Zero-based value that specifies which line the
+ /// parsing will begin at
+ /// Flags associated with the scriptlet
+ /// The results of scriptlet processing, or null if the caller expects no
+ /// result (that is, the value is not set)
+ object ParseScriptText(
+ string code,
+ string itemName,
+ object context,
+ string delimiter,
+ UIntPtr sourceContextCookie,
+ uint startingLineNumber,
+ ScriptTextFlags flags
+ );
+
+ ///
+ /// Used by a smart host to delegate the method
+ ///
+ /// The source context as provided to
+ /// or
+ ///
+ /// Character offset relative to start of script text
+ /// Number of characters in this context
+ /// An enumerator of the code contexts in the specified range
+ void EnumCodeContextsOfPosition(
+ UIntPtr sourceContext,
+ uint offset,
+ uint length,
+ out IEnumDebugCodeContexts enumContexts
+ );
+
+ void EnumStackFrames(
+ out IEnumDebugStackFrames enumFrames
+ );
+
+ ///
+ /// Interrupts the execution of a running script thread (an event sink, an immediate execution,
+ /// or a macro invocation). This method can be used to terminate a script that is stuck (for
+ /// example, in an infinite loop). It can be called from non-base threads without resulting in
+ /// a non-base callout to host objects or to the method.
+ ///
+ /// Identifier of the thread to interrupt
+ /// The error information that should be reported to the aborted script
+ /// Option flags associated with the interruption
+ void InterruptScriptThread(
+ uint scriptThreadId,
+ ref EXCEPINFO exceptionInfo,
+ ScriptInterruptFlags flags
+ );
+
+ ///
+ /// The Active Script host calls this method to start garbage collection
+ ///
+ /// The type of garbage collection
+ void CollectGarbage(
+ ScriptGCType type
+ );
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/JScriptRuntimeErrorNumber.cs b/src/MsieJavaScriptEngine/ActiveScript/JScriptRuntimeErrorNumber.cs
new file mode 100644
index 0000000..fd135a0
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/JScriptRuntimeErrorNumber.cs
@@ -0,0 +1,183 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// JScript runtime error numbers
+ ///
+ internal static class JScriptRuntimeErrorNumber
+ {
+ #region Engine
+
+ ///
+ /// Out of memory
+ ///
+ public const int OutOfMemory = 7;
+
+ #endregion
+
+ #region Runtime
+
+ ///
+ /// Out of stack space
+ ///
+ public const int OutOfStackSpace = 28;
+
+ ///
+ /// Cannot assign to this
+ ///
+ public const int CannotAssignToThisKeyword = 5000;
+
+ ///
+ /// Number expected
+ ///
+ public const int NumberExpected = 5001;
+
+ ///
+ /// Function expected
+ ///
+ public const int FunctionExpected = 5002;
+
+ ///
+ /// Cannot assign to a function result
+ ///
+ public const int CannotAssignToFunctionResult = 5003;
+
+ ///
+ /// String expected
+ ///
+ public const int StringExpected = 5005;
+
+ ///
+ /// Date object expected
+ ///
+ public const int DateObjectExpected = 5006;
+
+ ///
+ /// Object expected
+ ///
+ public const int ObjectExpected = 5007;
+
+ ///
+ /// Illegal assignment
+ ///
+ public const int IllegalAssignment = 5008;
+
+ ///
+ /// Undefined identifier
+ ///
+ public const int UndefinedIdentifier = 5009;
+
+ ///
+ /// Boolean expected
+ ///
+ public const int BooleanExpected = 5010;
+
+ ///
+ /// Object member expected
+ ///
+ public const int ObjectMemberExpected = 5012;
+
+ ///
+ /// VBArray expected
+ ///
+ public const int VbArrayExpected = 5013;
+
+ ///
+ /// JavaScript object expected
+ ///
+ public const int JavaScriptObjectExpected = 5014;
+
+ ///
+ /// Enumerator object expected
+ ///
+ public const int EnumeratorObjectExpected = 5015;
+
+ ///
+ /// Regular Expression object expected
+ ///
+ public const int RegularExpressionObjectExpected = 5016;
+
+ ///
+ /// Syntax error in regular expression
+ ///
+ public const int SyntaxErrorInRegularExpression = 5017;
+
+ ///
+ /// Unexpected quantifier
+ ///
+ public const int UnexpectedQuantifier = 5018;
+
+ ///
+ /// Expected ] in regular expression
+ ///
+ public const int ExpectedRightSquareBracketInRegularExpression = 5019;
+
+ ///
+ /// Expected ) in regular expression
+ ///
+ public const int ExpectedRightParenthesisInRegularExpression = 5020;
+
+ ///
+ /// Invalid range in character set
+ ///
+ public const int InvalidRangeInCharacterSet = 5021;
+
+ ///
+ /// Exception thrown and not caught
+ ///
+ public const int ExceptionThrownAndNotCaught = 5022;
+
+ ///
+ /// Function does not have a valid prototype object
+ ///
+ public const int FunctionDoesNotHaveValidPrototypeObject = 5023;
+
+ ///
+ /// The URI to be encoded contains an invalid character
+ ///
+ public const int UriToBeEncodedContainsInvalidCharacter = 5024;
+
+ ///
+ /// The URI to be decoded is not a valid encoding
+ ///
+ public const int UriToBeDecodedIsNotValidEncoding = 5025;
+
+ ///
+ /// The number of fractional digits is out of range
+ ///
+ public const int NumberOfFractionalDigitsIsOutOfRange = 5026;
+
+ ///
+ /// The precision is out of range
+ ///
+ public const int PrecisionOutOfRange = 5027;
+
+ ///
+ /// Array or arguments object expected
+ ///
+ public const int ArrayOrArgumentsObjectExpected = 5028;
+
+ ///
+ /// Array length must be a finite positive integer
+ ///
+ public const int ArrayLengthMustBeFinitePositiveInteger = 5029;
+
+ ///
+ /// Array length must be assigned a finite positive number
+ ///
+ public const int ArrayLengthMustBeAssignedFinitePositiveNumber = 5030;
+
+ ///
+ /// Circular reference in value argument not supported
+ ///
+ public const int CircularReferenceInValueArgumentNotSupported = 5034;
+
+ ///
+ /// Invalid replacer argument
+ ///
+ public const int InvalidReplacerArgument = 5035;
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/JScriptSyntaxErrorNumber.cs b/src/MsieJavaScriptEngine/ActiveScript/JScriptSyntaxErrorNumber.cs
new file mode 100644
index 0000000..76544e7
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/JScriptSyntaxErrorNumber.cs
@@ -0,0 +1,168 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// JScript syntax error numbers
+ ///
+ internal static class JScriptSyntaxErrorNumber
+ {
+ #region Engine
+
+ ///
+ /// Out of memory
+ ///
+ public const int OutOfMemory = 1001;
+
+ #endregion
+
+ #region Compilation
+
+ ///
+ /// Syntax error
+ ///
+ public const int SyntaxError = 1002;
+
+ ///
+ /// Expected :
+ ///
+ public const int ExpectedColon = 1003;
+
+ ///
+ /// Expected ;
+ ///
+ public const int ExpectedSemicolon = 1004;
+
+ ///
+ /// Expected (
+ ///
+ public const int ExpectedLeftParenthesis = 1005;
+
+ ///
+ /// Expected )
+ ///
+ public const int ExpectedRightParenthesis = 1006;
+
+ ///
+ /// Expected ]
+ ///
+ public const int ExpectedRightSquareBracket = 1007;
+
+ ///
+ /// Expected {
+ ///
+ public const int ExpectedLeftCurlyBrace = 1008;
+
+ ///
+ /// Expected }
+ ///
+ public const int ExpectedRightCurlyBrace = 1009;
+
+ ///
+ /// Expected identifier
+ ///
+ public const int ExpectedIdentifier = 1010;
+
+ ///
+ /// Expected =
+ ///
+ public const int ExpectedEqualSign = 1011;
+
+ ///
+ /// Expected /
+ ///
+ public const int ExpectedForwardSlash = 1012;
+
+ ///
+ /// Invalid character
+ ///
+ public const int InvalidCharacter = 1014;
+
+ ///
+ /// Unterminated string constant
+ ///
+ public const int UnterminatedStringConstant = 1015;
+
+ ///
+ /// Unterminated comment
+ ///
+ public const int UnterminatedComment = 1016;
+
+ ///
+ /// return statement outside of function
+ ///
+ public const int ReturnStatementOutsideOfFunction = 1018;
+
+ ///
+ /// Can't have break outside of loop
+ ///
+ public const int CannotHaveBreakStatementOutsideOfLoop = 1019;
+
+ ///
+ /// Can't have continue outside of loop
+ ///
+ public const int CannotHaveContinueStatementOutsideOfLoop = 1020;
+
+ ///
+ /// Expected hexadecimal digit
+ ///
+ public const int ExpectedHexadecimalDigit = 1023;
+
+ ///
+ /// Expected while
+ ///
+ public const int ExpectedWhileStatement = 1024;
+
+ ///
+ /// Label redefined
+ ///
+ public const int LabelRedefined = 1025;
+
+ ///
+ /// Label not found
+ ///
+ public const int LabelNotFound = 1026;
+
+ ///
+ /// default can only appear once in a switch statement
+ ///
+ public const int DefaultStatementCanOnlyAppearOnceInSwitchStatement = 1027;
+
+ ///
+ /// Expected identifier, string or number
+ ///
+ public const int ExpectedIdentifierStringOrNumber = 1028;
+
+ ///
+ /// Expected @end
+ ///
+ public const int ExpectedConditionalCompilationEndStatement = 1029;
+
+ ///
+ /// Conditional compilation is turned off
+ ///
+ public const int ConditionalCompilationTurnedOff = 1030;
+
+ ///
+ /// Expected constant
+ ///
+ public const int ExpectedConstant = 1031;
+
+ ///
+ /// Expected @
+ ///
+ public const int ExpectedAtSign = 1032;
+
+ ///
+ /// Expected catch
+ ///
+ public const int ExpectedCatchStatement = 1033;
+
+ ///
+ /// Throw must be followed by an expression on the same source line
+ ///
+ public const int ThrowMustBeFollowedByExpressionOnSameSourceLine = 1035;
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptGCType.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptGCType.cs
new file mode 100644
index 0000000..49f816a
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptGCType.cs
@@ -0,0 +1,20 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// The type of garbage collection to perform
+ ///
+ internal enum ScriptGCType
+ {
+ ///
+ /// Do normal garbage collection
+ ///
+ Normal = 0,
+
+ ///
+ /// Do exhaustive garbage collection
+ ///
+ Exhaustive = 1
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptHResult.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptHResult.cs
deleted file mode 100644
index 999276c..0000000
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptHResult.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- ///
- /// Common HRESULT Values
- ///
- internal enum ScriptHResult : uint
- {
- ///
- /// Success
- ///
- Ok = 0x00000000,
-
- ///
- /// An argument is not valid
- ///
- InvalidArg = 0x80070057,
-
- ///
- /// The call was not expected (for example, the scripting engine
- /// has not yet been loaded or initialized)
- ///
- Unexpected = 0x8000FFFF
- }
-}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptInfoFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptInfoFlags.cs
index eea4e89..26088b3 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptInfoFlags.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptInfoFlags.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
+#if NETFRAMEWORK
+using System;
+namespace MsieJavaScriptEngine.ActiveScript
+{
[Flags]
internal enum ScriptInfoFlags : uint
{
@@ -11,13 +12,14 @@ internal enum ScriptInfoFlags : uint
None = 0,
///
- /// Returns the IUnknown interface for this item
+ /// Returns the IUnknown interface for this item
///
IUnknown = 1,
///
- /// Returns the ITypeInfo interface for this item
+ /// Returns the ITypeInfo interface for this item
///
ITypeInfo = 2
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptInterruptFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptInterruptFlags.cs
index 1d731e7..04d4bb9 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptInterruptFlags.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptInterruptFlags.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
+#if NETFRAMEWORK
+using System;
+namespace MsieJavaScriptEngine.ActiveScript
+{
///
/// Thread interruption options
///
@@ -23,6 +24,7 @@ internal enum ScriptInterruptFlags : uint
/// Otherwise, the script method is aborted and the error code is returned to the caller; that
/// is, the event source or macro invoker.
///
- RaiseException = 2,
+ RaiseException = 2
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptItemFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptItemFlags.cs
index 54de65e..b627cae 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptItemFlags.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptItemFlags.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
+#if NETFRAMEWORK
+using System;
+namespace MsieJavaScriptEngine.ActiveScript
+{
[Flags]
internal enum ScriptItemFlags : uint
{
@@ -29,11 +30,11 @@ internal enum ScriptItemFlags : uint
///
/// Indicates that the item is a collection of global properties and methods associated
/// with the script. Normally, a scripting engine would ignore the object name (other than
- /// for the purpose of using it as a cookie for the IActiveScriptSite.GetItemInfo method,
+ /// for the purpose of using it as a cookie for the method,
/// or for resolving explicit scoping) and expose its members as global variables and
/// methods. This allows the host to extend the library (run-time functions and so on)
/// available to the script. It is left to the scripting engine to deal with name conflicts
- /// (for example, when two ScriptItemFlags.GlobalMembers items have methods of the same
+ /// (for example, when two items have methods of the same
/// name), although an error should not be returned because of this situation.
///
GlobalMembers = 0x00000008,
@@ -48,7 +49,7 @@ internal enum ScriptItemFlags : uint
///
/// Indicates that the named item represents a code-only object, and that the host has no
- /// IUnknown to be associated with this code-only object. The host only has a name for this
+ /// IUnknown to be associated with this code-only object. The host only has a name for this
/// object. In object-oriented languages such as C++, this flag would create a class.
/// Not all languages support this flag.
///
@@ -60,6 +61,7 @@ internal enum ScriptItemFlags : uint
/// without this flag being set, VBScript will create a separate module for the named item,
/// and C++ might create a separate wrapper class for the named item.
///
- NoCode = 0x00000400,
+ NoCode = 0x00000400
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptLanguageVersion.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptLanguageVersion.cs
index 67e5e4e..d4c90ca 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptLanguageVersion.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptLanguageVersion.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
{
///
- /// Version of script language (see https://msdn.microsoft.com/en-gb/library/hh769820(v=vs.94).aspx)
+ /// Specifies the possible scripting versions
///
internal enum ScriptLanguageVersion
{
@@ -28,6 +29,7 @@ internal enum ScriptLanguageVersion
///
/// ECMAScript 5
///
- EcmaScript5 = 3,
+ EcmaScript5 = 3
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptProperty.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptProperty.cs
index 7f5c1e1..6d83292 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptProperty.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptProperty.cs
@@ -1,4 +1,5 @@
-namespace MsieJavaScriptEngine.ActiveScript
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
{
///
/// Script property (see https://msdn.microsoft.com/en-us/subscriptions/downloads/cc512774(v=vs.94).aspx)
@@ -7,7 +8,7 @@ internal enum ScriptProperty : uint
{
///
/// Forces the scripting engine to divide in integer mode instead of floating point mode.
- /// The default value is False.
+ /// The default value is false .
///
IntegerMode = 0x00003000,
@@ -29,4 +30,5 @@ internal enum ScriptProperty : uint
///
InvokeVersioning = 0x00004000
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptState.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptState.cs
index 3d87167..a8b8a92 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptState.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptState.cs
@@ -1,44 +1,46 @@
-namespace MsieJavaScriptEngine.ActiveScript
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
{
///
- /// Contains named constant values that specify the state of a scripting engine
+ /// Specifies the state of a scripting engine
///
internal enum ScriptState : uint
{
///
- /// Script has just been created, but has not yet been initialized using an IPersist*
- /// interface and IActiveScript.SetScriptSite
+ /// Script has just been created, but has not yet been initialized using an IPersist*
+ /// interface and
///
Uninitialized = 0,
+ ///
+ /// Script has been initialized, but is not running (connecting to other objects or
+ /// sinking events) or executing any code. Code can be queried for execution by
+ /// calling the IActiveScriptParse.ParseScriptText method.
+ ///
+ Initialized = 1,
+
///
/// Script can execute code, but is not yet sinking the events of objects added by
- /// the IActiveScript.AddNamedItem method
+ /// the IActiveScript.AddNamedItem method
///
- Started = 1,
+ Started = 2,
///
/// Script is loaded and connected for sinking events
///
- Connected = 2,
+ Connected = 3,
///
/// Script is loaded and has a run-time execution state, but is temporarily
/// disconnected from sinking events
///
- Disconnected = 3,
+ Disconnected = 4,
///
/// Script has been closed. The scripting engine no longer works and returns errors
/// for most methods
///
- Closed = 4,
-
- ///
- /// Script has been initialized, but is not running (connecting to other objects or
- /// sinking events) or executing any code. Code can be queried for execution by
- /// calling the IActiveScriptParse.ParseScriptText method.
- ///
- Initialized = 5
+ Closed = 5
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptTextFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptTextFlags.cs
index 050f772..d8c9ba9 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptTextFlags.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptTextFlags.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
+#if NETFRAMEWORK
+using System;
+namespace MsieJavaScriptEngine.ActiveScript
+{
[Flags]
internal enum ScriptTextFlags : uint
{
@@ -24,12 +25,15 @@ internal enum ScriptTextFlags : uint
///
/// Indicates that the code added during this call should be saved if the scripting engine is saved
- /// (for example, through a call to IPersist*::Save), or if the scripting engine is reset by way of
+ /// (for example, through a call to IPersist*.Save ), or if the scripting engine is reset by way of
/// a transition back to the initialized state. For more information about this state, see Script
/// Engine States
///
IsPersistent = 0x00000040,
+
HostManagesSource = 0x00000080,
- IsCrossDomain = 0x00000100,
+
+ IsCrossDomain = 0x00000100
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadId.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadId.cs
new file mode 100644
index 0000000..541f3ff
--- /dev/null
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadId.cs
@@ -0,0 +1,25 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
+{
+ ///
+ /// Used to specify the type of thread
+ ///
+ internal static class ScriptThreadId
+ {
+ ///
+ /// The currently executing thread
+ ///
+ public const uint Current = 0xFFFFFFFD;
+
+ ///
+ /// The base thread; that is, the thread in which the scripting engine was instantiated
+ ///
+ public const uint Base = 0xFFFFFFFE;
+
+ ///
+ /// All threads
+ ///
+ public const uint All = 0xFFFFFFFF;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadState.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadState.cs
index 35fbcbc..bcafbb9 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadState.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptThreadState.cs
@@ -1,8 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.ActiveScript
{
///
- /// Contains named constant values that specify the state of a thread in a scripting
- /// engine. This enumeration is used by the IActiveScript::GetScriptThreadState method
+ /// Specifies the state of a thread in a scripting engine
///
internal enum ScriptThreadState : uint
{
@@ -16,6 +16,7 @@ internal enum ScriptThreadState : uint
/// Specified thread is actively servicing a scripted event, processing
/// immediately executed script text, or running a script macro
///
- Running = 1,
+ Running = 1
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/ActiveScript/ScriptTypeLibFlags.cs b/src/MsieJavaScriptEngine/ActiveScript/ScriptTypeLibFlags.cs
index ce92732..ba20786 100644
--- a/src/MsieJavaScriptEngine/ActiveScript/ScriptTypeLibFlags.cs
+++ b/src/MsieJavaScriptEngine/ActiveScript/ScriptTypeLibFlags.cs
@@ -1,7 +1,8 @@
-namespace MsieJavaScriptEngine.ActiveScript
-{
- using System;
+#if NETFRAMEWORK
+using System;
+namespace MsieJavaScriptEngine.ActiveScript
+{
[Flags]
internal enum ScriptTypeLibFlags : uint
{
@@ -18,6 +19,7 @@ internal enum ScriptTypeLibFlags : uint
///
/// Not documented
///
- IsPersistent = 0x00000040,
+ IsPersistent = 0x00000040
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Constants/ClassId.cs b/src/MsieJavaScriptEngine/Constants/ClassId.cs
new file mode 100644
index 0000000..715c435
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Constants/ClassId.cs
@@ -0,0 +1,14 @@
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.Constants
+{
+ ///
+ /// Class identifiers
+ ///
+ internal static class ClassId
+ {
+ public const string Classic = "{f414c260-6ac0-11cf-b6d1-00aa00bbbb58}";
+
+ public const string Chakra = "{16d51579-a30b-4c8b-a276-0ff4dc41e755}";
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Constants/ComErrorCode.cs b/src/MsieJavaScriptEngine/Constants/ComErrorCode.cs
index 1da41b0..26b1222 100644
--- a/src/MsieJavaScriptEngine/Constants/ComErrorCode.cs
+++ b/src/MsieJavaScriptEngine/Constants/ComErrorCode.cs
@@ -1,12 +1,33 @@
-namespace MsieJavaScriptEngine.Constants
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.Constants
{
///
/// COM error codes
///
internal static class ComErrorCode
{
- public const int ElementNotFound = unchecked((int)(0x8002802B));
+ // ReSharper disable InconsistentNaming
+ public const int SEVERITY_SUCCESS = 0;
+ public const int SEVERITY_ERROR = 1;
- public const int ClassNotRegistered = unchecked((int)(0x80040154));
+ public const int FACILITY_NULL = 0;
+ public const int FACILITY_RPC = 1;
+ public const int FACILITY_DISPATCH = 2;
+ public const int FACILITY_STORAGE = 3;
+ public const int FACILITY_ITF = 4;
+ public const int FACILITY_WIN32 = 7;
+ public const int FACILITY_WINDOWS = 8;
+ public const int FACILITY_CONTROL = 10;
+ public const int FACILITY_INTERNET = 12;
+ public const int FACILITY_URT = 19;
+
+ public const int S_OK = 0;
+ public const int S_FALSE = 1;
+
+ public const int E_ABORT = unchecked((int)0x80004004);
+ public const int E_ELEMENT_NOT_FOUND = unchecked((int)0x8002802B);
+ public const int E_CLASS_NOT_REGISTERED = unchecked((int)0x80040154);
+ // ReSharper restore InconsistentNaming
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Constants/DllName.cs b/src/MsieJavaScriptEngine/Constants/DllName.cs
index 3aca275..74bf627 100644
--- a/src/MsieJavaScriptEngine/Constants/DllName.cs
+++ b/src/MsieJavaScriptEngine/Constants/DllName.cs
@@ -5,6 +5,8 @@
///
internal static class DllName
{
+ public const string JScript = "jscript.dll";
+
public const string JScript9 = "jscript9.dll";
public const string Chakra = "chakra.dll";
diff --git a/src/MsieJavaScriptEngine/Constants/JsErrorCategory.cs b/src/MsieJavaScriptEngine/Constants/JsErrorCategory.cs
new file mode 100644
index 0000000..58f6208
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Constants/JsErrorCategory.cs
@@ -0,0 +1,14 @@
+namespace MsieJavaScriptEngine.Constants
+{
+ internal static class JsErrorCategory
+ {
+ public const string Unknown = "Unknown error";
+ public const string Compilation = "Compilation error";
+ public const string Runtime = "Runtime error";
+ public const string Interrupted = "Interrupted error";
+ public const string Usage = "Usage error";
+ public const string Engine = "Engine error";
+ public const string EngineLoad = "Engine load error";
+ public const string Fatal = "Fatal error";
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Constants/JsErrorType.cs b/src/MsieJavaScriptEngine/Constants/JsErrorType.cs
new file mode 100644
index 0000000..7c90417
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Constants/JsErrorType.cs
@@ -0,0 +1,15 @@
+namespace MsieJavaScriptEngine.Constants
+{
+ internal static class JsErrorType
+ {
+ public const string Common = "Error";
+ public const string Eval = "EvalError";
+ public const string Internal = "InternalError";
+ public const string Range = "RangeError";
+ public const string Reference = "ReferenceError";
+ public const string RegExp = "RegExpError";
+ public const string Syntax = "SyntaxError";
+ public const string Type = "TypeError";
+ public const string URI = "URIError";
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Constants/SpecialMemberName.cs b/src/MsieJavaScriptEngine/Constants/SpecialMemberName.cs
index 5415c70..9febe74 100644
--- a/src/MsieJavaScriptEngine/Constants/SpecialMemberName.cs
+++ b/src/MsieJavaScriptEngine/Constants/SpecialMemberName.cs
@@ -1,4 +1,5 @@
-namespace MsieJavaScriptEngine.Constants
+#if NETFRAMEWORK
+namespace MsieJavaScriptEngine.Constants
{
///
/// Special member names
@@ -7,4 +8,5 @@ internal static class SpecialMemberName
{
public const string Default = "[DISPID=0]";
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Extensions/ExceptionExtensions.cs b/src/MsieJavaScriptEngine/Extensions/ExceptionExtensions.cs
new file mode 100644
index 0000000..9f23504
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Extensions/ExceptionExtensions.cs
@@ -0,0 +1,29 @@
+#if NET40
+using System;
+using System.Reflection;
+
+namespace MsieJavaScriptEngine.Extensions
+{
+ ///
+ /// Exception extensions
+ ///
+ internal static class ExceptionExtensions
+ {
+ ///
+ /// Preserves a stack trace of exception
+ ///
+ /// The exception
+ public static void PreserveStackTrace(this Exception source)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ MethodInfo preserveStackTraceMethodInfo = typeof(Exception).GetMethod("InternalPreserveStackTrace",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+ preserveStackTraceMethodInfo.Invoke(source, null);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Extensions/StringExtensions.cs b/src/MsieJavaScriptEngine/Extensions/StringExtensions.cs
new file mode 100644
index 0000000..ad006d1
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Extensions/StringExtensions.cs
@@ -0,0 +1,165 @@
+using System;
+
+namespace MsieJavaScriptEngine.Extensions
+{
+ ///
+ /// Extensions for String
+ ///
+ internal static class StringExtensions
+ {
+ ///
+ /// Array of strings used to find the newline
+ ///
+ private static readonly string[] _newLineStrings = ["\r\n", "\r", "\n"];
+
+
+ ///
+ /// Returns a value indicating whether the specified quoted string occurs within this string
+ ///
+ /// Instance of
+ /// The string without quotes to seek
+ /// true if the quoted value occurs within this string; otherwise, false
+ public static bool ContainsQuotedValue(this string source, string value)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (value is null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ bool result = source.Contains("'" + value + "'") || source.Contains("\"" + value + "\"");
+
+ return result;
+ }
+
+ ///
+ /// Removes leading occurrence of the specified string from the current object
+ ///
+ /// Instance of
+ /// An string to remove
+ /// The string that remains after removing of the specified string from the start of
+ /// the current string
+ public static string TrimStart(this string source, string trimString)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (trimString is null)
+ {
+ throw new ArgumentNullException(nameof(trimString));
+ }
+
+ if (source.Length == 0 || trimString.Length == 0)
+ {
+ return source;
+ }
+
+ string result = source;
+ if (source.StartsWith(trimString, StringComparison.Ordinal))
+ {
+ result = source.Substring(trimString.Length);
+ }
+
+ return result;
+ }
+#if NETFRAMEWORK
+
+ ///
+ /// Converts a first letter of string to capital
+ ///
+ /// Instance of
+ /// The string starting with a capital letter
+ public static string CapitalizeFirstLetter(this string source)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ int length = source.Length;
+ if (length == 0)
+ {
+ return source;
+ }
+
+ string result;
+ char firstCharacter = source[0];
+
+ if (char.IsLower(firstCharacter))
+ {
+ result = char.ToUpperInvariant(firstCharacter).ToString();
+ if (length > 1)
+ {
+ result += source.Substring(1);
+ }
+ }
+ else
+ {
+ result = source;
+ }
+
+ return result;
+ }
+#endif
+
+ ///
+ /// Splits a string into lines
+ ///
+ /// Instance of
+ /// to omit empty array
+ /// elements from the array returned; or to include empty
+ /// array elements in the array returned
+ /// An array of lines
+ public static string[] SplitToLines(this string source, StringSplitOptions options)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ string[] result = source.Split(_newLineStrings, options);
+
+ return result;
+ }
+
+ ///
+ /// Gets a character at the specified index from the string.
+ /// A return value indicates whether the receiving succeeded.
+ ///
+ /// The source string
+ /// The zero-based index of the character
+ /// When this method returns, contains the character from the string,
+ /// if the receiving succeeded, or null character if the receiving failed.
+ /// The receiving fails if the index out of bounds.
+ /// true if the character was received successfully; otherwise, false
+ public static bool TryGetChar(this string source, int index, out char result)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ bool isSuccess;
+ int length = source.Length;
+
+ if (length > 0 && index >= 0 && index < length)
+ {
+ result = source[index];
+ isSuccess = true;
+ }
+ else
+ {
+ result = '\0';
+ isSuccess = false;
+ }
+
+ return isSuccess;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Extensions/TypeExtensions.cs b/src/MsieJavaScriptEngine/Extensions/TypeExtensions.cs
new file mode 100644
index 0000000..f3b5ba3
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Extensions/TypeExtensions.cs
@@ -0,0 +1,102 @@
+using System;
+#if NETSTANDARD1_3
+using System.Reflection;
+#endif
+
+namespace MsieJavaScriptEngine.Extensions
+{
+ ///
+ /// Type extensions
+ ///
+ internal static class TypeExtensions
+ {
+ ///
+ /// Gets a underlying type code of the specified
+ ///
+ /// The type whose underlying type code to get
+ /// The code of the underlying type
+ public static TypeCode GetTypeCode(this Type source)
+ {
+ TypeCode typeCode;
+
+#if NETSTANDARD1_3
+ if (source is null)
+ {
+ typeCode = TypeCode.Empty;
+ }
+ else if (source == typeof(bool))
+ {
+ typeCode = TypeCode.Boolean;
+ }
+ else if (source == typeof(char))
+ {
+ typeCode = TypeCode.Char;
+ }
+ else if (source == typeof(sbyte))
+ {
+ typeCode = TypeCode.SByte;
+ }
+ else if (source == typeof(byte))
+ {
+ typeCode = TypeCode.Byte;
+ }
+ else if (source == typeof(short))
+ {
+ typeCode = TypeCode.Int16;
+ }
+ else if (source == typeof(ushort))
+ {
+ typeCode = TypeCode.UInt16;
+ }
+ else if (source == typeof(int))
+ {
+ typeCode = TypeCode.Int32;
+ }
+ else if (source == typeof(uint))
+ {
+ typeCode = TypeCode.UInt32;
+ }
+ else if (source == typeof(long))
+ {
+ typeCode = TypeCode.Int64;
+ }
+ else if (source == typeof(ulong))
+ {
+ typeCode = TypeCode.UInt64;
+ }
+ else if (source == typeof(float))
+ {
+ typeCode = TypeCode.Single;
+ }
+ else if (source == typeof(double))
+ {
+ typeCode = TypeCode.Double;
+ }
+ else if (source == typeof(decimal))
+ {
+ typeCode = TypeCode.Decimal;
+ }
+ else if (source == typeof(DateTime))
+ {
+ typeCode = TypeCode.DateTime;
+ }
+ else if (source == typeof(string))
+ {
+ typeCode = TypeCode.String;
+ }
+ else if (source.GetTypeInfo().IsEnum)
+ {
+ typeCode = GetTypeCode(Enum.GetUnderlyingType(source));
+ }
+ else
+ {
+ typeCode = TypeCode.Object;
+ }
+#else
+ typeCode = Type.GetTypeCode(source);
+#endif
+
+ return typeCode;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/GlobalUsings.cs b/src/MsieJavaScriptEngine/GlobalUsings.cs
new file mode 100644
index 0000000..70bfca9
--- /dev/null
+++ b/src/MsieJavaScriptEngine/GlobalUsings.cs
@@ -0,0 +1,5 @@
+#if NET10_0_OR_GREATER
+global using Lock = System.Threading.Lock;
+#else
+global using Lock = System.Object;
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/CallStackItem.cs b/src/MsieJavaScriptEngine/Helpers/CallStackItem.cs
new file mode 100644
index 0000000..535a6e3
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Helpers/CallStackItem.cs
@@ -0,0 +1,56 @@
+namespace MsieJavaScriptEngine.Helpers
+{
+ ///
+ /// Script call stack item
+ ///
+ internal sealed class CallStackItem
+ {
+ ///
+ /// Gets or sets a function name
+ ///
+ public string FunctionName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a document name
+ ///
+ public string DocumentName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a line number
+ ///
+ public int LineNumber
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a column number
+ ///
+ public int ColumnNumber
+ {
+ get;
+ set;
+ }
+
+
+ ///
+ /// Constructs an instance of the script call stack item
+ ///
+ public CallStackItem()
+ {
+ FunctionName = string.Empty;
+ DocumentName = string.Empty;
+ LineNumber = 0;
+ ColumnNumber = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/ComHelpers.cs b/src/MsieJavaScriptEngine/Helpers/ComHelpers.cs
index b1ef7d9..62823c1 100644
--- a/src/MsieJavaScriptEngine/Helpers/ComHelpers.cs
+++ b/src/MsieJavaScriptEngine/Helpers/ComHelpers.cs
@@ -1,8 +1,11 @@
-namespace MsieJavaScriptEngine.Helpers
-{
- using System;
- using System.Runtime.InteropServices;
+#if NETFRAMEWORK
+using System;
+using System.Runtime.InteropServices;
+
+using MsieJavaScriptEngine.Constants;
+namespace MsieJavaScriptEngine.Helpers
+{
///
/// COM helpers
///
@@ -24,24 +27,30 @@ public static IntPtr CreateInstanceByClsid(Guid clsid)
return pInterface;
}
- public static IntPtr CreateInstanceByProgId(string progId)
+ public static bool TryCreateComObject(string progId, string serverName, out T obj) where T : class
{
- Guid clsid = ClsidFromProgId(progId);
- IntPtr pInterface = CreateInstanceByClsid(clsid);
+ Type type;
+ if (!TryGetComType(progId, serverName, out type))
+ {
+ obj = null;
+ return false;
+ }
- return pInterface;
+ obj = Activator.CreateInstance(type) as T;
+
+ return obj is not null;
}
- private static Guid ClsidFromProgId(string progId)
+ public static bool TryGetComType(string progId, string serverName, out Type type)
{
Guid clsid;
+ type = Guid.TryParseExact(progId, "B", out clsid) ?
+ Type.GetTypeFromCLSID(clsid, serverName)
+ :
+ Type.GetTypeFromProgID(progId, serverName)
+ ;
- if (!Guid.TryParseExact(progId, "B", out clsid))
- {
- HResult.Check(NativeMethods.CLSIDFromProgID(progId, out clsid));
- }
-
- return clsid;
+ return type is not null;
}
public static IntPtr QueryInterface(IntPtr pUnknown)
@@ -54,6 +63,15 @@ public static IntPtr QueryInterface(IntPtr pUnknown)
return pInterface;
}
+ public static IntPtr QueryInterfaceNoThrow(IntPtr pUnknown)
+ {
+ IntPtr pInterface;
+ Guid iid = typeof(T).GUID;
+ int result = Marshal.QueryInterface(pUnknown, ref iid, out pInterface);
+
+ return result == ComErrorCode.S_OK ? pInterface : IntPtr.Zero;
+ }
+
public static void ReleaseAndEmpty(ref IntPtr pUnk)
{
if (pUnk != IntPtr.Zero)
@@ -63,32 +81,6 @@ public static void ReleaseAndEmpty(ref IntPtr pUnk)
}
}
- public static void ReleaseComObject(ref T obj, bool final = false) where T : class
- {
- if (obj != null && Marshal.IsComObject(obj))
- {
- if (final)
- {
- Marshal.FinalReleaseComObject(obj);
- }
- else
- {
- Marshal.ReleaseComObject(obj);
- }
- }
-
- obj = null;
- }
-
- #region Private methods
-
- private static int UnsignedAsSigned(uint value)
- {
- return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
- }
-
- #endregion
-
#region Nested type: NativeMethods
private static class NativeMethods
@@ -101,12 +93,6 @@ public static extern uint CoCreateInstance(
[In] ref Guid iid,
[Out] out IntPtr pInterface
);
-
- [DllImport("ole32.dll", ExactSpelling = true)]
- public static extern uint CLSIDFromProgID(
- [In] [MarshalAs(UnmanagedType.LPWStr)] string progId,
- [Out] out Guid clsid
- );
}
#endregion
@@ -115,14 +101,9 @@ [Out] out Guid clsid
public static class HResult
{
- // ReSharper disable InconsistentNaming
- public const int SEVERITY_SUCCESS = 0;
- public const int SEVERITY_ERROR = 1;
- // ReSharper restore InconsistentNaming
-
public static void Check(uint result)
{
- Check(UnsignedAsSigned(result));
+ Check(NumericHelpers.UnsignedAsSigned(result));
}
public static void Check(int result)
@@ -130,9 +111,14 @@ public static void Check(int result)
Marshal.ThrowExceptionForHR(result);
}
+ public static bool Succeeded(uint result)
+ {
+ return GetSeverity(result) == ComErrorCode.SEVERITY_SUCCESS;
+ }
+
public static int GetSeverity(uint result)
{
- return GetSeverity(UnsignedAsSigned(result));
+ return GetSeverity(NumericHelpers.UnsignedAsSigned(result));
}
public static int GetSeverity(int result)
@@ -142,7 +128,7 @@ public static int GetSeverity(int result)
public static int GetFacility(uint result)
{
- return GetFacility(UnsignedAsSigned(result));
+ return GetFacility(NumericHelpers.UnsignedAsSigned(result));
}
public static int GetFacility(int result)
@@ -152,7 +138,7 @@ public static int GetFacility(int result)
public static int GetCode(uint result)
{
- return GetCode(UnsignedAsSigned(result));
+ return GetCode(NumericHelpers.UnsignedAsSigned(result));
}
public static int GetCode(int result)
@@ -162,10 +148,11 @@ public static int GetCode(int result)
public static int MakeResult(int severity, int facility, int code)
{
- return UnsignedAsSigned((uint)(code & 0xFFFF) | ((uint)(facility & 0x1FFF) << 16) | ((uint)(severity & 0x1) << 31));
+ return NumericHelpers.UnsignedAsSigned((uint)(code & 0xFFFF) | ((uint)(facility & 0x1FFF) << 16) | ((uint)(severity & 0x1) << 31));
}
}
#endregion
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/CommonRegExps.cs b/src/MsieJavaScriptEngine/Helpers/CommonRegExps.cs
new file mode 100644
index 0000000..4e69b8b
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Helpers/CommonRegExps.cs
@@ -0,0 +1,24 @@
+namespace MsieJavaScriptEngine.Helpers
+{
+ ///
+ /// Common regular expressions
+ ///
+ internal static class CommonRegExps
+ {
+ ///
+ /// Pattern for working with JS names
+ ///
+ public const string JsNamePattern = @"[$_\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}]" +
+ @"[$_\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\u200C\u200D\p{Mn}\p{Mc}\p{Nd}\p{Pc}]*";
+
+ ///
+ /// Pattern for working with JS full names
+ ///
+ public const string JsFullNamePattern = JsNamePattern + @"(?:\." + JsNamePattern + @")*";
+
+ ///
+ /// Pattern for working with document names
+ ///
+ public const string DocumentNamePattern = @"[^\s*?""<>|][^\t\n\r*?""<>|]*?";
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/JsEngineModeHelpers.cs b/src/MsieJavaScriptEngine/Helpers/JsEngineModeHelpers.cs
index 6aa48a9..06cfe76 100644
--- a/src/MsieJavaScriptEngine/Helpers/JsEngineModeHelpers.cs
+++ b/src/MsieJavaScriptEngine/Helpers/JsEngineModeHelpers.cs
@@ -1,7 +1,7 @@
-namespace MsieJavaScriptEngine.Helpers
-{
- using System;
+using System;
+namespace MsieJavaScriptEngine.Helpers
+{
internal static class JsEngineModeHelpers
{
public static string GetModeName(JsEngineMode mode)
diff --git a/src/MsieJavaScriptEngine/Helpers/JsErrorHelpers.cs b/src/MsieJavaScriptEngine/Helpers/JsErrorHelpers.cs
index 2942f10..27fbf26 100644
--- a/src/MsieJavaScriptEngine/Helpers/JsErrorHelpers.cs
+++ b/src/MsieJavaScriptEngine/Helpers/JsErrorHelpers.cs
@@ -1,79 +1,599 @@
-namespace MsieJavaScriptEngine.Helpers
-{
- using System;
- using System.Globalization;
- using System.Text;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using AdvancedStringBuilder;
- using Resources;
- using Utilities;
+using MsieJavaScriptEngine.Extensions;
+using MsieJavaScriptEngine.Resources;
+using MsieJavaScriptEngine.Utilities;
+namespace MsieJavaScriptEngine.Helpers
+{
///
- /// JavaScript engine error helpers
+ /// JS error helpers
///
public static class JsErrorHelpers
{
+ #region Call stack
+
+ ///
+ /// Regular expression for working with line of the script call stack
+ ///
+ private static readonly Regex _callStackLineRegex =
+ new Regex(@"^[ ]{3}at " +
+ @"(?[\w][\w ]*|" + CommonRegExps.JsFullNamePattern + @") " +
+ @"\((?" + CommonRegExps.DocumentNamePattern + @"):" +
+ @"(?\d+):(?\d+)\)$");
+
+
+ ///
+ /// Gets a string representation of the script call stack
+ ///
+ /// Error message with the script call stack
+ /// Error message without the script call stack
+ /// String representation of the script call stack
+ internal static string GetCallStackFromMessage(string message, string messageWithoutCallStack)
+ {
+ if (string.IsNullOrWhiteSpace(message))
+ {
+ return string.Empty;
+ }
+
+ if (string.IsNullOrWhiteSpace(messageWithoutCallStack))
+ {
+ return message;
+ }
+
+ string callStack = message
+ .TrimStart(messageWithoutCallStack)
+ .TrimStart(EnvironmentShortcuts.NewLineChars)
+ ;
+
+ return callStack;
+ }
+
+ ///
+ /// Parses a string representation of the script call stack to produce an array of
+ /// instances
+ ///
+ /// String representation of the script call stack
+ /// An array of instances
+ internal static CallStackItem[] ParseCallStack(string callStack)
+ {
+ if (string.IsNullOrWhiteSpace(callStack))
+ {
+ return [];
+ }
+
+ string[] lines = callStack.SplitToLines(StringSplitOptions.RemoveEmptyEntries);
+ int lineCount = lines.Length;
+ var callStackItems = new List(lineCount);
+
+ foreach (string line in lines)
+ {
+ CallStackItem callStackItem = MapCallStackItem(line);
+ if (callStackItem is not null)
+ {
+ callStackItems.Add(callStackItem);
+ }
+ else
+ {
+ Debug.WriteLine(string.Format(CommonStrings.Runtime_InvalidCallStackLineFormat, line));
+ return [];
+ }
+ }
+
+ return callStackItems.ToArray();
+ }
+
+ private static CallStackItem MapCallStackItem(string callStackLine)
+ {
+ CallStackItem item = null;
+ Match lineMatch = _callStackLineRegex.Match(callStackLine);
+
+ if (lineMatch.Success)
+ {
+ GroupCollection lineGroups = lineMatch.Groups;
+ item = new CallStackItem
+ {
+ FunctionName = lineGroups["functionName"].Value,
+ DocumentName = lineGroups["documentName"].Value,
+ LineNumber = int.Parse(lineGroups["lineNumber"].Value),
+ ColumnNumber = int.Parse(lineGroups["columnNumber"].Value)
+ };
+ }
+
+ return item;
+ }
+
+ ///
+ /// Produces a string representation of the script call stack from array of
+ /// instances
+ ///
+ /// An array of instances
+ /// String representation of the script call stack
+ internal static string StringifyCallStackItems(CallStackItem[] callStackItems)
+ {
+ if (callStackItems is null)
+ {
+ throw new ArgumentException(nameof(callStackItems));
+ }
+
+ int stackItemCount = callStackItems.Length;
+ if (stackItemCount == 0)
+ {
+ return string.Empty;
+ }
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder stackBuilder = stringBuilderPool.Rent();
+
+ for (int stackItemIndex = 0; stackItemIndex < stackItemCount; stackItemIndex++)
+ {
+ CallStackItem stackItem = callStackItems[stackItemIndex];
+
+ if (stackItemIndex > 0)
+ {
+ stackBuilder.AppendLine();
+ }
+ WriteErrorLocationLine(stackBuilder, stackItem.FunctionName, stackItem.DocumentName,
+ stackItem.LineNumber, stackItem.ColumnNumber);
+ }
+
+ string callStack = stackBuilder.ToString();
+ stringBuilderPool.Return(stackBuilder);
+
+ return callStack;
+ }
+
+ #endregion
+
+ #region Generation of error messages
+
+ ///
+ /// Generates a engine load error message
+ ///
+ /// Description of error
+ /// Name of JS engine mode
+ /// Makes a quote from the description
+ /// Engine load error message
+ internal static string GenerateEngineLoadErrorMessage(string description, string engineModeName,
+ bool quoteDescription = false)
+ {
+ if (engineModeName is null)
+ {
+ throw new ArgumentNullException(nameof(engineModeName));
+ }
+
+ if (string.IsNullOrWhiteSpace(engineModeName))
+ {
+ throw new ArgumentException(
+ string.Format(CommonStrings.Common_ArgumentIsEmpty, nameof(engineModeName)),
+ nameof(engineModeName)
+ );
+ }
+
+ string jsEngineNotLoadedPart = string.Format(CommonStrings.Engine_JsEngineNotLoaded,
+ engineModeName);
+ string message;
+
+ if (!string.IsNullOrWhiteSpace(description))
+ {
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder messageBuilder = stringBuilderPool.Rent();
+ messageBuilder.Append(jsEngineNotLoadedPart);
+ messageBuilder.Append(" ");
+ if (quoteDescription)
+ {
+ messageBuilder.AppendFormat(CommonStrings.Common_SeeOriginalErrorMessage, description);
+ }
+ else
+ {
+ messageBuilder.Append(description);
+ }
+
+ message = messageBuilder.ToString();
+ stringBuilderPool.Return(messageBuilder);
+ }
+ else
+ {
+ message = jsEngineNotLoadedPart;
+ }
+
+ return message;
+ }
+
+ ///
+ /// Generates a script error message
+ ///
+ /// Type of the script error
+ /// Description of error
+ /// Document name
+ /// Line number
+ /// Column number
+ /// Source fragment
+ /// Script error message
+ internal static string GenerateScriptErrorMessage(string type, string description,
+ string documentName, int lineNumber, int columnNumber, string sourceFragment)
+ {
+ return GenerateScriptErrorMessage(type, description, documentName, lineNumber, columnNumber,
+ sourceFragment, string.Empty);
+ }
+
+ ///
+ /// Generates a script error message
+ ///
+ /// Type of the script error
+ /// Description of error
+ /// String representation of the script call stack
+ /// Script error message
+ internal static string GenerateScriptErrorMessage(string type, string description, string callStack)
+ {
+ return GenerateScriptErrorMessage(type, description, string.Empty, 0, 0, string.Empty, callStack);
+ }
+
+ ///
+ /// Generates a script error message
+ ///
+ /// Type of the script error
+ /// Description of error
+ /// Document name
+ /// Line number
+ /// Column number
+ /// Source fragment
+ /// String representation of the script call stack
+ /// Script error message
+ internal static string GenerateScriptErrorMessage(string type, string description, string documentName,
+ int lineNumber, int columnNumber, string sourceFragment, string callStack)
+ {
+ if (description is null)
+ {
+ throw new ArgumentNullException(nameof(description));
+ }
+
+ if (string.IsNullOrWhiteSpace(description))
+ {
+ throw new ArgumentException(
+ string.Format(CommonStrings.Common_ArgumentIsEmpty, nameof(description)),
+ nameof(description)
+ );
+ }
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder messageBuilder = stringBuilderPool.Rent();
+ if (!string.IsNullOrWhiteSpace(type))
+ {
+ messageBuilder.Append(type);
+ messageBuilder.Append(": ");
+ }
+ messageBuilder.Append(description);
+
+ if (!string.IsNullOrWhiteSpace(callStack))
+ {
+ messageBuilder.AppendLine();
+ messageBuilder.Append(callStack);
+ }
+ else
+ {
+ if (!string.IsNullOrWhiteSpace(documentName) || lineNumber > 0)
+ {
+ messageBuilder.AppendLine();
+ WriteErrorLocationLine(messageBuilder, string.Empty, documentName, lineNumber, columnNumber,
+ sourceFragment);
+ }
+ }
+
+ string errorMessage = messageBuilder.ToString();
+ stringBuilderPool.Return(messageBuilder);
+
+ return errorMessage;
+ }
+
+ #endregion
+
+ #region Generation of error details
+
///
/// Generates a detailed error message
///
- /// JavaScript engine load exception
+ /// JS exception
+ /// Flag for whether to omit message
/// Detailed error message
- public static string Format(JsEngineLoadException jsEngineLoadException)
+ public static string GenerateErrorDetails(JsException jsException, bool omitMessage = false)
{
- var errorMessage = new StringBuilder();
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_Message,
- jsEngineLoadException.Message);
- if (!string.IsNullOrWhiteSpace(jsEngineLoadException.EngineMode))
+ if (jsException is null)
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_EngineMode,
- jsEngineLoadException.EngineMode);
+ throw new ArgumentNullException(nameof(jsException));
}
- return errorMessage.ToString();
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder detailsBuilder = stringBuilderPool.Rent();
+ WriteCommonErrorDetails(detailsBuilder, jsException, omitMessage);
+
+ var jsScriptException = jsException as JsScriptException;
+ if (jsScriptException is not null)
+ {
+ WriteScriptErrorDetails(detailsBuilder, jsScriptException);
+
+ var jsRuntimeException = jsScriptException as JsRuntimeException;
+ if (jsRuntimeException is not null)
+ {
+ WriteRuntimeErrorDetails(detailsBuilder, jsRuntimeException);
+ }
+ }
+
+ detailsBuilder.TrimEnd();
+
+ string errorDetails = detailsBuilder.ToString();
+ stringBuilderPool.Return(detailsBuilder);
+
+ return errorDetails;
}
///
/// Generates a detailed error message
///
- /// JavaScript runtime exception
+ /// JS script exception
+ /// Flag for whether to omit message
/// Detailed error message
- public static string Format(JsRuntimeException jsRuntimeException)
+ public static string GenerateErrorDetails(JsScriptException jsScriptException,
+ bool omitMessage = false)
{
- var errorMessage = new StringBuilder();
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_Message,
- jsRuntimeException.Message);
- if (!string.IsNullOrWhiteSpace(jsRuntimeException.EngineMode))
+ if (jsScriptException is null)
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_EngineMode,
- jsRuntimeException.EngineMode);
+ throw new ArgumentNullException(nameof(jsScriptException));
}
- if (!string.IsNullOrWhiteSpace(jsRuntimeException.ErrorCode))
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder detailsBuilder = stringBuilderPool.Rent();
+ WriteCommonErrorDetails(detailsBuilder, jsScriptException, omitMessage);
+ WriteScriptErrorDetails(detailsBuilder, jsScriptException);
+
+ var jsRuntimeException = jsScriptException as JsRuntimeException;
+ if (jsRuntimeException is not null)
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_ErrorCode,
- jsRuntimeException.ErrorCode);
+ WriteRuntimeErrorDetails(detailsBuilder, jsRuntimeException);
}
- if (!string.IsNullOrWhiteSpace(jsRuntimeException.Category))
+
+ detailsBuilder.TrimEnd();
+
+ string errorDetails = detailsBuilder.ToString();
+ stringBuilderPool.Return(detailsBuilder);
+
+ return errorDetails;
+ }
+
+ ///
+ /// Generates a detailed error message
+ ///
+ /// JS runtime exception
+ /// Flag for whether to omit message
+ /// Detailed error message
+ public static string GenerateErrorDetails(JsRuntimeException jsRuntimeException,
+ bool omitMessage = false)
+ {
+ if (jsRuntimeException is null)
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_Category,
- jsRuntimeException.Category);
+ throw new ArgumentNullException(nameof(jsRuntimeException));
}
- if (jsRuntimeException.LineNumber > 0)
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder detailsBuilder = stringBuilderPool.Rent();
+ WriteCommonErrorDetails(detailsBuilder, jsRuntimeException, omitMessage);
+ WriteScriptErrorDetails(detailsBuilder, jsRuntimeException);
+ WriteRuntimeErrorDetails(detailsBuilder, jsRuntimeException);
+
+ detailsBuilder.TrimEnd();
+
+ string errorDetails = detailsBuilder.ToString();
+ stringBuilderPool.Return(detailsBuilder);
+
+ return errorDetails;
+ }
+
+ ///
+ /// Writes a detailed error message to the buffer
+ ///
+ /// Instance of
+ /// JS exception
+ /// Flag for whether to omit message
+ private static void WriteCommonErrorDetails(StringBuilder buffer, JsException jsException,
+ bool omitMessage = false)
+ {
+ if (!omitMessage)
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_Message,
+ jsException.Message);
+ }
+ if (!string.IsNullOrWhiteSpace(jsException.EngineMode))
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_LineNumber,
- jsRuntimeException.LineNumber.ToString(CultureInfo.InvariantCulture));
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_EngineMode,
+ jsException.EngineMode);
}
- if (jsRuntimeException.ColumnNumber > 0)
+ if (!string.IsNullOrWhiteSpace(jsException.Category))
{
- errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_ColumnNumber,
- jsRuntimeException.ColumnNumber.ToString(CultureInfo.InvariantCulture));
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_Category,
+ jsException.Category);
}
- if (!string.IsNullOrWhiteSpace(jsRuntimeException.SourceFragment))
+ if (!string.IsNullOrWhiteSpace(jsException.Description))
{
- errorMessage.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine,
- Strings.ErrorDetails_SourceFragment,
- jsRuntimeException.SourceFragment);
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_Description,
+ jsException.Description);
}
+ }
- return errorMessage.ToString();
+ ///
+ /// Writes a detailed error message to the buffer
+ ///
+ /// Instance of
+ /// JS script exception
+ private static void WriteScriptErrorDetails(StringBuilder buffer,
+ JsScriptException jsScriptException)
+ {
+ if (!string.IsNullOrWhiteSpace(jsScriptException.Type))
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_Type,
+ jsScriptException.Type);
+ }
+ if (!string.IsNullOrWhiteSpace(jsScriptException.DocumentName))
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_DocumentName,
+ jsScriptException.DocumentName);
+ }
+ if (jsScriptException.LineNumber > 0)
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_LineNumber,
+ jsScriptException.LineNumber.ToString(CultureInfo.InvariantCulture));
+ }
+ if (jsScriptException.ColumnNumber > 0)
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_ColumnNumber,
+ jsScriptException.ColumnNumber.ToString(CultureInfo.InvariantCulture));
+ }
+ if (!string.IsNullOrWhiteSpace(jsScriptException.SourceFragment))
+ {
+ buffer.AppendFormatLine("{0}: {1}", CommonStrings.ErrorDetails_SourceFragment,
+ jsScriptException.SourceFragment);
+ }
}
+
+ ///
+ /// Writes a detailed error message to the buffer
+ ///
+ /// Instance of
+ /// JS runtime exception
+ private static void WriteRuntimeErrorDetails(StringBuilder buffer,
+ JsRuntimeException jsRuntimeException)
+ {
+ if (!string.IsNullOrWhiteSpace(jsRuntimeException.CallStack))
+ {
+ buffer.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine,
+ CommonStrings.ErrorDetails_CallStack,
+ jsRuntimeException.CallStack);
+ }
+ }
+
+ #endregion
+
+ #region Exception wrapping
+
+ public static JsEngineLoadException WrapEngineLoadException(Exception exception,
+ string engineModeName, bool quoteDescription = false)
+ {
+ string description = exception.Message;
+ string message = GenerateEngineLoadErrorMessage(description, engineModeName, quoteDescription);
+
+ var jsEngineLoadException = new JsEngineLoadException(message, engineModeName, exception)
+ {
+ Description = description
+ };
+
+ return jsEngineLoadException;
+ }
+
+ #endregion
+
+ #region Misc
+
+ ///
+ /// Writes a error location line to the buffer
+ ///
+ /// Instance of
+ /// Function name
+ /// Document name
+ /// Line number
+ /// Column number
+ /// Source fragment
+ internal static void WriteErrorLocationLine(StringBuilder buffer, string functionName,
+ string documentName, int lineNumber, int columnNumber, string sourceFragment = "")
+ {
+ bool functionNameNotEmpty = !string.IsNullOrWhiteSpace(functionName);
+ bool documentNameNotEmpty = !string.IsNullOrWhiteSpace(documentName);
+
+ if (functionNameNotEmpty || documentNameNotEmpty || lineNumber > 0)
+ {
+ buffer.Append(" at ");
+ if (functionNameNotEmpty)
+ {
+ buffer.Append(functionName);
+ }
+ if (documentNameNotEmpty || lineNumber > 0)
+ {
+ if (functionNameNotEmpty)
+ {
+ buffer.Append(" (");
+ }
+ if (documentNameNotEmpty)
+ {
+ buffer.Append(documentName);
+ }
+ if (lineNumber > 0)
+ {
+ if (documentNameNotEmpty)
+ {
+ buffer.Append(":");
+ }
+ buffer.Append(lineNumber);
+ if (columnNumber > 0)
+ {
+ buffer.Append(":");
+ buffer.Append(columnNumber);
+ }
+ }
+ if (functionNameNotEmpty)
+ {
+ buffer.Append(")");
+ }
+ if (!string.IsNullOrWhiteSpace(sourceFragment))
+ {
+ buffer.Append(" -> ");
+ buffer.Append(sourceFragment);
+ }
+ }
+ }
+ }
+
+ #region Obsolete methods
+
+ ///
+ /// Generates a detailed error message
+ ///
+ /// JS exception
+ /// Detailed error message
+ [Obsolete("Use a `GenerateErrorDetails` method")]
+ public static string Format(JsException jsException)
+ {
+ return GenerateErrorDetails(jsException);
+ }
+
+ ///
+ /// Generates a detailed error message
+ ///
+ /// JS script exception
+ /// Detailed error message
+ [Obsolete("Use a `GenerateErrorDetails` method")]
+ public static string Format(JsScriptException jsScriptException)
+ {
+ return GenerateErrorDetails(jsScriptException);
+ }
+
+ ///
+ /// Generates a detailed error message
+ ///
+ /// JS runtime exception
+ /// Detailed error message
+ [Obsolete("Use a `GenerateErrorDetails` method")]
+ public static string Format(JsRuntimeException jsRuntimeException)
+ {
+ return GenerateErrorDetails(jsRuntimeException);
+ }
+
+ #endregion
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/NumericHelpers.cs b/src/MsieJavaScriptEngine/Helpers/NumericHelpers.cs
new file mode 100644
index 0000000..7afb9f2
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Helpers/NumericHelpers.cs
@@ -0,0 +1,57 @@
+using System;
+
+using MsieJavaScriptEngine.Extensions;
+
+namespace MsieJavaScriptEngine.Helpers
+{
+ ///
+ /// Numeric helpers
+ ///
+ internal static class NumericHelpers
+ {
+ private const double MAX_INTEGER_IN_DOUBLE = (1L << 53) - 1;
+
+
+ ///
+ /// Casts a double value to the correct type
+ ///
+ /// Double value
+ /// Numeric value with the correct type
+ public static object CastDoubleValueToCorrectType(double value)
+ {
+ if (Math.Round(value) == value)
+ {
+ if (Math.Abs(value) <= MAX_INTEGER_IN_DOUBLE)
+ {
+ long longValue = Convert.ToInt64(value);
+ if (longValue >= int.MinValue && longValue <= int.MaxValue)
+ {
+ return (int)longValue;
+ }
+
+ return longValue;
+ }
+ }
+ else
+ {
+ float floatValue = Convert.ToSingle(value);
+ if (value == floatValue)
+ {
+ return floatValue;
+ }
+ }
+
+ return value;
+ }
+
+ internal static int UnsignedAsSigned(uint value)
+ {
+ return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
+ }
+
+ internal static uint SignedAsUnsigned(int value)
+ {
+ return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs b/src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs
new file mode 100644
index 0000000..c4cb41a
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs
@@ -0,0 +1,340 @@
+using System;
+#if NET45_OR_GREATER || NETSTANDARD || NET10_0_OR_GREATER
+using System.Buffers;
+#endif
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+#if NET40
+
+using PolyfillsForOldDotNet.System.Buffers;
+#endif
+
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.Helpers
+{
+ ///
+ /// Reflection helpers
+ ///
+ internal static class ReflectionHelpers
+ {
+ private static readonly PropertyInfo[] _disallowedProperties =
+ [
+ typeof(Delegate).GetProperty("Method"),
+ typeof(Exception).GetProperty("TargetSite")
+ ];
+
+ private static readonly MethodInfo[] _disallowedMethods =
+ [
+ typeof(object).GetMethod("GetType"),
+ typeof(Exception).GetMethod("GetType")
+ ];
+
+
+ public static BindingFlags GetDefaultBindingFlags(bool instance)
+ {
+ BindingFlags bindingFlags = BindingFlags.Public;
+ if (instance)
+ {
+ bindingFlags |= BindingFlags.Instance;
+ }
+ else
+ {
+ bindingFlags |= BindingFlags.Static;
+ }
+
+ return bindingFlags;
+ }
+
+ public static bool IsAllowedProperty(PropertyInfo property)
+ {
+ bool isAllowed = !_disallowedProperties.Contains(property, MemberComparer.Instance);
+
+ return isAllowed;
+ }
+
+ public static bool IsAllowedMethod(MethodInfo method)
+ {
+ bool isAllowed = !_disallowedMethods.Contains(method, MemberComparer.Instance);
+
+ return isAllowed;
+ }
+
+ public static bool IsFullyFledgedMethod(MethodInfo method)
+ {
+ if (!method.Attributes.HasFlag(MethodAttributes.SpecialName))
+ {
+ return true;
+ }
+
+ string name = method.Name;
+ bool isFullyFledged = !(name.StartsWith("get_", StringComparison.Ordinal)
+ || name.StartsWith("set_", StringComparison.Ordinal));
+
+ return isFullyFledged;
+ }
+
+ public static void FixFieldValueType(ref object value, FieldInfo field)
+ {
+ if (value is null)
+ {
+ return;
+ }
+
+ Type valueType = value.GetType();
+ Type fieldType = field.FieldType;
+
+ if (valueType != fieldType)
+ {
+ object convertedValue;
+
+ if (TypeConverter.TryConvertToType(value, fieldType, out convertedValue))
+ {
+ value = convertedValue;
+ }
+ }
+ }
+
+ public static void FixPropertyValueType(ref object value, PropertyInfo property)
+ {
+ if (value is null)
+ {
+ return;
+ }
+
+ Type valueType = value.GetType();
+ Type propertyType = property.PropertyType;
+
+ if (valueType != propertyType)
+ {
+ object convertedValue;
+
+ if (TypeConverter.TryConvertToType(value, propertyType, out convertedValue))
+ {
+ value = convertedValue;
+ }
+ }
+ }
+
+ public static void FixArgumentTypes(ref object[] argValues, ParameterInfo[] parameters)
+ {
+ int argCount = argValues.Length;
+ if (argCount == 0)
+ {
+ return;
+ }
+
+ int parameterCount = parameters.Length;
+
+ for (int argIndex = 0; argIndex < argCount; argIndex++)
+ {
+ if (argIndex >= parameterCount)
+ {
+ break;
+ }
+
+ object argValue = argValues[argIndex];
+ if (argValue is null)
+ {
+ continue;
+ }
+
+ Type argType = argValue.GetType();
+
+ ParameterInfo parameter = parameters[argIndex];
+ Type parameterType = parameter.ParameterType;
+
+ if (argType != parameterType)
+ {
+ object convertedArgValue;
+
+ if (TypeConverter.TryConvertToType(argValue, parameterType, out convertedArgValue))
+ {
+ argValues[argIndex] = convertedArgValue;
+ }
+ }
+ }
+ }
+
+ public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValues)
+ {
+ int methodCount = methods.Length;
+ if (methodCount == 0)
+ {
+ return null;
+ }
+
+ if (methodCount == 1)
+ {
+ MethodBase method = methods[0];
+ ParameterInfo[] parameters = method.GetParameters();
+
+ MethodBase bestFitMethod = null;
+ if (CompareParameterTypes(argValues, parameters, out _))
+ {
+ bestFitMethod = method;
+ }
+
+ return bestFitMethod;
+ }
+
+ MethodWithMetadata[] compatibleMethods = null;
+ int compatibleMethodCount = 0;
+
+ var methodArrayPool = ArrayPool.Shared;
+ MethodWithMetadata[] buffer = methodArrayPool.Rent(methodCount);
+
+ try
+ {
+ foreach (MethodBase method in methods)
+ {
+ ParameterInfo[] parameters = method.GetParameters();
+ ushort compatibilityScore;
+
+ if (CompareParameterTypes(argValues, parameters, out compatibilityScore))
+ {
+ compatibleMethodCount++;
+
+ int compatibleMethodIndex = compatibleMethodCount - 1;
+ buffer[compatibleMethodIndex] = new MethodWithMetadata
+ {
+ Method = method,
+ CompatibilityScore = compatibilityScore
+ };
+ }
+ }
+
+ if (compatibleMethodCount > 0)
+ {
+ if (compatibleMethodCount == 1)
+ {
+ return buffer[0].Method;
+ }
+
+ compatibleMethods = new MethodWithMetadata[compatibleMethodCount];
+ Array.Copy(buffer, compatibleMethods, compatibleMethodCount);
+ }
+ }
+ finally
+ {
+ bool clearArray = compatibleMethodCount > 0;
+ methodArrayPool.Return(buffer, clearArray);
+ }
+
+ if (compatibleMethods is not null)
+ {
+ MethodWithMetadata bestFitMethod = compatibleMethods
+ .OrderByDescending(m => m.CompatibilityScore)
+ .First()
+ ;
+
+ return bestFitMethod.Method;
+ }
+
+ return null;
+ }
+
+ private static bool CompareParameterTypes(object[] argValues, ParameterInfo[] parameters,
+ out ushort compatibilityScore)
+ {
+ int argCount = argValues.Length;
+ int parameterCount = parameters.Length;
+ compatibilityScore = 0;
+
+ if (argCount != parameterCount)
+ {
+ return false;
+ }
+ else if (argCount == 0)
+ {
+ compatibilityScore = ushort.MaxValue;
+ return true;
+ }
+
+ for (int argIndex = 0; argIndex < argCount; argIndex++)
+ {
+ object argValue = argValues[argIndex];
+ Type argType = argValue is not null ? argValue.GetType() : typeof(object);
+ ParameterInfo parameter = parameters[argIndex];
+ Type parameterType = parameter.ParameterType;
+
+ if (argType == parameterType)
+ {
+ compatibilityScore++;
+ }
+ else
+ {
+ // TODO: It is necessary to calculate the compatibility score based on length
+ // of inheritance and interface implementation chains.
+ object convertedArgValue;
+
+ if (!TypeConverter.TryConvertToType(argValue, parameterType, out convertedArgValue))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ private sealed class MemberComparer : EqualityComparer
+ where T : MemberInfo
+ {
+ public static MemberComparer Instance { get; } = new MemberComparer();
+
+
+ private MemberComparer()
+ { }
+
+
+ #region MemberComparer overrides
+
+ public override bool Equals(T x, T y)
+ {
+ if (x is null && y is null)
+ {
+ return true;
+ }
+ else if (x is null || y is null)
+ {
+ return false;
+ }
+
+ return x.Module == y.Module
+#if !NETSTANDARD1_3
+ && x.MetadataToken == y.MetadataToken
+#else
+ && x.DeclaringType == y.DeclaringType
+ && x.Name == y.Name
+#endif
+ ;
+ }
+
+ public override int GetHashCode(T obj)
+ {
+ return obj is not null ? obj.GetHashCode() : 0;
+ }
+
+ #endregion
+ }
+
+ private sealed class MethodWithMetadata
+ {
+ public MethodBase Method
+ {
+ get;
+ set;
+ }
+
+ /// TODO: In future will need to change type to double
+ public ushort CompatibilityScore
+ {
+ get;
+ set;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/TextHelpers.cs b/src/MsieJavaScriptEngine/Helpers/TextHelpers.cs
new file mode 100644
index 0000000..482478c
--- /dev/null
+++ b/src/MsieJavaScriptEngine/Helpers/TextHelpers.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Text;
+
+using AdvancedStringBuilder;
+
+using MsieJavaScriptEngine.Extensions;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.Helpers
+{
+ ///
+ /// Text helpers
+ ///
+ internal static class TextHelpers
+ {
+ ///
+ /// Array of characters used to find the next line break
+ ///
+ private static readonly char[] _nextLineBreakChars = EnvironmentShortcuts.NewLineChars;
+
+
+ ///
+ /// Gets a fragment from the text line
+ ///
+ /// Content of the text line
+ /// Column number
+ /// Maximum length of the text fragment
+ internal static string GetTextFragmentFromLine(string textLine, int columnNumber,
+ int maxFragmentLength = 100)
+ {
+ if (string.IsNullOrEmpty(textLine))
+ {
+ return string.Empty;
+ }
+
+ string fragment;
+ int lineLength = textLine.Length;
+
+ if (lineLength > maxFragmentLength)
+ {
+ const string ellipsisSymbol = "…";
+ string startPart = string.Empty;
+ string endPart = string.Empty;
+
+ var leftOffset = (int)Math.Floor((double)maxFragmentLength / 2);
+ int fragmentStartPosition = columnNumber - leftOffset - 1;
+ if (fragmentStartPosition > 0)
+ {
+ if (lineLength - fragmentStartPosition < maxFragmentLength)
+ {
+ fragmentStartPosition = lineLength - maxFragmentLength;
+ }
+ }
+ else
+ {
+ fragmentStartPosition = 0;
+ }
+ int fragmentLength = maxFragmentLength;
+
+ if (fragmentStartPosition > 0)
+ {
+ startPart = ellipsisSymbol;
+ }
+ if (fragmentStartPosition + fragmentLength < lineLength)
+ {
+ endPart = ellipsisSymbol;
+ }
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder fragmentBuilder = stringBuilderPool.Rent();
+ if (startPart.Length > 0)
+ {
+ fragmentBuilder.Append(startPart);
+ }
+ fragmentBuilder.Append(textLine.Substring(fragmentStartPosition, fragmentLength));
+ if (endPart.Length > 0)
+ {
+ fragmentBuilder.Append(endPart);
+ }
+
+ fragment = fragmentBuilder.ToString();
+ stringBuilderPool.Return(fragmentBuilder);
+ }
+ else
+ {
+ fragment = textLine;
+ }
+
+ return fragment;
+ }
+
+ ///
+ /// Finds a next line break
+ ///
+ /// Source text
+ /// Position in the input string that defines the leftmost
+ /// position to be searched
+ /// Number of characters in the substring to include in the search
+ /// Position of line break
+ /// Length of line break
+ internal static void FindNextLineBreak(string sourceText, int startPosition, int length,
+ out int lineBreakPosition, out int lineBreakLength)
+ {
+ lineBreakPosition = sourceText.IndexOfAny(_nextLineBreakChars, startPosition, length);
+ if (lineBreakPosition != -1)
+ {
+ lineBreakLength = 1;
+ char currentCharacter = sourceText[lineBreakPosition];
+
+ if (currentCharacter == '\r')
+ {
+ int nextCharacterPosition = lineBreakPosition + 1;
+ char nextCharacter;
+
+ if (sourceText.TryGetChar(nextCharacterPosition, out nextCharacter)
+ && nextCharacter == '\n')
+ {
+ lineBreakLength = 2;
+ }
+ }
+ }
+ else
+ {
+ lineBreakLength = 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs b/src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs
index 0f94505..1127fd7 100644
--- a/src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs
+++ b/src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs
@@ -1,10 +1,12 @@
-namespace MsieJavaScriptEngine.Helpers
-{
- using System;
- using System.Linq;
+#if NETFRAMEWORK
+using System;
+using System.Linq;
- using Utilities;
+using MsieJavaScriptEngine.ActiveScript;
+using MsieJavaScriptEngine.Utilities;
+namespace MsieJavaScriptEngine.Helpers
+{
///
/// Type mapping helpers
///
@@ -15,10 +17,11 @@ internal static class TypeMappingHelpers
///
/// The source value
/// JavaScript engine mode
+ /// Flag for whether to allow the usage of reflection API in the script code
/// The mapped value
- public static object MapToScriptType(object value, JsEngineMode engineMode)
+ public static object MapToScriptType(object value, JsEngineMode engineMode, bool allowReflection)
{
- if (value == null)
+ if (value is null)
{
return DBNull.Value;
}
@@ -28,12 +31,13 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
return null;
}
- if (TypeConverter.IsPrimitiveType(value.GetType()))
+ Type type = value.GetType();
+ if (TypeConverter.IsPrimitiveType(type) || type.FullName == "System.__ComObject")
{
return value;
}
- var result = new HostObject(value, engineMode);
+ var result = new HostObject(value, engineMode, allowReflection);
return result;
}
@@ -43,10 +47,11 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
///
/// The source array
/// JavaScript engine mode
+ /// Flag for whether to allow the usage of reflection API in the script code
/// The mapped array
- public static object[] MapToScriptType(object[] args, JsEngineMode engineMode)
+ public static object[] MapToScriptType(object[] args, JsEngineMode engineMode, bool allowReflection)
{
- return args.Select(arg => MapToScriptType(arg, engineMode)).ToArray();
+ return args.Select(arg => MapToScriptType(arg, engineMode, allowReflection)).ToArray();
}
///
@@ -56,7 +61,7 @@ public static object[] MapToScriptType(object[] args, JsEngineMode engineMode)
/// The mapped value
public static object MapToHostType(object value)
{
- if (value == null)
+ if (value is null)
{
return Undefined.Value;
}
@@ -72,7 +77,7 @@ public static object MapToHostType(object value)
}
var hostObj = value as HostObject;
- object result = hostObj != null ? hostObj.Target : value;
+ object result = hostObj is not null ? hostObj.Target : value;
return result;
}
@@ -87,4 +92,5 @@ public static object[] MapToHostType(object[] args)
return args.Select(MapToHostType).ToArray();
}
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/Helpers/ValidationHelpers.cs b/src/MsieJavaScriptEngine/Helpers/ValidationHelpers.cs
index de10b6c..eacf30f 100644
--- a/src/MsieJavaScriptEngine/Helpers/ValidationHelpers.cs
+++ b/src/MsieJavaScriptEngine/Helpers/ValidationHelpers.cs
@@ -1,11 +1,11 @@
-namespace MsieJavaScriptEngine.Helpers
-{
- using System;
- using System.Linq;
- using System.Text.RegularExpressions;
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
- using Utilities;
+using MsieJavaScriptEngine.Utilities;
+namespace MsieJavaScriptEngine.Helpers
+{
///
/// Validation helpers
///
@@ -15,21 +15,26 @@ public static class ValidationHelpers
/// List of supported types
///
private static readonly Type[] _supportedTypes =
- {
+ [
typeof(Undefined), typeof(Boolean), typeof(Int32), typeof(Double), typeof(String)
- };
+ ];
+
+ ///
+ /// Regular expression for working with JS names
+ ///
+ private static readonly Regex _jsNameRegex = new Regex("^" + CommonRegExps.JsNamePattern + "$");
///
- /// Regular expression for working with JS-names
+ /// Regular expression for working with document names
///
- private static readonly Regex _jsNameRegex = new Regex(@"^[A-Za-z_\$][0-9A-Za-z_\$]*$");
+ private static readonly Regex _documentNameRegex = new Regex("^" + CommonRegExps.DocumentNamePattern + "$");
///
/// Checks whether supports a .NET type
///
/// .NET type
- /// Result of check (true - is supported; false - is not supported)
+ /// Result of check (true - is supported; false - is not supported)
public static bool IsSupportedType(Type type)
{
bool result = _supportedTypes.Contains(type);
@@ -41,7 +46,7 @@ public static bool IsSupportedType(Type type)
/// Checks whether .NET type is primitive
///
/// .NET type
- /// Result of check (true - is primitive; false - is not primitive)
+ /// Result of check (true - is primitive; false - is not primitive)
public static bool IsPrimitiveType(Type type)
{
return TypeConverter.IsPrimitiveType(type);
@@ -51,10 +56,20 @@ public static bool IsPrimitiveType(Type type)
/// Checks a format of the name
///
/// The name
- /// Result of check (true - correct format; false - wrong format)
+ /// Result of check (true - correct format; false - wrong format)
public static bool CheckNameFormat(string name)
{
return _jsNameRegex.IsMatch(name);
}
+
+ ///
+ /// Checks a format of the document name
+ ///
+ /// The document name
+ /// Result of check (true - correct format; false - wrong format)
+ public static bool CheckDocumentNameFormat(string name)
+ {
+ return _documentNameRegex.IsMatch(name);
+ }
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/HostItemBase.cs b/src/MsieJavaScriptEngine/HostItemBase.cs
deleted file mode 100644
index ad1970f..0000000
--- a/src/MsieJavaScriptEngine/HostItemBase.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-namespace MsieJavaScriptEngine
-{
- using System;
- using System.Globalization;
- using System.Linq;
- using System.Reflection;
-
- ///
- /// Base class of item, that implements interface
- ///
- internal abstract class HostItemBase : IReflect
- {
- ///
- /// Target type
- ///
- protected readonly Type _type;
-
- ///
- /// Target object
- ///
- protected readonly object _target;
-
- ///
- /// JavaScript engine mode
- ///
- protected readonly JsEngineMode _engineMode;
-
- ///
- /// List of fields
- ///
- private readonly FieldInfo[] _fields;
-
- ///
- /// List of properties
- ///
- private readonly PropertyInfo[] _properties;
-
- ///
- /// List of methods
- ///
- private readonly MethodInfo[] _methods;
-
- ///
- /// Gets a target object
- ///
- public object Target
- {
- get { return _target; }
- }
-
-
- ///
- /// Constructs an instance of the wrapper for item, that implements interface
- ///
- /// Target type
- /// Target object
- /// JavaScript engine mode
- /// Flag for whether to allow access to members of the instance
- protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool instance)
- {
- _type = type;
- _target = target;
- _engineMode = engineMode;
-
- BindingFlags bindingFlags = BindingFlags.Public;
- if (instance)
- {
- bindingFlags |= BindingFlags.Instance;
- }
- else
- {
- bindingFlags |= BindingFlags.Static;
- }
-
- _fields = _type.GetFields(bindingFlags);
- _properties = _type.GetProperties(bindingFlags);
- _methods = _type.GetMethods(bindingFlags);
- }
-
-
- protected abstract object InnerInvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
- object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters);
-
- protected object InvokeStandardMember(string name, BindingFlags invokeAttr, Binder binder, object target,
- object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
- {
- BindingFlags processedInvokeAttr = invokeAttr;
- if ((processedInvokeAttr.HasFlag(BindingFlags.GetProperty)
- || processedInvokeAttr.HasFlag(BindingFlags.PutDispProperty))
- && !_properties.Any(p => p.Name == name)
- && _fields.Any(p => p.Name == name))
- {
- if (processedInvokeAttr.HasFlag(BindingFlags.GetProperty))
- {
- processedInvokeAttr &= ~BindingFlags.GetProperty;
- processedInvokeAttr |= BindingFlags.GetField;
- }
- else if (processedInvokeAttr.HasFlag(BindingFlags.PutDispProperty))
- {
- processedInvokeAttr &= ~BindingFlags.PutDispProperty;
- processedInvokeAttr |= BindingFlags.SetField;
- }
- }
-
- object result = _type.InvokeMember(name, processedInvokeAttr, binder, target,
- args, modifiers, culture, namedParameters);
-
- return result;
- }
-
- #region IReflect implementation
-
- Type IReflect.UnderlyingSystemType
- {
- get { throw new NotImplementedException(); }
- }
-
-
- FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
- {
- FieldInfo field = _fields.SingleOrDefault(f => f.Name == name);
-
- return field;
- }
-
- FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
- {
- return _fields;
- }
-
- MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
- {
- throw new NotImplementedException();
- }
-
- MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
- {
- throw new NotImplementedException();
- }
-
- MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr)
- {
- MethodInfo method = _methods.SingleOrDefault(m => m.Name == name);
-
- return method;
- }
-
- MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
- {
- throw new NotImplementedException();
- }
-
- MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
- {
- return _methods;
- }
-
- PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr)
- {
- return _properties;
- }
-
- PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr)
- {
- PropertyInfo property = _properties.SingleOrDefault(p => p.Name == name);
-
- return property;
- }
-
- PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder,
- Type returnType, Type[] types, ParameterModifier[] modifiers)
- {
- throw new NotImplementedException();
- }
-
- object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
- object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
- {
- return InnerInvokeMember(name, invokeAttr, binder,target, args, modifiers, culture, namedParameters);
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/HostObject.cs b/src/MsieJavaScriptEngine/HostObject.cs
deleted file mode 100644
index 1c19248..0000000
--- a/src/MsieJavaScriptEngine/HostObject.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-namespace MsieJavaScriptEngine
-{
- using System;
- using System.Globalization;
- using System.Linq;
- using System.Reflection;
-
- using Constants;
- using Helpers;
-
- ///
- /// Wrapper for object, that implements interface
- ///
- internal sealed class HostObject : HostItemBase
- {
- ///
- /// Constructs an instance of the wrapper for object, that implements interface
- ///
- /// Target object
- /// JavaScript engine mode
- public HostObject(object target, JsEngineMode engineMode)
- : base(target.GetType(), target, engineMode, true)
- { }
-
-
- private object InvokeDelegate(Delegate del, object[] args)
- {
- if (del == null)
- {
- throw new ArgumentNullException("del");
- }
-
- object[] processedArgs = args;
-
- if (_engineMode == JsEngineMode.Classic && processedArgs.Length > 0)
- {
- processedArgs = processedArgs.Skip(1).ToArray();
- }
-
- object result = del.DynamicInvoke(processedArgs);
-
- return result;
- }
-
- #region HostItemBase implementation
-
- protected override object InnerInvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target,
- object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
- {
- object result;
- object processedTarget = TypeMappingHelpers.MapToHostType(target);
- object[] processedArgs = TypeMappingHelpers.MapToHostType(args);
-
- if (name == SpecialMemberName.Default && processedTarget is Delegate)
- {
- var del = (Delegate)processedTarget;
- result = InvokeDelegate(del, processedArgs);
- }
- else
- {
- result = InvokeStandardMember(name, invokeAttr, binder, processedTarget,
- processedArgs, modifiers, culture, namedParameters);
- }
-
- return TypeMappingHelpers.MapToScriptType(result, _engineMode);
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/IInnerJsEngine.cs b/src/MsieJavaScriptEngine/IInnerJsEngine.cs
index a733dc1..6198864 100644
--- a/src/MsieJavaScriptEngine/IInnerJsEngine.cs
+++ b/src/MsieJavaScriptEngine/IInnerJsEngine.cs
@@ -1,30 +1,52 @@
-namespace MsieJavaScriptEngine
-{
- using System;
+using System;
+namespace MsieJavaScriptEngine
+{
///
- /// Interface for the inner JavaScript engine
+ /// Interface for the inner JS engine
///
internal interface IInnerJsEngine : IDisposable
{
///
- /// Gets a name of JavaScript engine mode
+ /// Gets a name of JS engine mode
///
string Mode { get; }
+ ///
+ /// Gets a value that indicates if the JS engine supports script pre-compilation
+ ///
+ bool SupportsScriptPrecompilation { get; }
+
+
+ ///
+ /// Creates a pre-compiled script from JS code
+ ///
+ /// JS code
+ /// Document name
+ /// A pre-compiled script that can be executed by different instances of JS engine
+ PrecompiledScript Precompile(string code, string documentName);
///
/// Evaluates an expression
///
- /// JavaScript expression
+ /// JS expression
+ /// Document name
/// Result of the expression
- object Evaluate(string expression);
+ object Evaluate(string expression, string documentName);
///
/// Executes a code
///
- /// JavaScript code
- void Execute(string code);
+ /// JS code
+ /// Document name
+ void Execute(string code, string documentName);
+
+ ///
+ /// Executes a pre-compiled script
+ ///
+ /// A pre-compiled script that can be executed by different
+ /// instances of JS engine
+ void Execute(PrecompiledScript precompiledScript);
///
/// Calls a function
@@ -35,10 +57,10 @@ internal interface IInnerJsEngine : IDisposable
object CallFunction(string functionName, params object[] args);
///
- /// Сhecks for the existence of a variable
+ /// Checks for the existence of a variable
///
/// Name of variable
- /// Result of check (true - exists; false - not exists
+ /// Result of check (true - exists; false - not exists
bool HasVariable(string variableName);
///
@@ -64,20 +86,32 @@ internal interface IInnerJsEngine : IDisposable
///
/// Embeds a host object to script code
///
+ ///
+ /// Allows to embed instances of simple classes (or structures) and delegates.
+ ///
/// The name for the new global variable or function that will represent the object
/// The object to expose
- /// Allows to embed instances of simple classes (or structures) and delegates.
void EmbedHostObject(string itemName, object value);
///
/// Embeds a host type to script code
///
- /// The name for the new global variable that will represent the type
- /// The type to expose
///
/// Host types are exposed to script code in the form of objects whose properties and
/// methods are bound to the type's static members.
///
+ /// The name for the new global variable that will represent the type
+ /// The type to expose
void EmbedHostType(string itemName, Type type);
+
+ ///
+ /// Interrupts script execution and causes the JS engine to throw an exception
+ ///
+ void Interrupt();
+
+ ///
+ /// Performs a full garbage collection
+ ///
+ void CollectGarbage();
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/InnerJsEngineBase.cs b/src/MsieJavaScriptEngine/InnerJsEngineBase.cs
new file mode 100644
index 0000000..e68123a
--- /dev/null
+++ b/src/MsieJavaScriptEngine/InnerJsEngineBase.cs
@@ -0,0 +1,99 @@
+using System;
+
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine
+{
+ ///
+ /// Base class of the inner JS engine
+ ///
+ internal abstract class InnerJsEngineBase : IInnerJsEngine
+ {
+ ///
+ /// JS engine settings
+ ///
+ protected JsEngineSettings _settings;
+
+ ///
+ /// Name of JS engine mode
+ ///
+ protected readonly string _engineModeName;
+
+ ///
+ /// Flag that object is destroyed
+ ///
+ protected StatedFlag _disposedFlag = new StatedFlag();
+
+
+ ///
+ /// Constructs an instance of the inner JS engine
+ ///
+ /// JS engine settings
+ protected InnerJsEngineBase(JsEngineSettings settings)
+ {
+ _settings = settings;
+ _engineModeName = JsEngineModeHelpers.GetModeName(_settings.EngineMode);
+ }
+
+
+ #region IInnerJsEngine implementation
+
+ ///
+ public string Mode
+ {
+ get { return _engineModeName; }
+ }
+
+ ///
+ public abstract bool SupportsScriptPrecompilation { get; }
+
+
+ ///
+ public abstract PrecompiledScript Precompile(string code, string documentName);
+
+ ///
+ public abstract object Evaluate(string expression, string documentName);
+
+ ///
+ public abstract void Execute(string code, string documentName);
+
+ ///
+ public abstract void Execute(PrecompiledScript precompiledScript);
+
+ ///
+ public abstract object CallFunction(string functionName, params object[] args);
+
+ ///
+ public abstract bool HasVariable(string variableName);
+
+ ///
+ public abstract object GetVariableValue(string variableName);
+
+ ///
+ public abstract void SetVariableValue(string variableName, object value);
+
+ ///
+ public abstract void RemoveVariable(string variableName);
+
+ ///
+ public abstract void EmbedHostObject(string itemName, object value);
+
+ ///
+ public abstract void EmbedHostType(string itemName, Type type);
+
+ ///
+ public abstract void Interrupt();
+
+ ///
+ public abstract void CollectGarbage();
+
+ #endregion
+
+ #region IDisposable implementation
+
+ public abstract void Dispose();
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsCompilationException.cs b/src/MsieJavaScriptEngine/JsCompilationException.cs
new file mode 100644
index 0000000..b8465d2
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsCompilationException.cs
@@ -0,0 +1,80 @@
+using System;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#endif
+
+using MsieJavaScriptEngine.Constants;
+
+namespace MsieJavaScriptEngine
+{
+ ///
+ /// The exception that is thrown during the script compilation stage, before the script
+ /// has begun to be executed
+ ///
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
+ public sealed class JsCompilationException : JsScriptException
+ {
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message
+ ///
+ /// The message that describes the error
+ public JsCompilationException(string message)
+ : base(message)
+ {
+ Category = JsErrorCategory.Compilation;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
+ ///
+ /// The error message that explains the reason for the exception
+ /// The exception that is the cause of the current exception
+ public JsCompilationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ Category = JsErrorCategory.Compilation;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ public JsCompilationException(string message, string engineMode)
+ : base(message, engineMode)
+ {
+ Category = JsErrorCategory.Compilation;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ /// The exception that is the cause of the current exception
+ public JsCompilationException(string message, string engineMode, Exception innerException)
+ : base(message, engineMode, innerException)
+ {
+ Category = JsErrorCategory.Compilation;
+ }
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ private JsCompilationException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ { }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsEngineException.cs b/src/MsieJavaScriptEngine/JsEngineException.cs
new file mode 100644
index 0000000..f82bc47
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsEngineException.cs
@@ -0,0 +1,79 @@
+using System;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#endif
+
+using MsieJavaScriptEngine.Constants;
+
+namespace MsieJavaScriptEngine
+{
+ ///
+ /// The exception that occurred in the workings of the JS engine itself
+ ///
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
+ public class JsEngineException : JsException
+ {
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message
+ ///
+ /// The message that describes the error
+ public JsEngineException(string message)
+ : base(message)
+ {
+ Category = JsErrorCategory.Engine;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
+ ///
+ /// The error message that explains the reason for the exception
+ /// The exception that is the cause of the current exception
+ public JsEngineException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ Category = JsErrorCategory.Engine;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ public JsEngineException(string message, string engineMode)
+ : base(message, engineMode)
+ {
+ Category = JsErrorCategory.Engine;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ /// The exception that is the cause of the current exception
+ public JsEngineException(string message, string engineMode, Exception innerException)
+ : base(message, engineMode, innerException)
+ {
+ Category = JsErrorCategory.Engine;
+ }
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ protected JsEngineException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ { }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsEngineLoadException.cs b/src/MsieJavaScriptEngine/JsEngineLoadException.cs
index 19faf1b..a6b7084 100644
--- a/src/MsieJavaScriptEngine/JsEngineLoadException.cs
+++ b/src/MsieJavaScriptEngine/JsEngineLoadException.cs
@@ -1,11 +1,19 @@
-namespace MsieJavaScriptEngine
-{
- using System;
+using System;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#endif
+
+using MsieJavaScriptEngine.Constants;
+namespace MsieJavaScriptEngine
+{
///
- /// The exception that is thrown when a loading of JavaScript engine is failed
+ /// The exception that is thrown when a loading of JS engine is failed
///
- public sealed class JsEngineLoadException : JsException
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
+ public sealed class JsEngineLoadException : JsEngineException
{
///
/// Initializes a new instance of the class
@@ -13,38 +21,59 @@ public sealed class JsEngineLoadException : JsException
///
/// The message that describes the error
public JsEngineLoadException(string message)
- : this(message, string.Empty)
- { }
+ : base(message)
+ {
+ Category = JsErrorCategory.EngineLoad;
+ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
///
/// The error message that explains the reason for the exception
/// The exception that is the cause of the current exception
public JsEngineLoadException(string message, Exception innerException)
- : this(message, string.Empty, innerException)
- { }
+ : base(message, innerException)
+ {
+ Category = JsErrorCategory.EngineLoad;
+ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
///
/// The error message that explains the reason for the exception
- /// Name of JavaScript engine mode
+ /// Name of JS engine mode
public JsEngineLoadException(string message, string engineMode)
- : this(message, engineMode, null)
- { }
+ : base(message, engineMode)
+ {
+ Category = JsErrorCategory.EngineLoad;
+ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
///
/// The error message that explains the reason for the exception
- /// Name of JavaScript engine mode
+ /// Name of JS engine mode
/// The exception that is the cause of the current exception
public JsEngineLoadException(string message, string engineMode, Exception innerException)
: base(message, engineMode, innerException)
+ {
+ Category = JsErrorCategory.EngineLoad;
+ }
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ private JsEngineLoadException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
{ }
+#endif
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsEngineMode.cs b/src/MsieJavaScriptEngine/JsEngineMode.cs
index 495b99d..172c2b8 100644
--- a/src/MsieJavaScriptEngine/JsEngineMode.cs
+++ b/src/MsieJavaScriptEngine/JsEngineMode.cs
@@ -1,36 +1,38 @@
namespace MsieJavaScriptEngine
{
///
- /// JavaScript engine modes
+ /// JS engine modes
///
public enum JsEngineMode
{
///
- /// Automatically selects the most modern JavaScript engine from available on the machine
+ /// Automatically selects the most modern JS engine from available on the machine
///
Auto = 0,
///
- /// Classic MSIE JavaScript engine (supports ECMAScript 3 with
- /// possibility of using the ECMAScript 5 Polyfill and the JSON2 library).
+ /// Classic MSIE JS engine (supports ECMAScript 3 with possibility of using
+ /// the ECMAScript 5 Polyfill and the JSON2 library).
/// Requires Internet Explorer 6 or higher on the machine.
+ /// Not supported in version for .NET Core.
///
Classic,
///
- /// ActiveScript version of Chakra JavaScript engine (supports ECMAScript 5).
+ /// ActiveScript version of Chakra JS engine (supports ECMAScript 5).
/// Requires Internet Explorer 9 or higher on the machine.
+ /// Not supported in version for .NET Core.
///
ChakraActiveScript,
///
- /// “IE” JsRT version of Chakra JavaScript engine (supports ECMAScript 5).
+ /// “IE” JsRT version of Chakra JS engine (supports ECMAScript 5).
/// Requires Internet Explorer 11 or Microsoft Edge on the machine.
///
ChakraIeJsRt,
///
- /// “Edge” JsRT version of Chakra JavaScript engine (supports ECMAScript 5).
+ /// “Edge” JsRT version of Chakra JS engine (supports ECMAScript 5).
/// Requires Microsoft Edge on the machine.
///
ChakraEdgeJsRt
diff --git a/src/MsieJavaScriptEngine/JsEngineSettings.cs b/src/MsieJavaScriptEngine/JsEngineSettings.cs
index 4102a28..ff92ee5 100644
--- a/src/MsieJavaScriptEngine/JsEngineSettings.cs
+++ b/src/MsieJavaScriptEngine/JsEngineSettings.cs
@@ -1,13 +1,47 @@
-namespace MsieJavaScriptEngine
+using System;
+
+using MsieJavaScriptEngine.Resources;
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine
{
///
- /// JavaScript engine settings
+ /// JS engine settings
///
public sealed class JsEngineSettings
{
+#if !NETSTANDARD1_3
+ ///
+ /// The stack size is sufficient to run the code of modern JavaScript libraries in 32-bit process
+ ///
+ const int STACK_SIZE_32 = 492 * 1024; // like 32-bit Node.js
+
+ ///
+ /// The stack size is sufficient to run the code of modern JavaScript libraries in 64-bit process
+ ///
+ const int STACK_SIZE_64 = 984 * 1024; // like 64-bit Node.js
+
+ ///
+ /// The maximum stack size in bytes
+ ///
+ private int _maxStackSize;
+
+#endif
+ ///
+ /// Gets or sets a flag for whether to allow the usage of reflection API in the script code
+ ///
+ ///
+ /// This affects , Exception.GetType ,
+ /// Exception.TargetSite and Delegate.Method .
+ ///
+ public bool AllowReflection
+ {
+ get;
+ set;
+ }
+
///
/// Gets or sets a flag for whether to enable script debugging features
- /// (only works in the ChakraIeJsRt and ChakraEdgeJsRt modes)
///
public bool EnableDebugging
{
@@ -16,13 +50,39 @@ public bool EnableDebugging
}
///
- /// Gets or sets a JavaScript engine mode
+ /// Gets or sets a JS engine mode
///
public JsEngineMode EngineMode
{
get;
set;
}
+#if !NETSTANDARD1_3
+
+ ///
+ /// Gets or sets a maximum stack size in bytes
+ ///
+ ///
+ /// Set a 0 to use the default maximum stack size specified in the header
+ /// for the executable.
+ ///
+ public int MaxStackSize
+ {
+ get { return _maxStackSize; }
+ set
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(value),
+ CommonStrings.Engine_MaxStackSizeMustBeNonNegative
+ );
+ }
+
+ _maxStackSize = value;
+ }
+ }
+#endif
///
/// Gets or sets a flag for whether to use the ECMAScript 5 Polyfill
@@ -44,14 +104,28 @@ public bool UseJson2Library
///
- /// Constructs instance of JavaScript engine settings
+ /// Constructs an instance of JS engine settings
///
public JsEngineSettings()
{
+ AllowReflection = false;
EnableDebugging = false;
EngineMode = JsEngineMode.Auto;
+#if !NETSTANDARD1_3
+ MaxStackSize = Utils.Is64BitProcess() ? STACK_SIZE_64 : STACK_SIZE_32;
+#endif
UseEcmaScript5Polyfill = false;
UseJson2Library = false;
}
+
+
+ ///
+ /// Creates a new object that is a copy of the current instance
+ ///
+ /// A new object that is a copy of this instance
+ public JsEngineSettings Clone()
+ {
+ return (JsEngineSettings)MemberwiseClone();
+ }
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsException.cs b/src/MsieJavaScriptEngine/JsException.cs
index 85808f6..e97d5f2 100644
--- a/src/MsieJavaScriptEngine/JsException.cs
+++ b/src/MsieJavaScriptEngine/JsException.cs
@@ -1,19 +1,66 @@
-namespace MsieJavaScriptEngine
-{
- using System;
+using System;
+using System.Text;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#if !NET10_0_OR_GREATER
+using System.Security.Permissions;
+#endif
+#endif
+
+using AdvancedStringBuilder;
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Helpers;
+
+namespace MsieJavaScriptEngine
+{
///
- /// The exception that is thrown during the work of JavaScript engine
+ /// The exception that is thrown during the work of JS engine
///
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
public class JsException : Exception
{
///
- /// Gets a name of JavaScript engine mode
+ /// Name of JS engine mode
+ ///
+ private readonly string _engineMode = string.Empty;
+
+ ///
+ /// Error category
+ ///
+ private string _category = JsErrorCategory.Unknown;
+
+ ///
+ /// Description of error
+ ///
+ private string _description = string.Empty;
+
+ ///
+ /// Gets a name of JS engine mode
///
public string EngineMode
{
- get;
- private set;
+ get { return _engineMode; }
+ }
+
+ ///
+ /// Gets or sets a error category
+ ///
+ public string Category
+ {
+ get { return _category; }
+ set { _category = value; }
+ }
+
+ ///
+ /// Gets or sets a description of error
+ ///
+ public string Description
+ {
+ get { return _description; }
+ set { _description = value; }
}
@@ -23,40 +70,131 @@ public string EngineMode
///
/// The message that describes the error
public JsException(string message)
- : this(message, string.Empty)
+ : base(message)
{ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
///
/// The error message that explains the reason for the exception
/// The exception that is the cause of the current exception
public JsException(string message, Exception innerException)
- : this(message, string.Empty, innerException)
+ : base(message, innerException)
{ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
///
/// The error message that explains the reason for the exception
- /// Name of JavaScript engine mode
+ /// Name of JS engine mode
public JsException(string message, string engineMode)
: this(message, engineMode, null)
{ }
///
/// Initializes a new instance of the class
- /// with a specified error message and a reference to the inner exception that is the cause of this exception
///
/// The error message that explains the reason for the exception
- /// Name of JavaScript engine mode
+ /// Name of JS engine mode
/// The exception that is the cause of the current exception
public JsException(string message, string engineMode, Exception innerException)
: base(message, innerException)
{
- EngineMode = engineMode;
+ _engineMode = engineMode;
}
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ protected JsException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ if (info is not null)
+ {
+ _engineMode = info.GetString("EngineMode");
+ _category = info.GetString("Category");
+ _description = info.GetString("Description");
+ }
+ }
+
+
+ #region Exception overrides
+
+ ///
+ /// Populates a with the data needed to serialize the target object
+ ///
+ /// The to populate with data
+ /// The destination (see ) for this serialization
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#else
+ [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
+#endif
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info is null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+
+ base.GetObjectData(info, context);
+ info.AddValue("EngineMode", _engineMode);
+ info.AddValue("Category", _category);
+ info.AddValue("Description", _description);
+ }
+
+ #endregion
+#endif
+
+ #region Object overrides
+
+ ///
+ /// Returns a string that represents the current exception
+ ///
+ /// A string that represents the current exception
+ public override string ToString()
+ {
+ string errorDetails = JsErrorHelpers.GenerateErrorDetails(this, true);
+
+ var stringBuilderPool = StringBuilderPool.Shared;
+ StringBuilder resultBuilder = stringBuilderPool.Rent();
+ resultBuilder.Append(this.GetType().FullName);
+ resultBuilder.Append(": ");
+ resultBuilder.Append(this.Message);
+
+ if (errorDetails.Length > 0)
+ {
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine();
+ resultBuilder.Append(errorDetails);
+ }
+
+ if (this.InnerException is not null)
+ {
+ resultBuilder.Append(" ---> ");
+ resultBuilder.Append(this.InnerException.ToString());
+ }
+
+ if (this.StackTrace is not null)
+ {
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine(this.StackTrace);
+ }
+
+ string result = resultBuilder.ToString();
+ stringBuilderPool.Return(resultBuilder);
+
+ return result;
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsFatalException.cs b/src/MsieJavaScriptEngine/JsFatalException.cs
new file mode 100644
index 0000000..43f2400
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsFatalException.cs
@@ -0,0 +1,79 @@
+using System;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#endif
+
+using MsieJavaScriptEngine.Constants;
+
+namespace MsieJavaScriptEngine
+{
+ ///
+ /// The fatal exception occurred
+ ///
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
+ public sealed class JsFatalException : JsException
+ {
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message
+ ///
+ /// The message that describes the error
+ public JsFatalException(string message)
+ : base(message)
+ {
+ Category = JsErrorCategory.Fatal;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
+ ///
+ /// The error message that explains the reason for the exception
+ /// The exception that is the cause of the current exception
+ public JsFatalException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ Category = JsErrorCategory.Fatal;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ public JsFatalException(string message, string engineMode)
+ : base(message, engineMode)
+ {
+ Category = JsErrorCategory.Fatal;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ /// The exception that is the cause of the current exception
+ public JsFatalException(string message, string engineMode, Exception innerException)
+ : base(message, engineMode, innerException)
+ {
+ Category = JsErrorCategory.Fatal;
+ }
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ private JsFatalException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ { }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsInterruptedException.cs b/src/MsieJavaScriptEngine/JsInterruptedException.cs
new file mode 100644
index 0000000..ec40bad
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsInterruptedException.cs
@@ -0,0 +1,79 @@
+using System;
+#if !NETSTANDARD1_3
+using System.Runtime.Serialization;
+#endif
+
+using MsieJavaScriptEngine.Constants;
+
+namespace MsieJavaScriptEngine
+{
+ ///
+ /// The exception that is thrown when script execution is interrupted by the host
+ ///
+#if !NETSTANDARD1_3
+ [Serializable]
+#endif
+ public sealed class JsInterruptedException : JsRuntimeException
+ {
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message
+ ///
+ /// The message that describes the error
+ public JsInterruptedException(string message)
+ : base(message)
+ {
+ Category = JsErrorCategory.Interrupted;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception
+ /// that is the cause of this exception
+ ///
+ /// The error message that explains the reason for the exception
+ /// The exception that is the cause of the current exception
+ public JsInterruptedException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ Category = JsErrorCategory.Interrupted;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ public JsInterruptedException(string message, string engineMode)
+ : base(message, engineMode)
+ {
+ Category = JsErrorCategory.Interrupted;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The error message that explains the reason for the exception
+ /// Name of JS engine mode
+ /// The exception that is the cause of the current exception
+ public JsInterruptedException(string message, string engineMode, Exception innerException)
+ : base(message, engineMode, innerException)
+ {
+ Category = JsErrorCategory.Interrupted;
+ }
+#if !NETSTANDARD1_3
+
+ ///
+ /// Initializes a new instance of the class with serialized data
+ ///
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
+ private JsInterruptedException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ { }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/ChakraJsRtJsEngineBase.cs b/src/MsieJavaScriptEngine/JsRt/ChakraJsRtJsEngineBase.cs
index d724440..3c467d9 100644
--- a/src/MsieJavaScriptEngine/JsRt/ChakraJsRtJsEngineBase.cs
+++ b/src/MsieJavaScriptEngine/JsRt/ChakraJsRtJsEngineBase.cs
@@ -1,90 +1,35 @@
-namespace MsieJavaScriptEngine.JsRt
-{
- using System;
-
- using Helpers;
+using System;
+namespace MsieJavaScriptEngine.JsRt
+{
///
- /// Base class of the Chakra JsRT JavaScript engine
+ /// JsRT version of Chakra JS engine
///
- internal abstract class ChakraJsRtJsEngineBase : IInnerJsEngine
+ internal abstract class ChakraJsRtJsEngineBase : InnerJsEngineBase
{
///
- /// JavaScript engine mode
- ///
- protected readonly JsEngineMode _engineMode;
-
- ///
- /// Name of JavaScript engine mode
- ///
- protected readonly string _engineModeName;
-
- ///
- /// Flag for whether to enable script debugging features
- ///
- protected readonly bool _enableDebugging;
-
- ///
- /// Flag indicating whether debugging started
+ /// JS source context
///
- private StatedFlag _debuggingStartedFlag;
-
+ protected JsSourceContext _jsSourceContext = JsSourceContext.FromIntPtr(IntPtr.Zero);
///
- /// Constructs instance of the Chakra JsRT JavaScript engine
+ /// Script dispatcher
///
- /// JavaScript engine mode
- /// Flag for whether to enable script debugging features
- protected ChakraJsRtJsEngineBase(JsEngineMode engineMode, bool enableDebugging)
- {
- _engineMode = engineMode;
- _engineModeName = JsEngineModeHelpers.GetModeName(engineMode);
- _enableDebugging = enableDebugging;
- }
+ protected ScriptDispatcher _dispatcher;
///
- /// Starts debugging
+ /// Constructs an instance of the Chakra JsRT engine
///
- protected void StartDebugging()
+ /// JS engine settings
+ protected ChakraJsRtJsEngineBase(JsEngineSettings settings)
+ : base(settings)
{
- if (_debuggingStartedFlag.Set())
- {
- InnerStartDebugging();
- }
+#if NETSTANDARD1_3
+ _dispatcher = new ScriptDispatcher();
+#else
+ _dispatcher = new ScriptDispatcher(settings.MaxStackSize);
+#endif
}
-
- protected abstract void InnerStartDebugging();
-
- #region IInnerJsEngine implementation
-
- public abstract string Mode { get; }
-
-
- public abstract object Evaluate(string expression);
-
- public abstract void Execute(string code);
-
- public abstract object CallFunction(string functionName, params object[] args);
-
- public abstract bool HasVariable(string variableName);
-
- public abstract object GetVariableValue(string variableName);
-
- public abstract void SetVariableValue(string variableName, object value);
-
- public abstract void RemoveVariable(string variableName);
-
- public abstract void EmbedHostObject(string itemName, object value);
-
- public abstract void EmbedHostType(string itemName, Type type);
-
- #endregion
-
- #region IDisposable implementation
-
- public abstract void Dispose();
-
- #endregion
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs b/src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs
index 2d95218..4f0b1c2 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs
@@ -1,84 +1,107 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
+using System;
+
+using MsieJavaScriptEngine.Constants;
+using MsieJavaScriptEngine.Extensions;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.Resources;
+
+using WrapperCompilationException = MsieJavaScriptEngine.JsCompilationException;
+using WrapperEngineException = MsieJavaScriptEngine.JsEngineException;
+using WrapperEngineLoadException = MsieJavaScriptEngine.JsEngineLoadException;
+using WrapperException = MsieJavaScriptEngine.JsException;
+using WrapperFatalException = MsieJavaScriptEngine.JsFatalException;
+using WrapperInterruptedException = MsieJavaScriptEngine.JsInterruptedException;
+using WrapperRuntimeException = MsieJavaScriptEngine.JsRuntimeException;
+using WrapperScriptException = MsieJavaScriptEngine.JsScriptException;
+using WrapperUsageException = MsieJavaScriptEngine.JsUsageException;
+
+using OriginalEngineException = MsieJavaScriptEngine.JsRt.JsEngineException;
+using OriginalException = MsieJavaScriptEngine.JsRt.JsException;
+using OriginalFatalException = MsieJavaScriptEngine.JsRt.JsFatalException;
+using OriginalScriptException = MsieJavaScriptEngine.JsRt.Edge.EdgeJsScriptException;
+using OriginalUsageException = MsieJavaScriptEngine.JsRt.JsUsageException;
+
+namespace MsieJavaScriptEngine.JsRt.Edge
{
- using System;
- using System.Globalization;
- using System.Linq;
-
- using Constants;
- using Resources;
- using Utilities;
-
///
- /// “Edge” JsRT version of Chakra JavaScript engine
+ /// “Edge” JsRT version of Chakra JS engine
///
internal sealed class ChakraEdgeJsRtJsEngine : ChakraJsRtJsEngineBase
{
///
- /// Instance of JavaScript runtime
+ /// Instance of JS runtime
///
private EdgeJsRuntime _jsRuntime;
///
- /// Instance of JavaScript context
+ /// Instance of JS context
///
- private readonly EdgeJsContext _jsContext;
+ private EdgeJsContext _jsContext;
///
- /// Flag indicating whether this JavaScript engine is supported
- ///
- private static bool? _isSupported;
-
- ///
- /// Support synchronizer
+ /// Type mapper
///
- private static readonly object _supportSynchronizer = new object();
+ private EdgeTypeMapper _typeMapper;
///
- /// Run synchronizer
+ /// Flag indicating whether this JS engine is supported
///
- private readonly object _runSynchronizer = new object();
+ private static bool? _isSupported;
///
- /// Flag that object is destroyed
+ /// Support synchronizer
///
- private StatedFlag _disposedFlag = new StatedFlag();
+ private static readonly Lock _supportSynchronizer = new Lock();
///
- /// Constructs instance of the Chakra “Edge” JsRT JavaScript engine
+ /// Constructs an instance of the Chakra “Edge” JsRT engine
///
- /// Flag for whether to enable script debugging features
- public ChakraEdgeJsRtJsEngine(bool enableDebugging)
- : base(JsEngineMode.ChakraEdgeJsRt, enableDebugging)
+ /// JS engine settings
+ public ChakraEdgeJsRtJsEngine(JsEngineSettings settings)
+ : base(settings)
{
+ _typeMapper = new EdgeTypeMapper(settings.AllowReflection);
+
try
{
- _jsRuntime = CreateJsRuntime();
- _jsContext = _jsRuntime.CreateContext();
+ _dispatcher.Invoke(() =>
+ {
+ _jsRuntime = CreateJsRuntime();
+ _jsContext = _jsRuntime.CreateContext();
+ if (_jsContext.IsValid)
+ {
+ _jsContext.AddRef();
+
+ if (_settings.EnableDebugging)
+ {
+ using (new EdgeJsScope(_jsContext))
+ {
+ EdgeJsContext.StartDebugging();
+ }
+ }
+ }
+ });
}
- catch (JsUsageException e)
+ catch (DllNotFoundException e)
{
- string errorMessage;
- if (e.ErrorCode == JsErrorCode.WrongThread)
- {
- errorMessage = Strings.Runtime_JsEnginesConflictOnMachine;
- }
- else
- {
- errorMessage = string.Format(Strings.Runtime_EdgeJsEngineNotLoaded, e.Message);
- }
-
- throw new JsEngineLoadException(errorMessage, _engineModeName);
+ throw WrapDllNotFoundException(e);
}
catch (Exception e)
{
- throw new JsEngineLoadException(
- string.Format(Strings.Runtime_EdgeJsEngineNotLoaded, e.Message), _engineModeName);
+ throw JsErrorHelpers.WrapEngineLoadException(e, _engineModeName, true);
+ }
+ finally
+ {
+ if (!_jsContext.IsValid)
+ {
+ Dispose();
+ }
}
}
///
- /// Destructs instance of the Chakra “Edge” JsRT JavaScript engine
+ /// Destructs an instance of the Chakra “Edge” JsRT engine
///
~ChakraEdgeJsRtJsEngine()
{
@@ -87,20 +110,18 @@ public ChakraEdgeJsRtJsEngine(bool enableDebugging)
///
- /// Creates a instance of JavaScript runtime with special settings
+ /// Creates a instance of JS runtime with special settings
///
- /// Instance of JavaScript runtime with special settings
+ /// Instance of JS runtime with special settings
private static EdgeJsRuntime CreateJsRuntime()
{
- var jsRuntime = EdgeJsRuntime.Create(JsRuntimeAttributes.AllowScriptInterrupt, null);
-
- return jsRuntime;
+ return EdgeJsRuntime.Create(JsRuntimeAttributes.AllowScriptInterrupt, null);
}
///
- /// Checks a support of the Chakra “Edge” JsRT JavaScript engine
+ /// Checks a support of the Chakra “Edge” JsRT engine
///
- /// Result of check (true - supports; false - does not support)
+ /// Result of check (true - supports; false - does not support)
public static bool IsSupported()
{
if (_isSupported.HasValue)
@@ -124,7 +145,7 @@ public static bool IsSupported()
}
catch (DllNotFoundException e)
{
- if (e.Message.IndexOf("'" + DllName.Chakra + "'", StringComparison.OrdinalIgnoreCase) != -1)
+ if (e.Message.ContainsQuotedValue(DllName.Chakra))
{
_isSupported = false;
}
@@ -143,294 +164,438 @@ public static bool IsSupported()
}
///
- /// Makes a mapping of value from the host type to a script type
+ /// Adds a reference to the value
///
- /// The source value
- /// The mapped value
- private EdgeJsValue MapToScriptType(object value)
+ /// The value
+ private static void AddReferenceToValue(EdgeJsValue value)
{
- if (value == null)
- {
- return EdgeJsValue.Null;
- }
-
- if (value is Undefined)
+ if (CanHaveReferences(value))
{
- return EdgeJsValue.Undefined;
- }
-
- var typeCode = Type.GetTypeCode(value.GetType());
-
- switch (typeCode)
- {
- case TypeCode.Boolean:
- return EdgeJsValue.FromBoolean((bool)value);
- case TypeCode.Int32:
- return EdgeJsValue.FromInt32((int)value);
- case TypeCode.Double:
- return EdgeJsValue.FromDouble((double)value);
- case TypeCode.String:
- return EdgeJsValue.FromString((string)value);
- default:
- object processedValue = !TypeConverter.IsPrimitiveType(typeCode) ?
- new HostObject(value, _engineMode) : value;
- return EdgeJsValue.FromObject(processedValue);
+ value.AddRef();
}
}
///
- /// Makes a mapping of array items from the host type to a script type
+ /// Removes a reference to the value
///
- /// The source array
- /// The mapped array
- private EdgeJsValue[] MapToScriptType(object[] args)
+ /// The value
+ private static void RemoveReferenceToValue(EdgeJsValue value)
{
- return args.Select(MapToScriptType).ToArray();
+ if (CanHaveReferences(value))
+ {
+ value.Release();
+ }
}
///
- /// Makes a mapping of value from the script type to a host type
+ /// Checks whether the value can have references
///
- /// The source value
- /// The mapped value
- private object MapToHostType(EdgeJsValue value)
+ /// The value
+ /// Result of check (true - may have; false - may not have)
+ private static bool CanHaveReferences(EdgeJsValue value)
{
JsValueType valueType = value.ValueType;
- EdgeJsValue processedValue;
- object result;
switch (valueType)
{
case JsValueType.Null:
- result = null;
- break;
case JsValueType.Undefined:
- result = Undefined.Value;
- break;
case JsValueType.Boolean:
- processedValue = value.ConvertToBoolean();
- result = processedValue.ToBoolean();
- break;
- case JsValueType.Number:
- processedValue = value.ConvertToNumber();
- result = processedValue.ToDouble();
- break;
- case JsValueType.String:
- processedValue = value.ConvertToString();
- result = processedValue.ToString();
- break;
- case JsValueType.Object:
- case JsValueType.Function:
- case JsValueType.Error:
- case JsValueType.Array:
- processedValue = value.ConvertToObject();
- object obj = processedValue.ToObject();
-
- if (!TypeConverter.IsPrimitiveType(obj.GetType()))
- {
- var hostObj = obj as HostObject;
- result = hostObj != null ? hostObj.Target : obj;
- }
- else
- {
- result = obj;
- }
- break;
+ return false;
default:
- throw new ArgumentOutOfRangeException();
+ return true;
}
-
- return result;
}
- ///
- /// Makes a mapping of array items from the script type to a host type
- ///
- /// The source array
- /// The mapped array
- private object[] MapToHostType(EdgeJsValue[] args)
- {
- return args.Select(MapToHostType).ToArray();
- }
+ #region Mapping
- private JsRuntimeException ConvertJsExceptionToJsRuntimeException(
- JsException jsException)
+ private WrapperException WrapJsException(OriginalException originalException,
+ string defaultDocumentName = null)
{
- string message = jsException.Message;
- string category = string.Empty;
+ WrapperException wrapperException;
+ JsErrorCode errorCode = originalException.ErrorCode;
+ string description = originalException.Message;
+ string message = description;
+ string type = string.Empty;
+ string documentName = defaultDocumentName ?? string.Empty;
int lineNumber = 0;
int columnNumber = 0;
+ string callStack = string.Empty;
string sourceFragment = string.Empty;
- var jsScriptException = jsException as EdgeJsScriptException;
- if (jsScriptException != null)
+ var originalScriptException = originalException as OriginalScriptException;
+ if (originalScriptException is not null)
{
- category = "Script error";
- EdgeJsValue errorValue = jsScriptException.Error;
+ EdgeJsValue errorValue = originalScriptException.Error;
- EdgeJsPropertyId messagePropertyId = EdgeJsPropertyId.FromString("message");
- EdgeJsValue messagePropertyValue = errorValue.GetProperty(messagePropertyId);
- string scriptMessage = messagePropertyValue.ConvertToString().ToString();
- if (!string.IsNullOrWhiteSpace(scriptMessage))
+ if (errorValue.IsValid)
{
- message = string.Format("{0}: {1}", message.TrimEnd('.'), scriptMessage);
- }
+ JsValueType errorValueType = errorValue.ValueType;
- EdgeJsPropertyId linePropertyId = EdgeJsPropertyId.FromString("line");
- if (errorValue.HasProperty(linePropertyId))
- {
- EdgeJsValue linePropertyValue = errorValue.GetProperty(linePropertyId);
- lineNumber = (int)linePropertyValue.ConvertToNumber().ToDouble() + 1;
+ if (errorValueType == JsValueType.Error
+ || errorValueType == JsValueType.Object)
+ {
+ EdgeJsValue messagePropertyValue = errorValue.GetProperty("message");
+ string localDescription = messagePropertyValue.ConvertToString().ToString();
+ if (!string.IsNullOrWhiteSpace(localDescription))
+ {
+ description = localDescription;
+ }
+
+ EdgeJsValue namePropertyValue = errorValue.GetProperty("name");
+ type = namePropertyValue.ValueType == JsValueType.String ?
+ namePropertyValue.ToString() : string.Empty;
+
+ EdgeJsPropertyId descriptionPropertyId = EdgeJsPropertyId.FromString("description");
+ if (errorValue.HasProperty(descriptionPropertyId))
+ {
+ EdgeJsValue descriptionPropertyValue = errorValue.GetProperty(descriptionPropertyId);
+ localDescription = descriptionPropertyValue.ConvertToString().ToString();
+ if (!string.IsNullOrWhiteSpace(localDescription))
+ {
+ description = localDescription;
+ }
+ }
+
+ if (type == JsErrorType.Syntax)
+ {
+ errorCode = JsErrorCode.ScriptCompile;
+ }
+ else
+ {
+ EdgeJsPropertyId numberPropertyId = EdgeJsPropertyId.FromString("number");
+ if (errorValue.HasProperty(numberPropertyId))
+ {
+ EdgeJsValue numberPropertyValue = errorValue.GetProperty(numberPropertyId);
+ int errorNumber = numberPropertyValue.ValueType == JsValueType.Number ?
+ numberPropertyValue.ToInt32() : 0;
+ errorCode = (JsErrorCode)errorNumber;
+ }
+ }
+
+ EdgeJsPropertyId stackPropertyId = EdgeJsPropertyId.FromString("stack");
+ if (errorValue.HasProperty(stackPropertyId))
+ {
+ EdgeJsValue stackPropertyValue = errorValue.GetProperty(stackPropertyId);
+ string messageWithTypeAndCallStack = stackPropertyValue.ValueType == JsValueType.String ?
+ stackPropertyValue.ToString() : string.Empty;
+ string messageWithType = errorValue.ConvertToString().ToString();
+ string rawCallStack = JsErrorHelpers.GetCallStackFromMessage(
+ messageWithTypeAndCallStack, messageWithType);
+ CallStackItem[] callStackItems = JsErrorHelpers.ParseCallStack(rawCallStack);
+
+ if (callStackItems.Length > 0)
+ {
+ CallStackItem firstCallStackItem = callStackItems[0];
+ if (firstCallStackItem.DocumentName.Length > 0)
+ {
+ documentName = firstCallStackItem.DocumentName;
+ }
+ lineNumber = firstCallStackItem.LineNumber;
+ columnNumber = firstCallStackItem.ColumnNumber;
+ callStack = JsErrorHelpers.StringifyCallStackItems(callStackItems);
+ }
+
+ message = JsErrorHelpers.GenerateScriptErrorMessage(type, description, callStack);
+ }
+ else
+ {
+ EdgeJsPropertyId urlPropertyId = EdgeJsPropertyId.FromString("url");
+ if (errorValue.HasProperty(urlPropertyId))
+ {
+ EdgeJsValue urlPropertyValue = errorValue.GetProperty(urlPropertyId);
+ documentName = urlPropertyValue.ValueType == JsValueType.String ?
+ urlPropertyValue.ToString() : string.Empty;
+ }
+
+ EdgeJsPropertyId linePropertyId = EdgeJsPropertyId.FromString("line");
+ if (errorValue.HasProperty(linePropertyId))
+ {
+ EdgeJsValue linePropertyValue = errorValue.GetProperty(linePropertyId);
+ lineNumber = linePropertyValue.ValueType == JsValueType.Number ?
+ linePropertyValue.ToInt32() + 1 : 0;
+ }
+
+ EdgeJsPropertyId columnPropertyId = EdgeJsPropertyId.FromString("column");
+ if (errorValue.HasProperty(columnPropertyId))
+ {
+ EdgeJsValue columnPropertyValue = errorValue.GetProperty(columnPropertyId);
+ columnNumber = columnPropertyValue.ValueType == JsValueType.Number ?
+ columnPropertyValue.ToInt32() + 1 : 0;
+ }
+
+ string sourceLine = string.Empty;
+ EdgeJsPropertyId sourcePropertyId = EdgeJsPropertyId.FromString("source");
+ if (errorValue.HasProperty(sourcePropertyId))
+ {
+ EdgeJsValue sourcePropertyValue = errorValue.GetProperty(sourcePropertyId);
+ sourceLine = sourcePropertyValue.ValueType == JsValueType.String ?
+ sourcePropertyValue.ToString() : string.Empty;
+ if (sourceLine != "undefined")
+ {
+ sourceFragment = TextHelpers.GetTextFragmentFromLine(sourceLine, columnNumber);
+ }
+ }
+
+ message = JsErrorHelpers.GenerateScriptErrorMessage(type, description, documentName,
+ lineNumber, columnNumber, sourceFragment);
+ }
+ }
+ else if (errorValueType == JsValueType.String)
+ {
+ message = errorValue.ToString();
+ description = message;
+ }
+ else
+ {
+ message = errorValue.ConvertToString().ToString();
+ description = message;
+ }
}
- EdgeJsPropertyId columnPropertyId = EdgeJsPropertyId.FromString("column");
- if (errorValue.HasProperty(columnPropertyId))
+ WrapperScriptException wrapperScriptException;
+ if (errorCode == JsErrorCode.ScriptCompile)
{
- EdgeJsValue columnPropertyValue = errorValue.GetProperty(columnPropertyId);
- columnNumber = (int)columnPropertyValue.ConvertToNumber().ToDouble() + 1;
+ wrapperScriptException = new WrapperCompilationException(message, _engineModeName,
+ originalScriptException);
}
+ else if (errorCode == JsErrorCode.ScriptTerminated)
+ {
+ wrapperScriptException = new WrapperInterruptedException(CommonStrings.Runtime_ScriptInterrupted,
+ _engineModeName, originalScriptException);
- EdgeJsPropertyId sourcePropertyId = EdgeJsPropertyId.FromString("source");
- if (errorValue.HasProperty(sourcePropertyId))
+ // Restore a JS engine after interruption
+ _jsRuntime.Disabled = false;
+ }
+ else
{
- EdgeJsValue sourcePropertyValue = errorValue.GetProperty(sourcePropertyId);
- sourceFragment = sourcePropertyValue.ConvertToString().ToString();
+ wrapperScriptException = new WrapperRuntimeException(message, _engineModeName,
+ originalScriptException)
+ {
+ CallStack = callStack
+ };
}
+ wrapperScriptException.Type = type;
+ wrapperScriptException.DocumentName = documentName;
+ wrapperScriptException.LineNumber = lineNumber;
+ wrapperScriptException.ColumnNumber = columnNumber;
+ wrapperScriptException.SourceFragment = sourceFragment;
+
+ wrapperException = wrapperScriptException;
}
- else if (jsException is JsUsageException)
+ else
{
- category = "Usage error";
+ if (originalException is OriginalUsageException)
+ {
+ wrapperException = new WrapperUsageException(message, _engineModeName, originalException);
+ }
+ else if (originalException is OriginalEngineException)
+ {
+ wrapperException = new WrapperEngineException(message, _engineModeName, originalException);
+ }
+ else if (originalException is OriginalFatalException)
+ {
+ wrapperException = new WrapperFatalException(message, _engineModeName, originalException);
+ }
+ else
+ {
+ wrapperException = new WrapperException(message, _engineModeName, originalException);
+ }
}
- else if (jsException is JsEngineException)
+
+ wrapperException.Description = description;
+
+ return wrapperException;
+ }
+
+ private WrapperEngineLoadException WrapDllNotFoundException(
+ DllNotFoundException originalDllNotFoundException)
+ {
+ string originalMessage = originalDllNotFoundException.Message;
+ string description;
+ string message;
+
+ if (originalMessage.ContainsQuotedValue(DllName.Chakra))
{
- category = "Engine error";
+ description = string.Format(CommonStrings.Engine_AssemblyNotRegistered, DllName.Chakra) + " " +
+ CommonStrings.Engine_EdgeInstallationRequired;
+ message = JsErrorHelpers.GenerateEngineLoadErrorMessage(description, _engineModeName);
}
- else if (jsException is JsFatalException)
+ else
{
- category = "Fatal error";
+ description = originalMessage;
+ message = JsErrorHelpers.GenerateEngineLoadErrorMessage(description, _engineModeName, true);
}
- var jsEngineException = new JsRuntimeException(message, _engineModeName)
+ var wrapperEngineLoadException = new WrapperEngineLoadException(message, _engineModeName,
+ originalDllNotFoundException)
{
- ErrorCode = ((uint)jsException.ErrorCode).ToString(CultureInfo.InvariantCulture),
- Category = category,
- LineNumber = lineNumber,
- ColumnNumber = columnNumber,
- SourceFragment = sourceFragment,
- HelpLink = jsException.HelpLink
+ Description = description
};
- return jsEngineException;
+ return wrapperEngineLoadException;
}
- protected override void InnerStartDebugging()
+ #endregion
+
+ #region ChakraJsRtJsEngineBase overrides
+
+ #region IInnerJsEngine implementation
+
+ public override bool SupportsScriptPrecompilation
{
- EdgeJsContext.StartDebugging();
+ get { return true; }
}
- private void InvokeScript(Action action)
+
+ public override PrecompiledScript Precompile(string code, string documentName)
{
- lock (_runSynchronizer)
- using (new EdgeJsScope(_jsContext))
+ PrecompiledScript precompiledScript = _dispatcher.Invoke(() =>
{
- if (_enableDebugging)
+ using (new EdgeJsScope(_jsContext))
{
- StartDebugging();
- }
+ try
+ {
+ byte[] cachedBytes = EdgeJsContext.SerializeScript(code);
- try
- {
- action();
- }
- catch (JsException e)
- {
- throw ConvertJsExceptionToJsRuntimeException(e);
+ return new PrecompiledScript(_engineModeName, code, cachedBytes, documentName);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e, documentName);
+ }
}
- }
+ });
+
+ return precompiledScript;
}
- private T InvokeScript(Func func)
+ public override object Evaluate(string expression, string documentName)
{
- lock (_runSynchronizer)
- using (new EdgeJsScope(_jsContext))
+ object result = _dispatcher.Invoke(() =>
{
- if (_enableDebugging)
+ using (new EdgeJsScope(_jsContext))
{
- StartDebugging();
- }
+ try
+ {
+ EdgeJsValue resultValue = EdgeJsContext.RunScript(expression, _jsSourceContext++,
+ documentName);
- try
- {
- return func();
- }
- catch (JsException e)
- {
- throw ConvertJsExceptionToJsRuntimeException(e);
+ return _typeMapper.MapToHostType(resultValue);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
}
- }
+ });
+
+ return result;
}
- ///
- /// Destroys object
- ///
- /// Flag, allowing destruction of
- /// managed objects contained in fields of class
- private void Dispose(bool disposing)
+ public override void Execute(string code, string documentName)
{
- lock (_runSynchronizer)
+ _dispatcher.Invoke(() =>
{
- if (_disposedFlag.Set())
+ using (new EdgeJsScope(_jsContext))
{
- _jsRuntime.Dispose();
+ try
+ {
+ EdgeJsContext.RunScript(code, _jsSourceContext++, documentName);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
}
- }
- }
-
- #region IInnerJsEngine implementation
-
- public override string Mode
- {
- get { return _engineModeName; }
+ });
}
- public override object Evaluate(string expression)
+ public override void Execute(PrecompiledScript precompiledScript)
{
- object result = InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- EdgeJsValue resultValue = EdgeJsContext.RunScript(expression);
-
- return MapToHostType(resultValue);
+ using (new EdgeJsScope(_jsContext))
+ {
+ try
+ {
+ EdgeJsContext.RunSerializedScript(precompiledScript.Code, precompiledScript.CachedBytes,
+ _jsSourceContext++, precompiledScript.DocumentName);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ finally
+ {
+ GC.KeepAlive(precompiledScript);
+ }
+ }
});
-
- return result;
- }
-
- public override void Execute(string code)
- {
- InvokeScript(() => EdgeJsContext.RunScript(code));
}
public override object CallFunction(string functionName, params object[] args)
{
- object result = InvokeScript(() =>
+ object result = _dispatcher.Invoke(() =>
{
- EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
- EdgeJsPropertyId functionId = EdgeJsPropertyId.FromString(functionName);
-
- bool functionExist = globalObj.HasProperty(functionId);
- if (!functionExist)
+ using (new EdgeJsScope(_jsContext))
{
- throw new JsRuntimeException(
- string.Format(Strings.Runtime_FunctionNotExist, functionName));
+ try
+ {
+ EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
+ EdgeJsPropertyId functionId = EdgeJsPropertyId.FromString(functionName);
+
+ bool functionExist = globalObj.HasProperty(functionId);
+ if (!functionExist)
+ {
+ throw new WrapperRuntimeException(
+ string.Format(CommonStrings.Runtime_FunctionNotExist, functionName),
+ _engineModeName
+ );
+ }
+
+ EdgeJsValue resultValue;
+ EdgeJsValue functionValue = globalObj.GetProperty(functionId);
+
+ int argCount = args.Length;
+ if (argCount > 0)
+ {
+ int processedArgCount = argCount + 1;
+ var processedArgs = new EdgeJsValue[processedArgCount];
+ processedArgs[0] = globalObj;
+
+ for (int argIndex = 0; argIndex < argCount; argIndex++)
+ {
+ EdgeJsValue processedArg = _typeMapper.MapToScriptType(args[argIndex]);
+ AddReferenceToValue(processedArg);
+
+ processedArgs[argIndex + 1] = processedArg;
+ }
+
+ try
+ {
+ resultValue = functionValue.CallFunction(processedArgs);
+ }
+ finally
+ {
+ for (int argIndex = 1; argIndex < processedArgCount; argIndex++)
+ {
+ RemoveReferenceToValue(processedArgs[argIndex]);
+ }
+ }
+ }
+ else
+ {
+ resultValue = functionValue.CallFunction(globalObj);
+ }
+
+ return _typeMapper.MapToHostType(resultValue);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
}
-
- var processedArgs = MapToScriptType(args);
- var allProcessedArgs = new[] { globalObj }.Concat(processedArgs).ToArray();
-
- EdgeJsValue functionValue = globalObj.GetProperty(functionId);
- EdgeJsValue resultValue = functionValue.CallFunction(allProcessedArgs);
-
- return MapToHostType(resultValue);
});
return result;
@@ -438,19 +603,29 @@ public override object CallFunction(string functionName, params object[] args)
public override bool HasVariable(string variableName)
{
- bool result = InvokeScript(() =>
+ bool result = _dispatcher.Invoke(() =>
{
- EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
- EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
- bool variableExist = globalObj.HasProperty(variableId);
-
- if (variableExist)
+ using (new EdgeJsScope(_jsContext))
{
- EdgeJsValue variableValue = globalObj.GetProperty(variableId);
- variableExist = (variableValue.ValueType != JsValueType.Undefined);
- }
+ try
+ {
+ EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
+ EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
+ bool variableExist = globalObj.HasProperty(variableId);
+
+ if (variableExist)
+ {
+ EdgeJsValue variableValue = globalObj.GetProperty(variableId);
+ variableExist = variableValue.ValueType != JsValueType.Undefined;
+ }
- return variableExist;
+ return variableExist;
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ }
});
return result;
@@ -458,12 +633,21 @@ public override bool HasVariable(string variableName)
public override object GetVariableValue(string variableName)
{
- object result = InvokeScript(() =>
+ object result = _dispatcher.Invoke(() =>
{
- EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
- EdgeJsValue variableValue = EdgeJsValue.GlobalObject.GetProperty(variableId);
+ using (new EdgeJsScope(_jsContext))
+ {
+ try
+ {
+ EdgeJsValue variableValue = EdgeJsValue.GlobalObject.GetProperty(variableName);
- return MapToHostType(variableValue);
+ return _typeMapper.MapToHostType(variableValue);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ }
});
return result;
@@ -471,51 +655,104 @@ public override object GetVariableValue(string variableName)
public override void SetVariableValue(string variableName, object value)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
- EdgeJsValue inputValue = MapToScriptType(value);
-
- EdgeJsValue.GlobalObject.SetProperty(variableId, inputValue, true);
+ using (new EdgeJsScope(_jsContext))
+ {
+ try
+ {
+ EdgeJsValue inputValue = _typeMapper.MapToScriptType(value);
+ AddReferenceToValue(inputValue);
+
+ try
+ {
+ EdgeJsValue.GlobalObject.SetProperty(variableName, inputValue, true);
+ }
+ finally
+ {
+ RemoveReferenceToValue(inputValue);
+ }
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ }
});
}
public override void RemoveVariable(string variableName)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
- EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
-
- if (globalObj.HasProperty(variableId))
+ using (new EdgeJsScope(_jsContext))
{
- globalObj.SetProperty(variableId, EdgeJsValue.Undefined, true);
+ try
+ {
+ EdgeJsValue globalObj = EdgeJsValue.GlobalObject;
+ EdgeJsPropertyId variableId = EdgeJsPropertyId.FromString(variableName);
+
+ if (globalObj.HasProperty(variableId))
+ {
+ globalObj.SetProperty(variableId, EdgeJsValue.Undefined, true);
+ }
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
}
});
}
public override void EmbedHostObject(string itemName, object value)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- EdgeJsValue processedValue = MapToScriptType(value);
- EdgeJsPropertyId itemId = EdgeJsPropertyId.FromString(itemName);
-
- EdgeJsValue.GlobalObject.SetProperty(itemId, processedValue, true);
+ using (new EdgeJsScope(_jsContext))
+ {
+ try
+ {
+ EdgeJsValue processedValue = _typeMapper.GetOrCreateScriptObject(value);
+ EdgeJsValue.GlobalObject.SetProperty(itemName, processedValue, true);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ }
});
}
public override void EmbedHostType(string itemName, Type type)
{
- InvokeScript(() =>
+ _dispatcher.Invoke(() =>
{
- EdgeJsValue typeValue = EdgeJsValue.FromObject(new HostType(type, _engineMode));
- EdgeJsPropertyId itemId = EdgeJsPropertyId.FromString(itemName);
-
- EdgeJsValue.GlobalObject.SetProperty(itemId, typeValue, true);
+ using (new EdgeJsScope(_jsContext))
+ {
+ try
+ {
+ EdgeJsValue typeValue = _typeMapper.GetOrCreateScriptType(type);
+ EdgeJsValue.GlobalObject.SetProperty(itemName, typeValue, true);
+ }
+ catch (OriginalException e)
+ {
+ throw WrapJsException(e);
+ }
+ }
});
}
+ public override void Interrupt()
+ {
+ _jsRuntime.Disabled = true;
+ }
+
+ public override void CollectGarbage()
+ {
+ _jsRuntime.CollectGarbage();
+ }
+
#endregion
#region IDisposable implementation
@@ -529,6 +766,48 @@ public override void Dispose()
GC.SuppressFinalize(this);
}
+ ///
+ /// Destroys object
+ ///
+ /// Flag, allowing destruction of managed objects contained in fields of class
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_disposedFlag.Set())
+ {
+ if (_dispatcher is not null)
+ {
+ _dispatcher.Invoke(DisposeUnmanagedResources);
+
+ _dispatcher.Dispose();
+ _dispatcher = null;
+ }
+
+ if (_typeMapper is not null)
+ {
+ _typeMapper.Dispose();
+ _typeMapper = null;
+ }
+ }
+ }
+ else
+ {
+ DisposeUnmanagedResources();
+ }
+ }
+
+ private void DisposeUnmanagedResources()
+ {
+ if (_jsContext.IsValid)
+ {
+ _jsContext.Release();
+ }
+ _jsRuntime.Dispose();
+ }
+
+ #endregion
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsContext.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsContext.cs
index 45e4c9b..43027ea 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsContext.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsContext.cs
@@ -1,9 +1,7 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
-
- using JsRt;
+using System;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” script context
///
@@ -81,23 +79,6 @@ public static bool HasException
}
}
- ///
- /// Gets a value indicating whether the heap of the current context is being enumerated
- ///
- ///
- /// Requires an active script context.
- ///
- public static bool IsEnumeratingHeap
- {
- get
- {
- bool isEnumerating;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsIsEnumeratingHeap(out isEnumerating));
-
- return isEnumerating;
- }
- }
-
///
/// Gets a runtime that the context belongs to
///
@@ -149,10 +130,8 @@ internal EdgeJsContext(IntPtr reference)
/// Requires an active script context.
///
///
- ///
- /// The next system tick when there will be more idle work to do. Returns the
- /// maximum number of ticks if there no upcoming idle work to do.
- ///
+ /// The next system tick when there will be more idle work to do. Returns the
+ /// maximum number of ticks if there no upcoming idle work to do.
public static uint Idle()
{
uint ticks;
@@ -162,71 +141,53 @@ public static uint Idle()
}
///
- /// Parses a script and returns a Function representing the script
+ /// Parses a script and returns a function representing the script
///
///
/// Requires an active script context.
///
/// The script to parse
- /// The cookie identifying the script that can be used
+ /// A cookie identifying the script that can be used
/// by script contexts that have debugging enabled
/// The location the script came from
- /// The Function representing the script code
+ /// A function representing the script code
public static EdgeJsValue ParseScript(string script, JsSourceContext sourceContext, string sourceName)
{
EdgeJsValue result;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsParseScript(script, sourceContext, sourceName, out result));
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsParseScript(script, sourceContext, sourceName,
+ out result));
return result;
}
///
- /// Parses a serialized script and returns a Function representing the script
+ /// Parses a serialized script and returns a function representing the script
///
///
+ ///
/// Requires an active script context.
+ ///
+ ///
+ /// The runtime will hold on to the buffer until all instances of any functions created from
+ /// the buffer are garbage collected.
+ ///
///
/// The script to parse
/// The serialized script
- /// The cookie identifying the script that can be used
+ /// A cookie identifying the script that can be used
/// by script contexts that have debugging enabled
/// The location the script came from
- /// The Function representing the script code
- public static EdgeJsValue ParseScript(string script, byte[] buffer, JsSourceContext sourceContext, string sourceName)
+ /// A function representing the script code
+ public static EdgeJsValue ParseSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext,
+ string sourceName)
{
EdgeJsValue result;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsParseSerializedScript(script, buffer, sourceContext, sourceName, out result));
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsParseSerializedScript(script, buffer, sourceContext,
+ sourceName, out result));
return result;
}
- ///
- /// Parses a script and returns a Function representing the script
- ///
- ///
- /// Requires an active script context.
- ///
- /// The script to parse
- /// The Function representing the script code
- public static EdgeJsValue ParseScript(string script)
- {
- return ParseScript(script, JsSourceContext.None, string.Empty);
- }
-
- ///
- /// Parses a serialized script and returns a Function representing the script
- ///
- ///
- /// Requires an active script context.
- ///
- /// The script to parse
- /// The serialized script
- /// The Function representing the script code
- public static EdgeJsValue ParseScript(string script, byte[] buffer)
- {
- return ParseScript(script, buffer, JsSourceContext.None, string.Empty);
- }
-
///
/// Executes a script
///
@@ -234,14 +195,15 @@ public static EdgeJsValue ParseScript(string script, byte[] buffer)
/// Requires an active script context.
///
/// The script to run
- /// The cookie identifying the script that can be used
+ /// A cookie identifying the script that can be used
/// by script contexts that have debugging enabled
/// The location the script came from
/// The result of the script, if any
public static EdgeJsValue RunScript(string script, JsSourceContext sourceContext, string sourceName)
{
EdgeJsValue result;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsRunScript(script, sourceContext, sourceName, out result));
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsRunScript(script, sourceContext, sourceName,
+ out result));
return result;
}
@@ -250,55 +212,36 @@ public static EdgeJsValue RunScript(string script, JsSourceContext sourceContext
/// Runs a serialized script
///
///
+ ///
/// Requires an active script context.
+ ///
+ ///
+ /// The runtime will hold on to the buffer until all instances of any functions created from
+ /// the buffer are garbage collected.
+ ///
///
/// The source code of the serialized script
/// The serialized script
- /// The cookie identifying the script that can be used
+ /// A cookie identifying the script that can be used
/// by script contexts that have debugging enabled
/// The location the script came from
/// The result of the script, if any
- public static EdgeJsValue RunScript(string script, byte[] buffer, JsSourceContext sourceContext, string sourceName)
+ public static EdgeJsValue RunSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext,
+ string sourceName)
{
EdgeJsValue result;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsRunSerializedScript(script, buffer, sourceContext, sourceName, out result));
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsRunSerializedScript(script, buffer, sourceContext,
+ sourceName, out result));
return result;
}
- ///
- /// Executes a script
- ///
- ///
- /// Requires an active script context.
- ///
- /// The script to run
- /// The result of the script, if any
- public static EdgeJsValue RunScript(string script)
- {
- return RunScript(script, JsSourceContext.None, string.Empty);
- }
-
- ///
- /// Runs a serialized script
- ///
- ///
- /// Requires an active script context.
- ///
- /// The source code of the serialized script
- /// The serialized script
- /// The result of the script, if any
- public static EdgeJsValue RunScript(string script, byte[] buffer)
- {
- return RunScript(script, buffer, JsSourceContext.None, string.Empty);
- }
-
///
/// Serializes a parsed script to a buffer than can be reused
///
///
///
- /// SerializeScript parses a script and then stores the parsed form of the script in a
+ /// SerializeScript parses a script and then stores the parsed form of the script in a
/// runtime-independent format. The serialized script then can be deserialized in any
/// runtime without requiring the script to be re-parsed.
///
@@ -307,14 +250,21 @@ public static EdgeJsValue RunScript(string script, byte[] buffer)
///
///
/// The script to serialize
- /// The buffer to put the serialized script into. Can be null.
- /// The size of the buffer, in bytes, required to hold the serialized script
- public static ulong SerializeScript(string script, byte[] buffer)
+ /// The buffer to put the serialized script into
+ public static byte[] SerializeScript(string script)
{
- var bufferSize = (ulong)buffer.Length;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsSerializeScript(script, buffer, ref bufferSize));
+ byte[] buffer = null;
+ uint bufferSize = 0;
+
+ JsErrorCode errorCode = EdgeNativeMethods.JsSerializeScript(script, buffer, ref bufferSize);
+ EdgeJsErrorHelpers.ThrowIfError(errorCode);
+
+ buffer = new byte[(int)bufferSize];
- return bufferSize;
+ errorCode = EdgeNativeMethods.JsSerializeScript(script, buffer, ref bufferSize);
+ EdgeJsErrorHelpers.ThrowIfError(errorCode);
+
+ return buffer;
}
///
@@ -368,63 +318,11 @@ public static void StartDebugging()
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsStartDebugging());
}
- ///
- /// Starts profiling in the current context
- ///
- ///
- /// Requires an active script context.
- ///
- /// The profiling callback to use
- /// The profiling events to callback with
- /// A context to pass to the profiling callback
- public static void StartProfiling(IActiveScriptProfilerCallback callback, ProfilerEventMask eventMask, int context)
- {
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsStartProfiling(callback, eventMask, context));
- }
-
- ///
- /// Stops profiling in the current context
- ///
- ///
- ///
- /// Will not return an error if profiling has not started.
- ///
- ///
- /// Requires an active script context.
- ///
- ///
- /// The reason for stopping profiling to pass to the profiler callback
- public static void StopProfiling(int reason)
- {
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsStopProfiling(reason));
- }
-
- ///
- /// Enumerates a heap of the current context.
- ///
- ///
- ///
- /// While the heap is being enumerated, the current context cannot be removed, and all calls to
- /// modify the state of the context will fail until the heap enumerator is released.
- ///
- ///
- /// Requires an active script context.
- ///
- ///
- /// A heap enumerator
- public static IActiveScriptProfilerHeapEnum EnumerateHeap()
- {
- IActiveScriptProfilerHeapEnum enumerator;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsEnumerateHeap(out enumerator));
-
- return enumerator;
- }
-
///
/// Adds a reference to a script context
///
///
- /// Calling AddRef ensures that the context will not be freed until Release is called.
+ /// Calling AddRef ensures that the context will not be freed until Release is called.
///
/// The object's new reference count
public uint AddRef()
@@ -439,7 +337,7 @@ public uint AddRef()
/// Releases a reference to a script context
///
///
- /// Removes a reference to a context that was created by AddRef.
+ /// Removes a reference to a context that was created by AddRef .
///
/// The object's new reference count
public uint Release()
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsErrorHelpers.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsErrorHelpers.cs
index df5a44a..755eaaa 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsErrorHelpers.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsErrorHelpers.cs
@@ -8,109 +8,213 @@ internal static class EdgeJsErrorHelpers
///
/// Throws if a native method returns an error code
///
- /// The error
- public static void ThrowIfError(JsErrorCode error)
+ /// The error code
+ public static void ThrowIfError(JsErrorCode errorCode)
{
- if (error != JsErrorCode.NoError)
+ if (errorCode != JsErrorCode.NoError)
{
- switch (error)
+ switch (errorCode)
{
+ #region Usage
+
case JsErrorCode.InvalidArgument:
- throw new JsUsageException(error, "Invalid argument.");
+ throw new JsUsageException(errorCode, "Invalid argument.");
case JsErrorCode.NullArgument:
- throw new JsUsageException(error, "Null argument.");
+ throw new JsUsageException(errorCode, "Null argument.");
case JsErrorCode.NoCurrentContext:
- throw new JsUsageException(error, "No current context.");
+ throw new JsUsageException(errorCode, "No current context.");
case JsErrorCode.InExceptionState:
- throw new JsUsageException(error, "Runtime is in exception state.");
+ throw new JsUsageException(errorCode, "Runtime is in exception state.");
case JsErrorCode.NotImplemented:
- throw new JsUsageException(error, "Method is not implemented.");
+ throw new JsUsageException(errorCode, "Method is not implemented.");
case JsErrorCode.WrongThread:
- throw new JsUsageException(error, "Runtime is active on another thread.");
+ throw new JsUsageException(errorCode, "Runtime is active on another thread.");
case JsErrorCode.RuntimeInUse:
- throw new JsUsageException(error, "Runtime is in use.");
+ throw new JsUsageException(errorCode, "Runtime is in use.");
case JsErrorCode.BadSerializedScript:
- throw new JsUsageException(error, "Bad serialized script.");
+ throw new JsUsageException(errorCode, "Bad serialized script.");
case JsErrorCode.InDisabledState:
- throw new JsUsageException(error, "Runtime is disabled.");
+ throw new JsUsageException(errorCode, "Runtime is disabled.");
case JsErrorCode.CannotDisableExecution:
- throw new JsUsageException(error, "Cannot disable execution.");
-
- case JsErrorCode.AlreadyDebuggingContext:
- throw new JsUsageException(error, "Context is already in debug mode.");
+ throw new JsUsageException(errorCode, "Cannot disable execution.");
case JsErrorCode.HeapEnumInProgress:
- throw new JsUsageException(error, "Heap enumeration is in progress.");
+ throw new JsUsageException(errorCode, "Heap enumeration is in progress.");
case JsErrorCode.ArgumentNotObject:
- throw new JsUsageException(error, "Argument is not an object.");
+ throw new JsUsageException(errorCode, "Argument is not an object.");
case JsErrorCode.InProfileCallback:
- throw new JsUsageException(error, "In a profile callback.");
+ throw new JsUsageException(errorCode, "In a profile callback.");
case JsErrorCode.InThreadServiceCallback:
- throw new JsUsageException(error, "In a thread service callback.");
+ throw new JsUsageException(errorCode, "In a thread service callback.");
case JsErrorCode.CannotSerializeDebugScript:
- throw new JsUsageException(error, "Cannot serialize a debug script.");
+ throw new JsUsageException(errorCode, "Cannot serialize a debug script.");
+
+ case JsErrorCode.AlreadyDebuggingContext:
+ throw new JsUsageException(errorCode, "Context is already in debug mode.");
case JsErrorCode.AlreadyProfilingContext:
- throw new JsUsageException(error, "Already profiling this context.");
+ throw new JsUsageException(errorCode, "Already profiling this context.");
case JsErrorCode.IdleNotEnabled:
- throw new JsUsageException(error, "Idle is not enabled.");
+ throw new JsUsageException(errorCode, "Idle is not enabled.");
- case JsErrorCode.OutOfMemory:
- throw new JsEngineException(error, "Out of memory.");
+ #endregion
- case JsErrorCode.ScriptException:
- {
- EdgeJsValue errorObject;
- JsErrorCode innerError = EdgeNativeMethods.JsGetAndClearException(out errorObject);
+ #region Engine
- if (innerError != JsErrorCode.NoError)
- {
- throw new JsFatalException(innerError);
- }
+ case JsErrorCode.OutOfMemory:
+ throw new JsEngineException(errorCode, "Out of memory.");
- throw new EdgeJsScriptException(error, errorObject, "Script threw an exception.");
- }
+ #endregion
+
+ #region Script
+ case JsErrorCode.ScriptException:
case JsErrorCode.ScriptCompile:
{
EdgeJsValue errorObject;
- JsErrorCode innerError = EdgeNativeMethods.JsGetAndClearException(out errorObject);
+ JsErrorCode innerErrorCode = EdgeNativeMethods.JsGetAndClearException(out errorObject);
- if (innerError != JsErrorCode.NoError)
+ if (innerErrorCode != JsErrorCode.NoError)
{
- throw new JsFatalException(innerError);
+ throw new JsFatalException(innerErrorCode);
}
- throw new EdgeJsScriptException(error, errorObject, "Compile error.");
+ string message = errorCode == JsErrorCode.ScriptCompile ?
+ "Compile error." : "Script threw an exception.";
+
+ throw new EdgeJsScriptException(errorCode, errorObject, message);
}
case JsErrorCode.ScriptTerminated:
- throw new EdgeJsScriptException(error, EdgeJsValue.Invalid, "Script was terminated.");
+ throw new EdgeJsScriptException(errorCode, EdgeJsValue.Invalid, "Script was terminated.");
case JsErrorCode.ScriptEvalDisabled:
- throw new EdgeJsScriptException(error, EdgeJsValue.Invalid, "Eval of strings is disabled in this runtime.");
+ throw new EdgeJsScriptException(errorCode, EdgeJsValue.Invalid, "Eval of strings is disabled in this runtime.");
+
+ #endregion
+
+ #region Fatal
case JsErrorCode.Fatal:
- throw new JsFatalException(error);
+ throw new JsFatalException(errorCode);
+
+ #endregion
default:
- throw new JsFatalException(error);
+ throw new JsFatalException(errorCode);
}
}
}
+
+
+ ///
+ /// Creates a new JavaScript Error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateError(messageValue);
+
+ return errorValue;
+ }
+
+ ///
+ /// Creates a new JavaScript RangeError error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateRangeError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateRangeError(messageValue);
+
+ return errorValue;
+ }
+
+ ///
+ /// Creates a new JavaScript ReferenceError error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateReferenceError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateReferenceError(messageValue);
+
+ return errorValue;
+ }
+
+ ///
+ /// Creates a new JavaScript SyntaxError error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateSyntaxError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateSyntaxError(messageValue);
+
+ return errorValue;
+ }
+
+ ///
+ /// Creates a new JavaScript TypeError error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateTypeError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateTypeError(messageValue);
+
+ return errorValue;
+ }
+
+ ///
+ /// Creates a new JavaScript URIError error object
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The message that describes the error
+ /// The new error object
+ public static EdgeJsValue CreateUriError(string message)
+ {
+ EdgeJsValue messageValue = EdgeJsValue.FromString(message);
+ EdgeJsValue errorValue = EdgeJsValue.CreateUriError(messageValue);
+
+ return errorValue;
+ }
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsNativeFunction.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsNativeFunction.cs
index 3046b57..30f79a2 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsNativeFunction.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsNativeFunction.cs
@@ -1,13 +1,13 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
- using System.Runtime.InteropServices;
+using System;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” function callback
///
/// The Function object that represents the function being invoked
- /// Indicates whether this is a regular call or a 'new' call
+ /// Indicates whether this is a regular call or a new call
/// The arguments to the call
/// The number of arguments
/// Callback data, if any
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsPropertyId.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsPropertyId.cs
index cfcbc1e..3af5b25 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsPropertyId.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsPropertyId.cs
@@ -1,8 +1,8 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
- using System.Runtime.InteropServices;
+using System;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” property identifier
///
@@ -29,9 +29,7 @@ public static EdgeJsPropertyId Invalid
/// Gets a name associated with the property ID
///
///
- ///
/// Requires an active script context.
- ///
///
public string Name
{
@@ -40,7 +38,7 @@ public string Name
IntPtr buffer;
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsGetPropertyNameFromId(this, out buffer));
- return Marshal.PtrToStringAuto(buffer);
+ return Marshal.PtrToStringUni(buffer);
}
}
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsRuntime.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsRuntime.cs
index e1e80b2..e5f4b20 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsRuntime.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsRuntime.cs
@@ -1,9 +1,7 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
-
- using JsRt;
+using System;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” Chakra runtime
///
@@ -17,9 +15,9 @@
/// time.
///
///
- /// NOTE: A , unlike other objects in the Chakra hosting API, is not
+ /// NOTE: A , unlike other objects in the Chakra hosting API, is not
/// garbage collected since it contains the garbage collected heap itself. A runtime will
- /// continue to exist until Dispose is called.
+ /// continue to exist until Dispose is called.
///
///
internal struct EdgeJsRuntime : IDisposable
@@ -103,15 +101,10 @@ public bool Disabled
///
/// Creates a new runtime
///
- /// The attributes of the runtime to be created
- /// The thread service for the runtime. Can be null
/// The runtime created
- public static EdgeJsRuntime Create(JsRuntimeAttributes attributes, JsThreadServiceCallback threadServiceCallback)
+ public static EdgeJsRuntime Create()
{
- EdgeJsRuntime handle;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsCreateRuntime(attributes, threadServiceCallback, out handle));
-
- return handle;
+ return Create(JsRuntimeAttributes.None, null);
}
///
@@ -127,10 +120,15 @@ public static EdgeJsRuntime Create(JsRuntimeAttributes attributes)
///
/// Creates a new runtime
///
+ /// The attributes of the runtime to be created
+ /// The thread service for the runtime. Can be null
/// The runtime created
- public static EdgeJsRuntime Create()
+ public static EdgeJsRuntime Create(JsRuntimeAttributes attributes, JsThreadServiceCallback threadServiceCallback)
{
- return Create(JsRuntimeAttributes.None, null);
+ EdgeJsRuntime handle;
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsCreateRuntime(attributes, threadServiceCallback, out handle));
+
+ return handle;
}
///
@@ -149,7 +147,7 @@ public void CollectGarbage()
/// Registering a memory allocation callback will cause the runtime to call back to the host
/// whenever it acquires memory from, or releases memory to, the OS. The callback routine is
/// called before the runtime memory manager allocates a block of memory. The allocation will
- /// be rejected if the callback returns false. The runtime memory manager will also invoke the
+ /// be rejected if the callback returns false . The runtime memory manager will also invoke the
/// callback routine after freeing a block of memory, as well as after allocation failures.
///
///
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScope.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScope.cs
index 16c9128..13bbea0 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScope.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScope.cs
@@ -1,7 +1,7 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
+using System;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” scope automatically sets a context to current and resets the original context
/// when disposed
@@ -16,7 +16,7 @@ internal struct EdgeJsScope : IDisposable
///
/// Whether the structure has been disposed
///
- private StatedFlag _disposedFlag;
+ private bool _disposed;
///
@@ -25,7 +25,7 @@ internal struct EdgeJsScope : IDisposable
/// The context to create the scope for
public EdgeJsScope(EdgeJsContext context)
{
- _disposedFlag = new StatedFlag();
+ _disposed = false;
_previousContext = EdgeJsContext.Current;
EdgeJsContext.Current = context;
}
@@ -33,14 +33,17 @@ public EdgeJsScope(EdgeJsContext context)
#region IDisposable implementation
///
- /// Disposes a scope and sets the previous context to current
+ /// Disposes the scope and sets the previous context to current
///
public void Dispose()
{
- if (_disposedFlag.Set())
+ if (_disposed)
{
- EdgeJsContext.Current = _previousContext;
+ return;
}
+
+ EdgeJsContext.Current = _previousContext;
+ _disposed = true;
}
#endregion
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScriptException.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScriptException.cs
index 14c8119..373c6c6 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScriptException.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsScriptException.cs
@@ -1,26 +1,30 @@
+#if !NETSTANDARD1_3
+using System;
+using System.Runtime.Serialization;
+
+#endif
namespace MsieJavaScriptEngine.JsRt.Edge
{
- using System;
- using System.Runtime.Serialization;
-
- using JsRt;
-
///
/// Edge script exception
///
+#if !NETSTANDARD1_3
[Serializable]
- internal sealed class EdgeJsScriptException : JsException
+#endif
+ public sealed class EdgeJsScriptException : JsException
{
///
/// The error
///
+#if !NETSTANDARD1_3
[NonSerialized]
+#endif
private readonly EdgeJsValue _error;
///
/// Gets a JavaScript object representing the script error
///
- public EdgeJsValue Error
+ internal EdgeJsValue Error
{
get { return _error; }
}
@@ -29,31 +33,45 @@ public EdgeJsValue Error
///
/// Initializes a new instance of the class
///
- /// The error code returned
- /// The JavaScript error object
- public EdgeJsScriptException(JsErrorCode code, EdgeJsValue error)
- : this(code, error, "JavaScript Exception")
+ /// The error code returned
+ public EdgeJsScriptException(JsErrorCode errorCode)
+ : this(errorCode, "JavaScript Exception")
{ }
///
/// Initializes a new instance of the class
///
- /// The error code returned
+ /// The error code returned
+ /// The error message
+ public EdgeJsScriptException(JsErrorCode errorCode, string message)
+ : this(errorCode, EdgeJsValue.Invalid, message)
+ { }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message
+ ///
+ /// The error code returned
/// The JavaScript error object
/// The error message
- public EdgeJsScriptException(JsErrorCode code, EdgeJsValue error, string message)
- : base(code, message)
+ internal EdgeJsScriptException(JsErrorCode errorCode, EdgeJsValue error, string message)
+ : base(errorCode, message)
{
_error = error;
}
+#if !NETSTANDARD1_3
///
- /// Initializes a new instance of the class
+ /// Initializes a new instance of the class with serialized data
///
- /// The serialization info
- /// The streaming context
+ /// The object that holds the serialized data
+ /// The contextual information about the source or destination
+#if NET10_0_OR_GREATER
+ [Obsolete(DiagnosticId = "SYSLIB0051")]
+#endif
private EdgeJsScriptException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
+#endif
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValue.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValue.cs
index 5a8a69e..140fa09 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValue.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValue.cs
@@ -1,16 +1,14 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
- using System.Runtime.InteropServices;
-
- using JsRt;
+using System;
+using System.Runtime.InteropServices;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” JavaScript value
///
///
- /// The JavaScript value is one of the following types of values: Undefined, Null, Boolean,
- /// String, Number, or Object.
+ /// The JavaScript value is one of the following types of values: undefined , null , Boolean ,
+ /// String , Number , or Object .
///
internal struct EdgeJsValue
{
@@ -307,22 +305,6 @@ public static EdgeJsValue FromString(string value)
return reference;
}
- ///
- /// Creates a JavaScript value that is a projection of the passed in object
- ///
- ///
- /// Requires an active script context.
- ///
- /// The object to be projected
- /// The JavaScript value that is a projection of the object
- public static EdgeJsValue FromObject(object value)
- {
- EdgeJsValue reference;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsVariantToValue(ref value, out reference));
-
- return reference;
- }
-
///
/// Creates a new Object
///
@@ -344,10 +326,10 @@ public static EdgeJsValue CreateObject()
///
/// Requires an active script context.
///
- /// External data that the object will represent. May be null
- /// The callback for when the object is finalized. May be null.
+ /// External data that the object will represent. May be null
+ /// The callback for when the object is finalized. May be null .
/// The new Object
- public static EdgeJsValue CreateExternalObject(IntPtr data, JsObjectFinalizeCallback finalizer)
+ public static EdgeJsValue CreateExternalObject(IntPtr data, JsFinalizeCallback finalizer)
{
EdgeJsValue reference;
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsCreateExternalObject(data, finalizer, out reference));
@@ -405,7 +387,7 @@ public static EdgeJsValue CreateArray(uint length)
}
///
- /// Creates a new JavaScript error object
+ /// Creates a new JavaScript Error object
///
///
/// Requires an active script context.
@@ -421,7 +403,7 @@ public static EdgeJsValue CreateError(EdgeJsValue message)
}
///
- /// Creates a new JavaScript RangeError error object
+ /// Creates a new JavaScript RangeError error object
///
///
/// Requires an active script context.
@@ -437,7 +419,7 @@ public static EdgeJsValue CreateRangeError(EdgeJsValue message)
}
///
- /// Creates a new JavaScript ReferenceError error object
+ /// Creates a new JavaScript ReferenceError error object
///
///
/// Requires an active script context.
@@ -453,7 +435,7 @@ public static EdgeJsValue CreateReferenceError(EdgeJsValue message)
}
///
- /// Creates a new JavaScript SyntaxError error object
+ /// Creates a new JavaScript SyntaxError error object
///
///
/// Requires an active script context.
@@ -469,7 +451,7 @@ public static EdgeJsValue CreateSyntaxError(EdgeJsValue message)
}
///
- /// Creates a new JavaScript TypeError error object
+ /// Creates a new JavaScript TypeError error object
///
///
/// Requires an active script context.
@@ -485,7 +467,7 @@ public static EdgeJsValue CreateTypeError(EdgeJsValue message)
}
///
- /// Creates a new JavaScript URIError error object
+ /// Creates a new JavaScript URIError error object
///
///
/// Requires an active script context.
@@ -505,8 +487,8 @@ public static EdgeJsValue CreateUriError(EdgeJsValue message)
///
///
/// This only needs to be called on objects that are not going to be stored somewhere on
- /// the stack. Calling AddRef ensures that the JavaScript object the value refers to will not be freed
- /// until Release is called.
+ /// the stack. Calling AddRef ensures that the JavaScript object the value refers to will not be freed
+ /// until Release is called.
///
/// The object's new reference count
public uint AddRef()
@@ -521,7 +503,7 @@ public uint AddRef()
/// Releases a reference to the object
///
///
- /// Removes a reference that was created by AddRef.
+ /// Removes a reference that was created by AddRef .
///
/// The object's new reference count
public uint Release()
@@ -552,7 +534,7 @@ public bool ToBoolean()
///
///
///
- /// This function retrieves the value of a Number value. It will fail with
+ /// This function retrieves the value of a Number value. It will fail with
/// InvalidArgument if the type of the value is not Number .
///
///
@@ -569,41 +551,47 @@ public double ToDouble()
}
///
- /// Retrieves a string pointer of a String value
+ /// Retrieves a int value of a Number value
///
///
///
- /// This function retrieves the string pointer of a String value. It will fail with
- /// InvalidArgument if the type of the value is not String .
+ /// This function retrieves the value of a Number value. It will fail with
+ /// InvalidArgument if the type of the value is not Number .
///
///
/// Requires an active script context.
///
///
- /// The string
- public new string ToString()
+ /// The int value
+ public int ToInt32()
{
- IntPtr buffer;
- UIntPtr length;
-
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsStringToPointer(this, out buffer, out length));
+ int value;
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsNumberToInt(this, out value));
- return Marshal.PtrToStringAuto(buffer, (int)length);
+ return value;
}
///
- /// Retrieves a object representation of an Object value
+ /// Retrieves a string pointer of a String value
///
///
+ ///
+ /// This function retrieves the string pointer of a String value. It will fail with
+ /// InvalidArgument if the type of the value is not String .
+ ///
+ ///
/// Requires an active script context.
+ ///
///
- /// The object representation of the value
- public object ToObject()
+ /// The string
+ public new string ToString()
{
- object value;
- EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsValueToVariant(this, out value));
+ IntPtr buffer;
+ UIntPtr length;
- return value;
+ EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsStringToPointer(this, out buffer, out length));
+
+ return Marshal.PtrToStringUni(buffer, (int)length);
}
///
@@ -850,7 +838,7 @@ public void DeleteIndexedProperty(EdgeJsValue index)
///
///
///
- /// This function is equivalent to the "==" operator in JavaScript.
+ /// This function is equivalent to the == operator in JavaScript.
///
///
/// Requires an active script context.
@@ -871,7 +859,7 @@ public bool Equals(EdgeJsValue other)
///
///
///
- /// This function is equivalent to the "===" operator in JavaScript.
+ /// This function is equivalent to the === operator in JavaScript.
///
///
/// Requires an active script context.
@@ -894,14 +882,14 @@ public bool StrictEquals(EdgeJsValue other)
/// Requires an active script context.
///
/// The arguments to the call
- /// The Value returned from the function invocation, if any
+ /// The JavaScript value returned from the function invocation, if any
public EdgeJsValue CallFunction(params EdgeJsValue[] arguments)
{
EdgeJsValue returnReference;
if (arguments.Length > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException("arguments");
+ throw new ArgumentOutOfRangeException(nameof(arguments));
}
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsCallFunction(this, arguments, (ushort)arguments.Length, out returnReference));
@@ -916,14 +904,14 @@ public EdgeJsValue CallFunction(params EdgeJsValue[] arguments)
/// Requires an active script context.
///
/// The arguments to the call
- /// The Value returned from the function invocation
+ /// The JavaScript value returned from the function invocation
public EdgeJsValue ConstructObject(params EdgeJsValue[] arguments)
{
EdgeJsValue returnReference;
if (arguments.Length > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException("arguments");
+ throw new ArgumentOutOfRangeException(nameof(arguments));
}
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsConstructObject(this, arguments, (ushort)arguments.Length, out returnReference));
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValueExtensions.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValueExtensions.cs
new file mode 100644
index 0000000..dde90ba
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeJsValueExtensions.cs
@@ -0,0 +1,111 @@
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
+ ///
+ /// Extensions for the “Edge” JavaScript value
+ ///
+ internal static class EdgeJsValueExtensions
+ {
+ ///
+ /// Gets a property descriptor for an object's own property
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// The property descriptor
+ public static EdgeJsValue GetOwnPropertyDescriptor(this EdgeJsValue source, string propertyName)
+ {
+ EdgeJsPropertyId propertyId = EdgeJsPropertyId.FromString(propertyName);
+ EdgeJsValue resultValue = source.GetOwnPropertyDescriptor(propertyId);
+
+ return resultValue;
+ }
+
+ ///
+ /// Determines whether an object has a property
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// Whether the object (or a prototype) has the property
+ public static bool HasProperty(this EdgeJsValue source, string propertyName)
+ {
+ EdgeJsPropertyId propertyId = EdgeJsPropertyId.FromString(propertyName);
+ bool result = source.HasProperty(propertyId);
+
+ return result;
+ }
+
+ ///
+ /// Gets an object's property
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// The value of the property
+ public static EdgeJsValue GetProperty(this EdgeJsValue source, string name)
+ {
+ EdgeJsPropertyId id = EdgeJsPropertyId.FromString(name);
+ EdgeJsValue resultValue = source.GetProperty(id);
+
+ return resultValue;
+ }
+
+ ///
+ /// Sets an object's property
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// The new value of the property
+ /// The property set should follow strict mode rules
+ public static void SetProperty(this EdgeJsValue source, string name, EdgeJsValue value, bool useStrictRules)
+ {
+ EdgeJsPropertyId id = EdgeJsPropertyId.FromString(name);
+ source.SetProperty(id, value, useStrictRules);
+ }
+
+ ///
+ /// Deletes an object's property
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// The property set should follow strict mode rules
+ /// Whether the property was deleted
+ public static EdgeJsValue DeleteProperty(this EdgeJsValue source, string propertyName, bool useStrictRules)
+ {
+ EdgeJsPropertyId propertyId = EdgeJsPropertyId.FromString(propertyName);
+ EdgeJsValue resultValue = source.DeleteProperty(propertyId, useStrictRules);
+
+ return resultValue;
+ }
+
+ ///
+ /// Defines a new object's own property from a property descriptor
+ ///
+ ///
+ /// Requires an active script context.
+ ///
+ /// The JavaScript value
+ /// The name of the property
+ /// The property descriptor
+ /// Whether the property was defined
+ public static bool DefineProperty(this EdgeJsValue source, string propertyName, EdgeJsValue propertyDescriptor)
+ {
+ EdgeJsPropertyId propertyId = EdgeJsPropertyId.FromString(propertyName);
+ bool result = source.DefineProperty(propertyId, propertyDescriptor);
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeNativeMethods.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeNativeMethods.cs
index 6b3b217..0e8dd7a 100644
--- a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeNativeMethods.cs
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeNativeMethods.cs
@@ -1,275 +1,284 @@
-namespace MsieJavaScriptEngine.JsRt.Edge
-{
- using System;
- using System.Runtime.InteropServices;
+using System;
+using System.Runtime.InteropServices;
- using Constants;
- using JsRt;
+using MsieJavaScriptEngine.Constants;
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
///
/// “Edge” native methods
///
internal static class EdgeNativeMethods
{
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsCreateRuntime(JsRuntimeAttributes attributes, JsThreadServiceCallback threadService, out EdgeJsRuntime runtime);
+ #region Hosting
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsCollectGarbage(EdgeJsRuntime handle);
+ internal static extern JsErrorCode JsParseScript(string script, JsSourceContext sourceContext,
+ string sourceUrl, out EdgeJsValue result);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsDisposeRuntime(EdgeJsRuntime handle);
+ internal static extern JsErrorCode JsRunScript(string script, JsSourceContext sourceContext,
+ string sourceUrl, out EdgeJsValue result);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetRuntimeMemoryUsage(EdgeJsRuntime runtime, out UIntPtr memoryUsage);
+ internal static extern JsErrorCode JsSerializeScript(string script, byte[] buffer, ref uint bufferSize);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetRuntimeMemoryLimit(EdgeJsRuntime runtime, out UIntPtr memoryLimit);
+ internal static extern JsErrorCode JsParseSerializedScript(string script, byte[] buffer,
+ JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSetRuntimeMemoryLimit(EdgeJsRuntime runtime, UIntPtr memoryLimit);
+ internal static extern JsErrorCode JsRunSerializedScript(string script, byte[] buffer,
+ JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSetRuntimeMemoryAllocationCallback(EdgeJsRuntime runtime, IntPtr callbackState, JsMemoryAllocationCallback allocationCallback);
+ internal static extern JsErrorCode JsGetPropertyIdFromName(string name, out EdgeJsPropertyId propertyId);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetPropertyNameFromId(EdgeJsPropertyId propertyId, out IntPtr buffer);
[DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSetRuntimeBeforeCollectCallback(EdgeJsRuntime runtime, IntPtr callbackState, JsBeforeCollectCallback beforeCollectCallback);
+ internal static extern JsErrorCode JsPointerToString(string value, UIntPtr stringLength,
+ out EdgeJsValue stringValue);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsStringToPointer(EdgeJsValue value, out IntPtr stringValue,
+ out UIntPtr stringLength);
+
+ #endregion
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsCreateRuntime(JsRuntimeAttributes attributes,
+ JsThreadServiceCallback threadService, out EdgeJsRuntime runtime);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsCollectGarbage(EdgeJsRuntime handle);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode, EntryPoint = "JsAddRef")]
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsDisposeRuntime(EdgeJsRuntime handle);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetRuntimeMemoryUsage(EdgeJsRuntime runtime, out UIntPtr memoryUsage);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetRuntimeMemoryLimit(EdgeJsRuntime runtime, out UIntPtr memoryLimit);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsSetRuntimeMemoryLimit(EdgeJsRuntime runtime, UIntPtr memoryLimit);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsSetRuntimeMemoryAllocationCallback(EdgeJsRuntime runtime,
+ IntPtr callbackState, JsMemoryAllocationCallback allocationCallback);
+
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsSetRuntimeBeforeCollectCallback(EdgeJsRuntime runtime,
+ IntPtr callbackState, JsBeforeCollectCallback beforeCollectCallback);
+
+ [DllImport(DllName.Chakra, EntryPoint = "JsAddRef")]
internal static extern JsErrorCode JsContextAddRef(EdgeJsContext reference, out uint count);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsAddRef(EdgeJsValue reference, out uint count);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode, EntryPoint = "JsRelease")]
+ [DllImport(DllName.Chakra, EntryPoint = "JsRelease")]
internal static extern JsErrorCode JsContextRelease(EdgeJsContext reference, out uint count);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsRelease(EdgeJsValue reference, out uint count);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateContext(EdgeJsRuntime runtime, out EdgeJsContext newContext);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetCurrentContext(out EdgeJsContext currentContext);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsSetCurrentContext(EdgeJsContext context);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetRuntime(EdgeJsContext context, out EdgeJsRuntime runtime);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsStartDebugging();
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsIdle(out uint nextIdleTick);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsParseScript(string script, JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsRunScript(string script, JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSerializeScript(string script, byte[] buffer, ref ulong bufferSize);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsParseSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsRunSerializedScript(string script, byte[] buffer, JsSourceContext sourceContext, string sourceUrl, out EdgeJsValue result);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetPropertyIdFromName(string name, out EdgeJsPropertyId propertyId);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetPropertyNameFromId(EdgeJsPropertyId propertyId, out IntPtr buffer);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetUndefinedValue(out EdgeJsValue undefinedValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetNullValue(out EdgeJsValue nullValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetTrueValue(out EdgeJsValue trueValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetFalseValue(out EdgeJsValue falseValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsBoolToBoolean(bool value, out EdgeJsValue booleanValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsBooleanToBool(EdgeJsValue booleanValue, out bool boolValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsConvertValueToBoolean(EdgeJsValue value, out EdgeJsValue booleanValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetValueType(EdgeJsValue value, out JsValueType type);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsDoubleToNumber(double doubleValue, out EdgeJsValue value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsIntToNumber(int intValue, out EdgeJsValue value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsNumberToDouble(EdgeJsValue value, out double doubleValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsNumberToInt(EdgeJsValue value, out int intValue);
+
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsConvertValueToNumber(EdgeJsValue value, out EdgeJsValue numberValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetStringLength(EdgeJsValue sringValue, out int length);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsPointerToString(string value, UIntPtr stringLength, out EdgeJsValue stringValue);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsStringToPointer(EdgeJsValue value, out IntPtr stringValue, out UIntPtr stringLength);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsConvertValueToString(EdgeJsValue value, out EdgeJsValue stringValue);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsVariantToValue([MarshalAs(UnmanagedType.Struct)] ref object var, out EdgeJsValue value);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsValueToVariant(EdgeJsValue obj, [MarshalAs(UnmanagedType.Struct)] out object var);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetGlobalObject(out EdgeJsValue globalObject);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateObject(out EdgeJsValue obj);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsCreateExternalObject(IntPtr data, JsObjectFinalizeCallback finalizeCallback, out EdgeJsValue obj);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsCreateExternalObject(IntPtr data,
+ JsFinalizeCallback finalizeCallback, out EdgeJsValue obj);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsConvertValueToObject(EdgeJsValue value, out EdgeJsValue obj);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetPrototype(EdgeJsValue obj, out EdgeJsValue prototypeObject);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsSetPrototype(EdgeJsValue obj, EdgeJsValue prototypeObject);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetExtensionAllowed(EdgeJsValue obj, out bool value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsPreventExtension(EdgeJsValue obj);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId, out EdgeJsValue value);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ out EdgeJsValue value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetOwnPropertyDescriptor(EdgeJsValue obj, EdgeJsPropertyId propertyId, out EdgeJsValue propertyDescriptor);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetOwnPropertyDescriptor(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ out EdgeJsValue propertyDescriptor);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetOwnPropertyNames(EdgeJsValue obj, out EdgeJsValue propertyNames);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSetProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId, EdgeJsValue value, bool useStrictRules);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsSetProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ EdgeJsValue value, bool useStrictRules);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsHasProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId, out bool hasProperty);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsHasProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ out bool hasProperty);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsDeleteProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId, bool useStrictRules, out EdgeJsValue result);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsDeleteProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ bool useStrictRules, out EdgeJsValue result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsDefineProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId, EdgeJsValue propertyDescriptor, out bool result);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsDefineProperty(EdgeJsValue obj, EdgeJsPropertyId propertyId,
+ EdgeJsValue propertyDescriptor, out bool result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsHasIndexedProperty(EdgeJsValue obj, EdgeJsValue index, out bool result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsGetIndexedProperty(EdgeJsValue obj, EdgeJsValue index, out EdgeJsValue result);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsGetIndexedProperty(EdgeJsValue obj, EdgeJsValue index,
+ out EdgeJsValue result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsSetIndexedProperty(EdgeJsValue obj, EdgeJsValue index, EdgeJsValue value);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsSetIndexedProperty(EdgeJsValue obj, EdgeJsValue index,
+ EdgeJsValue value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsDeleteIndexedProperty(EdgeJsValue obj, EdgeJsValue index);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsEquals(EdgeJsValue obj1, EdgeJsValue obj2, out bool result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsStrictEquals(EdgeJsValue obj1, EdgeJsValue obj2, out bool result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsHasExternalData(EdgeJsValue obj, out bool value);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetExternalData(EdgeJsValue obj, out IntPtr externalData);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsSetExternalData(EdgeJsValue obj, IntPtr externalData);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateArray(uint length, out EdgeJsValue result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsCallFunction(EdgeJsValue function, EdgeJsValue[] arguments, ushort argumentCount, out EdgeJsValue result);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsCallFunction(EdgeJsValue function, EdgeJsValue[] arguments,
+ ushort argumentCount, out EdgeJsValue result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsConstructObject(EdgeJsValue function, EdgeJsValue[] arguments, ushort argumentCount, out EdgeJsValue result);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsConstructObject(EdgeJsValue function, EdgeJsValue[] arguments,
+ ushort argumentCount, out EdgeJsValue result);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsCreateFunction(EdgeJsNativeFunction nativeFunction, IntPtr externalData, out EdgeJsValue function);
+ [DllImport(DllName.Chakra)]
+ internal static extern JsErrorCode JsCreateFunction(EdgeJsNativeFunction nativeFunction,
+ IntPtr externalData, out EdgeJsValue function);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateRangeError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateReferenceError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateSyntaxError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateTypeError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsCreateURIError(EdgeJsValue message, out EdgeJsValue error);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsHasException(out bool hasException);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsGetAndClearException(out EdgeJsValue exception);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsSetException(EdgeJsValue exception);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsDisableRuntimeExecution(EdgeJsRuntime runtime);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsEnableRuntimeExecution(EdgeJsRuntime runtime);
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
+ [DllImport(DllName.Chakra)]
internal static extern JsErrorCode JsIsRuntimeExecutionDisabled(EdgeJsRuntime runtime, out bool isDisabled);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsStartProfiling(IActiveScriptProfilerCallback callback, ProfilerEventMask eventMask, int context);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsStopProfiling(int reason);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsEnumerateHeap(out IActiveScriptProfilerHeapEnum enumerator);
-
- [DllImport(DllName.Chakra, CharSet = CharSet.Unicode)]
- internal static extern JsErrorCode JsIsEnumeratingHeap(out bool isEnumeratingHeap);
}
}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Edge/EdgeTypeMapper.cs b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeTypeMapper.cs
new file mode 100644
index 0000000..43fc4ac
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsRt/Edge/EdgeTypeMapper.cs
@@ -0,0 +1,708 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using MsieJavaScriptEngine.Extensions;
+using MsieJavaScriptEngine.Helpers;
+using MsieJavaScriptEngine.JsRt.Embedding;
+using MsieJavaScriptEngine.Resources;
+
+using WrapperException = MsieJavaScriptEngine.JsException;
+
+namespace MsieJavaScriptEngine.JsRt.Edge
+{
+ using EdgeEmbeddedItem = EmbeddedItem;
+ using EdgeEmbeddedObject = EmbeddedObject;
+ using EdgeEmbeddedType = EmbeddedType;
+
+ ///
+ /// “Edge” type mapper
+ ///
+ internal sealed class EdgeTypeMapper : TypeMapper
+ {
+ ///
+ /// Constructs an instance of the “Edge” type mapper
+ ///
+ /// Flag for whether to allow the usage of reflection API in the script code
+ public EdgeTypeMapper(bool allowReflection)
+ : base(allowReflection)
+ { }
+
+
+ ///
+ /// Makes a mapping of value from the host type to a script type
+ ///
+ /// The source value
+ /// The mapped value
+ public override EdgeJsValue MapToScriptType(object value)
+ {
+ if (value is null)
+ {
+ return EdgeJsValue.Null;
+ }
+
+ if (value is Undefined)
+ {
+ return EdgeJsValue.Undefined;
+ }
+
+ var typeCode = value.GetType().GetTypeCode();
+
+ switch (typeCode)
+ {
+ case TypeCode.Boolean:
+ return (bool)value ? EdgeJsValue.True : EdgeJsValue.False;
+
+ case TypeCode.SByte:
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ return EdgeJsValue.FromInt32(Convert.ToInt32(value));
+
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.Decimal:
+ return EdgeJsValue.FromDouble(Convert.ToDouble(value));
+
+ case TypeCode.Char:
+ case TypeCode.String:
+ return EdgeJsValue.FromString((string)value);
+
+ default:
+ return value is EdgeJsValue ? (EdgeJsValue)value : GetOrCreateScriptObject(value);
+ }
+ }
+
+ ///
+ /// Makes a mapping of value from the script type to a host type
+ ///
+ /// The source value
+ /// The mapped value
+ public override object MapToHostType(EdgeJsValue value)
+ {
+ JsValueType valueType = value.ValueType;
+ object result = null;
+
+ switch (valueType)
+ {
+ case JsValueType.Null:
+ result = null;
+ break;
+ case JsValueType.Undefined:
+ result = Undefined.Value;
+ break;
+ case JsValueType.Boolean:
+ result = value.ToBoolean();
+ break;
+ case JsValueType.Number:
+ result = NumericHelpers.CastDoubleValueToCorrectType(value.ToDouble());
+ break;
+ case JsValueType.String:
+ result = value.ToString();
+ break;
+ case JsValueType.Function:
+ EdgeJsPropertyId externalObjectPropertyId = EdgeJsPropertyId.FromString(ExternalObjectPropertyName);
+ if (value.HasProperty(externalObjectPropertyId))
+ {
+ EdgeJsValue externalObjectValue = value.GetProperty(externalObjectPropertyId);
+ result = externalObjectValue.HasExternalData ?
+ GCHandle.FromIntPtr(externalObjectValue.ExternalData).Target : null;
+ }
+
+ result = result ?? value.ConvertToObject();
+ break;
+ case JsValueType.Object:
+ case JsValueType.Error:
+ case JsValueType.Array:
+ result = value.HasExternalData ?
+ GCHandle.FromIntPtr(value.ExternalData).Target : value.ConvertToObject();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ return result;
+ }
+
+ protected override EdgeEmbeddedObject CreateEmbeddedObjectOrFunction(object obj)
+ {
+ var del = obj as Delegate;
+ EdgeEmbeddedObject embeddedObject = del is not null ?
+ CreateEmbeddedFunction(del) : CreateEmbeddedObject(obj);
+
+ return embeddedObject;
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private EdgeEmbeddedObject CreateEmbeddedObject(object obj)
+ {
+ GCHandle objHandle = GCHandle.Alloc(obj);
+ IntPtr objPtr = GCHandle.ToIntPtr(objHandle);
+ EdgeJsValue objValue = EdgeJsValue.CreateExternalObject(objPtr, _embeddedObjectFinalizeCallback);
+
+ var embeddedObject = new EdgeEmbeddedObject(obj, objValue);
+
+ ProjectFields(embeddedObject);
+ ProjectProperties(embeddedObject);
+ ProjectMethods(embeddedObject);
+ FreezeObject(objValue);
+
+ return embeddedObject;
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private EdgeEmbeddedObject CreateEmbeddedFunction(Delegate del)
+ {
+ EdgeJsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+#if NET40
+ MethodInfo method = del.Method;
+#else
+ MethodInfo method = del.GetMethodInfo();
+#endif
+ ParameterInfo[] parameters = method.GetParameters();
+ object[] processedArgs = GetHostItemMemberArguments(args, parameters.Length);
+
+ ReflectionHelpers.FixArgumentTypes(ref processedArgs, parameters);
+
+ object result;
+
+ try
+ {
+ result = del.DynamicInvoke(processedArgs);
+ }
+ catch (Exception e)
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue = wrapperException is not null ?
+ CreateErrorFromWrapperException(wrapperException)
+ :
+ EdgeJsErrorHelpers.CreateError(string.Format(
+ CommonStrings.Runtime_HostDelegateInvocationFailed, exception.Message))
+ ;
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ EdgeJsValue resultValue = MapToScriptType(result);
+
+ return resultValue;
+ };
+
+ GCHandle delHandle = GCHandle.Alloc(del);
+ IntPtr delPtr = GCHandle.ToIntPtr(delHandle);
+ EdgeJsValue objValue = EdgeJsValue.CreateExternalObject(delPtr, _embeddedObjectFinalizeCallback);
+
+ EdgeJsValue functionValue = EdgeJsValue.CreateFunction(nativeFunction);
+ SetNonEnumerableProperty(functionValue, ExternalObjectPropertyName, objValue);
+
+ var embeddedObject = new EdgeEmbeddedObject(del, functionValue, [nativeFunction]);
+
+ return embeddedObject;
+ }
+
+ protected override EdgeEmbeddedType CreateEmbeddedType(Type type)
+ {
+#if NET40
+ Type typeInfo = type;
+#else
+ TypeInfo typeInfo = type.GetTypeInfo();
+#endif
+ string typeName = type.FullName;
+ BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(true);
+ ConstructorInfo[] constructors = type.GetConstructors(defaultBindingFlags);
+
+ EdgeJsNativeFunction nativeConstructorFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ object result;
+ EdgeJsValue resultValue;
+ object[] processedArgs = GetHostItemMemberArguments(args);
+
+ if (processedArgs.Length == 0 && typeInfo.IsValueType)
+ {
+ result = Activator.CreateInstance(type);
+ resultValue = MapToScriptType(result);
+
+ return resultValue;
+ }
+
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (constructors.Length == 0)
+ {
+ CreateAndSetError(string.Format(CommonStrings.Runtime_HostTypeConstructorNotFound, typeName));
+ return undefinedValue;
+ }
+
+ var bestFitConstructor = (ConstructorInfo)ReflectionHelpers.GetBestFitMethod(
+ constructors, processedArgs);
+ if (bestFitConstructor is null)
+ {
+ CreateAndSetReferenceError(string.Format(
+ CommonStrings.Runtime_SuitableConstructorOfHostTypeNotFound, typeName));
+ return undefinedValue;
+ }
+
+ ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitConstructor.GetParameters());
+
+ try
+ {
+ result = bestFitConstructor.Invoke(processedArgs);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue = wrapperException is not null ?
+ CreateErrorFromWrapperException(wrapperException)
+ :
+ EdgeJsErrorHelpers.CreateError(string.Format(
+ CommonStrings.Runtime_HostTypeConstructorInvocationFailed, typeName, exception.Message))
+ ;
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ resultValue = MapToScriptType(result);
+
+ return resultValue;
+ };
+
+ GCHandle embeddedTypeHandle = GCHandle.Alloc(type);
+ IntPtr embeddedTypePtr = GCHandle.ToIntPtr(embeddedTypeHandle);
+ EdgeJsValue objValue = EdgeJsValue.CreateExternalObject(embeddedTypePtr,
+ _embeddedTypeFinalizeCallback);
+
+ EdgeJsValue typeValue = EdgeJsValue.CreateFunction(nativeConstructorFunction);
+ SetNonEnumerableProperty(typeValue, ExternalObjectPropertyName, objValue);
+
+ var embeddedType = new EdgeEmbeddedType(type, typeValue,
+ new List { nativeConstructorFunction });
+
+ ProjectFields(embeddedType);
+ ProjectProperties(embeddedType);
+ ProjectMethods(embeddedType);
+ FreezeObject(typeValue);
+
+ return embeddedType;
+ }
+
+ private void ProjectFields(EdgeEmbeddedItem externalItem)
+ {
+ Type type = externalItem.HostType;
+ object obj = externalItem.HostObject;
+ EdgeJsValue typeValue = externalItem.ScriptValue;
+ bool instance = externalItem.IsInstance;
+ IList nativeFunctions = externalItem.NativeFunctions;
+
+ string typeName = type.FullName;
+ BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
+ FieldInfo[] fields = type.GetFields(defaultBindingFlags);
+
+ foreach (FieldInfo field in fields)
+ {
+ string fieldName = field.Name;
+
+ EdgeJsValue descriptorValue = EdgeJsValue.CreateObject();
+ descriptorValue.SetProperty("enumerable", EdgeJsValue.True, true);
+
+ EdgeJsNativeFunction nativeGetFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (instance && obj is null)
+ {
+ CreateAndSetTypeError(string.Format(
+ CommonStrings.Runtime_InvalidThisContextForHostObjectField, fieldName));
+ return undefinedValue;
+ }
+
+ object result;
+
+ try
+ {
+ result = field.GetValue(obj);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue;
+
+ if (wrapperException is not null)
+ {
+ errorValue = CreateErrorFromWrapperException(wrapperException);
+ }
+ else
+ {
+ string errorMessage = instance ?
+ string.Format(CommonStrings.Runtime_HostObjectFieldGettingFailed, fieldName,
+ exception.Message)
+ :
+ string.Format(CommonStrings.Runtime_HostTypeFieldGettingFailed, fieldName, typeName,
+ exception.Message)
+ ;
+ errorValue = EdgeJsErrorHelpers.CreateError(errorMessage);
+ }
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ EdgeJsValue resultValue = MapToScriptType(result);
+
+ return resultValue;
+ };
+ nativeFunctions.Add(nativeGetFunction);
+
+ EdgeJsValue getMethodValue = EdgeJsValue.CreateFunction(nativeGetFunction);
+ descriptorValue.SetProperty("get", getMethodValue, true);
+
+ if (!field.IsInitOnly)
+ {
+ EdgeJsNativeFunction nativeSetFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (instance && obj is null)
+ {
+ CreateAndSetTypeError(string.Format(
+ CommonStrings.Runtime_InvalidThisContextForHostObjectField, fieldName));
+ return undefinedValue;
+ }
+
+ object value = MapToHostType(args[1]);
+ ReflectionHelpers.FixFieldValueType(ref value, field);
+
+ try
+ {
+ field.SetValue(obj, value);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue;
+
+ if (wrapperException is not null)
+ {
+ errorValue = CreateErrorFromWrapperException(wrapperException);
+ }
+ else
+ {
+ string errorMessage = instance ?
+ string.Format(CommonStrings.Runtime_HostObjectFieldSettingFailed, fieldName,
+ exception.Message)
+ :
+ string.Format(CommonStrings.Runtime_HostTypeFieldSettingFailed, fieldName, typeName,
+ exception.Message)
+ ;
+ errorValue = EdgeJsErrorHelpers.CreateError(errorMessage);
+ }
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ return undefinedValue;
+ };
+ nativeFunctions.Add(nativeSetFunction);
+
+ EdgeJsValue setMethodValue = EdgeJsValue.CreateFunction(nativeSetFunction);
+ descriptorValue.SetProperty("set", setMethodValue, true);
+ }
+
+ typeValue.DefineProperty(fieldName, descriptorValue);
+ }
+ }
+
+ private void ProjectProperties(EdgeEmbeddedItem externalItem)
+ {
+ Type type = externalItem.HostType;
+ object obj = externalItem.HostObject;
+ EdgeJsValue typeValue = externalItem.ScriptValue;
+ IList nativeFunctions = externalItem.NativeFunctions;
+ bool instance = externalItem.IsInstance;
+
+ string typeName = type.FullName;
+ BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
+ PropertyInfo[] properties = type.GetProperties(defaultBindingFlags);
+
+ foreach (PropertyInfo property in properties)
+ {
+ if (!IsAvailableProperty(property))
+ {
+ continue;
+ }
+
+ string propertyName = property.Name;
+
+ EdgeJsValue descriptorValue = EdgeJsValue.CreateObject();
+ descriptorValue.SetProperty("enumerable", EdgeJsValue.True, true);
+
+ if (property.CanRead)
+ {
+ EdgeJsNativeFunction nativeGetFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (instance && obj is null)
+ {
+ CreateAndSetTypeError(string.Format(
+ CommonStrings.Runtime_InvalidThisContextForHostObjectProperty, propertyName));
+ return undefinedValue;
+ }
+
+ object result;
+
+ try
+ {
+ result = property.GetValue(obj, []);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue;
+
+ if (wrapperException is not null)
+ {
+ errorValue = CreateErrorFromWrapperException(wrapperException);
+ }
+ else
+ {
+ string errorMessage = instance ?
+ string.Format(CommonStrings.Runtime_HostObjectPropertyGettingFailed, propertyName,
+ exception.Message)
+ :
+ string.Format(CommonStrings.Runtime_HostTypePropertyGettingFailed, propertyName,
+ typeName, exception.Message)
+ ;
+ errorValue = EdgeJsErrorHelpers.CreateError(errorMessage);
+ }
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ EdgeJsValue resultValue = MapToScriptType(result);
+
+ return resultValue;
+ };
+ nativeFunctions.Add(nativeGetFunction);
+
+ EdgeJsValue getMethodValue = EdgeJsValue.CreateFunction(nativeGetFunction);
+ descriptorValue.SetProperty("get", getMethodValue, true);
+ }
+
+ if (property.CanWrite)
+ {
+ EdgeJsNativeFunction nativeSetFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (instance && obj is null)
+ {
+ CreateAndSetTypeError(string.Format(
+ CommonStrings.Runtime_InvalidThisContextForHostObjectProperty, propertyName));
+ return undefinedValue;
+ }
+
+ object value = MapToHostType(args[1]);
+ ReflectionHelpers.FixPropertyValueType(ref value, property);
+
+ try
+ {
+ property.SetValue(obj, value, []);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue;
+
+ if (wrapperException is not null)
+ {
+ errorValue = CreateErrorFromWrapperException(wrapperException);
+ }
+ else
+ {
+ string errorMessage = instance ?
+ string.Format(CommonStrings.Runtime_HostObjectPropertySettingFailed, propertyName,
+ exception.Message)
+ :
+ string.Format(CommonStrings.Runtime_HostTypePropertySettingFailed, propertyName,
+ typeName, exception.Message)
+ ;
+ errorValue = EdgeJsErrorHelpers.CreateError(errorMessage);
+ }
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ return undefinedValue;
+ };
+ nativeFunctions.Add(nativeSetFunction);
+
+ EdgeJsValue setMethodValue = EdgeJsValue.CreateFunction(nativeSetFunction);
+ descriptorValue.SetProperty("set", setMethodValue, true);
+ }
+
+ typeValue.DefineProperty(propertyName, descriptorValue);
+ }
+ }
+
+ private void ProjectMethods(EdgeEmbeddedItem externalItem)
+ {
+ Type type = externalItem.HostType;
+ object obj = externalItem.HostObject;
+ EdgeJsValue typeValue = externalItem.ScriptValue;
+ IList nativeFunctions = externalItem.NativeFunctions;
+ bool instance = externalItem.IsInstance;
+
+ string typeName = type.FullName;
+ BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
+ MethodInfo[] methods = type.GetMethods(defaultBindingFlags);
+ Dictionary> availableMethodGroups = GetAvailableMethodGroups(methods);
+
+ foreach (KeyValuePair> methodGroup in availableMethodGroups)
+ {
+ string methodName = methodGroup.Key;
+ MethodInfo[] methodCandidates = methodGroup.Value.ToArray();
+
+ EdgeJsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) =>
+ {
+ EdgeJsValue undefinedValue = EdgeJsValue.Undefined;
+
+ if (instance && obj is null)
+ {
+ CreateAndSetTypeError(string.Format(
+ CommonStrings.Runtime_InvalidThisContextForHostObjectMethod, methodName));
+ return undefinedValue;
+ }
+
+ object[] processedArgs = GetHostItemMemberArguments(args);
+
+ var bestFitMethod = (MethodInfo)ReflectionHelpers.GetBestFitMethod(
+ methodCandidates, processedArgs);
+ if (bestFitMethod is null)
+ {
+ CreateAndSetReferenceError(string.Format(
+ CommonStrings.Runtime_SuitableMethodOfHostObjectNotFound, methodName));
+ return undefinedValue;
+ }
+
+ ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitMethod.GetParameters());
+
+ object result;
+
+ try
+ {
+ result = bestFitMethod.Invoke(obj, processedArgs);
+ }
+ catch (Exception e)
+ {
+ Exception exception = UnwrapException(e);
+ var wrapperException = exception as WrapperException;
+ EdgeJsValue errorValue;
+
+ if (wrapperException is not null)
+ {
+ errorValue = CreateErrorFromWrapperException(wrapperException);
+ }
+ else
+ {
+ string errorMessage = instance ?
+ string.Format(CommonStrings.Runtime_HostObjectMethodInvocationFailed, methodName,
+ exception.Message)
+ :
+ string.Format(CommonStrings.Runtime_HostTypeMethodInvocationFailed, methodName, typeName,
+ exception.Message)
+ ;
+ errorValue = EdgeJsErrorHelpers.CreateError(errorMessage);
+ }
+ EdgeJsContext.SetException(errorValue);
+
+ return undefinedValue;
+ }
+
+ EdgeJsValue resultValue = MapToScriptType(result);
+
+ return resultValue;
+ };
+ nativeFunctions.Add(nativeFunction);
+
+ EdgeJsValue methodValue = EdgeJsValue.CreateFunction(nativeFunction);
+ typeValue.SetProperty(methodName, methodValue, true);
+ }
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private static void FreezeObject(EdgeJsValue objValue)
+ {
+ EdgeJsValue freezeMethodValue = EdgeJsValue.GlobalObject
+ .GetProperty("Object")
+ .GetProperty("freeze")
+ ;
+ freezeMethodValue.CallFunction(objValue);
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private static void SetNonEnumerableProperty(EdgeJsValue objValue, string name, EdgeJsValue value)
+ {
+ EdgeJsValue descriptorValue = EdgeJsValue.CreateObject();
+ descriptorValue.SetProperty("enumerable", EdgeJsValue.False, true);
+ descriptorValue.SetProperty("writable", EdgeJsValue.True, true);
+
+ EdgeJsPropertyId id = EdgeJsPropertyId.FromString(name);
+ objValue.DefineProperty(id, descriptorValue);
+ objValue.SetProperty(id, value, true);
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private static void CreateAndSetError(string message)
+ {
+ EdgeJsValue errorValue = EdgeJsErrorHelpers.CreateError(message);
+ EdgeJsContext.SetException(errorValue);
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private static void CreateAndSetReferenceError(string message)
+ {
+ EdgeJsValue errorValue = EdgeJsErrorHelpers.CreateReferenceError(message);
+ EdgeJsContext.SetException(errorValue);
+ }
+
+ [MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
+ private static void CreateAndSetTypeError(string message)
+ {
+ EdgeJsValue errorValue = EdgeJsErrorHelpers.CreateTypeError(message);
+ EdgeJsContext.SetException(errorValue);
+ }
+
+ private static EdgeJsValue CreateErrorFromWrapperException(WrapperException exception)
+ {
+ var originalException = (JsException)exception.InnerException;
+ var originalScriptException = originalException as EdgeJsScriptException;
+ EdgeJsValue errorValue = originalScriptException is not null ?
+ originalScriptException.Error
+ :
+ EdgeJsErrorHelpers.CreateError(exception.Description)
+ ;
+
+ return errorValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedItem.cs b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedItem.cs
new file mode 100644
index 0000000..52ab74d
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedItem.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+
+using MsieJavaScriptEngine.Utilities;
+
+namespace MsieJavaScriptEngine.JsRt.Embedding
+{
+ ///
+ /// Embedded item
+ ///
+ /// The type of the JavaScript value
+ /// The type of the native function
+ internal abstract class EmbeddedItem : IDisposable
+ where TValue : struct
+ where TFunction : Delegate
+ {
+ ///
+ /// Host type
+ ///
+ private Type _hostType;
+
+ ///
+ /// Instance of host type
+ ///
+ private object _hostObject;
+
+ ///
+ /// JavaScript value created from an host item
+ ///
+ private readonly TValue _scriptValue;
+
+ ///
+ /// List of native functions, that used to access to members of host item
+ ///
+ private IList _nativeFunctions;
+
+ ///
+ /// Flag indicating whether this object is disposed
+ ///
+ private InterlockedStatedFlag _disposedFlag = new InterlockedStatedFlag();
+
+ ///
+ /// Gets a host type
+ ///
+ public Type HostType
+ {
+ get { return _hostType; }
+ }
+
+ ///
+ /// Gets a instance of host type
+ ///
+ public object HostObject
+ {
+ get { return _hostObject; }
+ }
+
+ ///
+ /// Gets a JavaScript value created from an host item
+ ///
+ public TValue ScriptValue
+ {
+ get { return _scriptValue; }
+ }
+
+ ///
+ /// Gets a list of native functions, that used to access to members of host item
+ ///
+ public IList NativeFunctions
+ {
+ get { return _nativeFunctions; }
+ }
+
+ ///
+ /// Gets a value that indicates if the host item is an instance
+ ///
+ public abstract bool IsInstance
+ {
+ get;
+ }
+
+
+ ///
+ /// Constructs an instance of the embedded item
+ ///
+ /// Host type
+ /// Instance of host type
+ /// JavaScript value created from an host item
+ /// List of native functions, that used to access to members of host item
+ protected EmbeddedItem(Type hostType, object hostObject, TValue scriptValue,
+ IList nativeFunctions)
+ {
+ _hostType = hostType;
+ _hostObject = hostObject;
+ _scriptValue = scriptValue;
+ _nativeFunctions = nativeFunctions;
+ }
+
+
+ #region IDisposable implementation
+
+ ///
+ /// Disposes the embedded item
+ ///
+ public void Dispose()
+ {
+ if (_disposedFlag.Set())
+ {
+ _hostType = null;
+ _hostObject = null;
+
+ IList nativeFunctions = _nativeFunctions;
+ if (nativeFunctions is not null)
+ {
+ nativeFunctions.Clear();
+ _nativeFunctions = null;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObject.cs b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObject.cs
new file mode 100644
index 0000000..8300a73
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObject.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+
+namespace MsieJavaScriptEngine.JsRt.Embedding
+{
+ ///
+ /// Embedded object
+ ///
+ /// The type of the JavaScript value
+ /// The type of the native function
+ internal sealed class EmbeddedObject : EmbeddedItem
+ where TValue : struct
+ where TFunction : Delegate
+ {
+ ///
+ /// Constructs an instance of the embedded object
+ ///
+ /// Instance of host type
+ /// JavaScript value created from an host object
+ public EmbeddedObject(object hostObject, TValue scriptValue)
+ : base(hostObject.GetType(), hostObject, scriptValue, new List())
+ { }
+
+ ///
+ /// Constructs an instance of the embedded object
+ ///
+ /// Instance of host type
+ /// JavaScript value created from an host object
+ /// List of native functions, that used to access to members of host object
+ public EmbeddedObject(object hostObject, TValue scriptValue, IList nativeFunctions)
+ : base(hostObject.GetType(), hostObject, scriptValue, nativeFunctions)
+ { }
+
+ #region EmbeddedItem overrides
+
+ ///
+ /// Gets a value that indicates if the host item is an instance
+ ///
+ public override bool IsInstance
+ {
+ get { return true; }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObjectKey.cs b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObjectKey.cs
new file mode 100644
index 0000000..4131629
--- /dev/null
+++ b/src/MsieJavaScriptEngine/JsRt/Embedding/EmbeddedObjectKey.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using MsieJavaScriptEngine.Resources;
+
+namespace MsieJavaScriptEngine.JsRt.Embedding
+{
+ ///
+ /// Key for storage of embedded objects
+ ///
+ internal struct EmbeddedObjectKey : IEquatable, IStructuralEquatable,
+ IComparable, IComparable, IStructuralComparable
+ {
+ ///
+ /// Name of host type
+ ///
+ public readonly string HostTypeName;
+
+ ///
+ /// Instance of host type
+ ///
+ public readonly object HostObject;
+
+
+ ///
+ /// Constructs an instance of the key for storage of embedded objects
+ ///
+ /// Instance of host type
+ public EmbeddedObjectKey(object hostObject)
+ {
+ HostTypeName = hostObject.GetType().AssemblyQualifiedName;
+ HostObject = hostObject;
+ }
+
+
+ private static int CombineHashCodes(int h1, int h2)
+ {
+ return ((h1 << 5) + h1) ^ h2;
+ }
+
+ #region IEquatable implementation
+
+ public bool Equals(EmbeddedObjectKey other)
+ {
+ return EqualityComparer.Default.Equals(HostTypeName, other.HostTypeName)
+ && EqualityComparer