Skip to content

Commit f770c93

Browse files
committed
Added the EmbedHostObject method (embeds a instance of simple class, structure or delegate to script code)
1 parent 83d2db8 commit f770c93

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1542
-161
lines changed

MsieJavaScriptEngine.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsieJavaScriptEngine.Test.C
2626
EndProject
2727
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsieJavaScriptEngine.Test.Classic", "test\MsieJavaScriptEngine.Test.Classic\MsieJavaScriptEngine.Test.Classic.csproj", "{50453B82-ACBF-4E25-9582-1113F274D53E}"
2828
EndProject
29+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsieJavaScriptEngine.ConsoleTests", "test\MsieJavaScriptEngine.ConsoleTests\MsieJavaScriptEngine.ConsoleTests.csproj", "{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5}"
30+
EndProject
31+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedFiles", "SharedFiles", "{76F4C14E-54ED-42AC-84F7-2072B14ED59E}"
32+
ProjectSection(SolutionItems) = preProject
33+
test\SharedFiles\link.txt = test\SharedFiles\link.txt
34+
test\SharedFiles\square.js = test\SharedFiles\square.js
35+
EndProjectSection
36+
EndProject
2937
Global
3038
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3139
Debug|Any CPU = Debug|Any CPU
@@ -60,6 +68,10 @@ Global
6068
{50453B82-ACBF-4E25-9582-1113F274D53E}.Debug|Any CPU.Build.0 = Debug|Any CPU
6169
{50453B82-ACBF-4E25-9582-1113F274D53E}.Release|Any CPU.ActiveCfg = Release|Any CPU
6270
{50453B82-ACBF-4E25-9582-1113F274D53E}.Release|Any CPU.Build.0 = Release|Any CPU
71+
{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
72+
{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
73+
{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
74+
{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5}.Release|Any CPU.Build.0 = Release|Any CPU
6375
EndGlobalSection
6476
GlobalSection(SolutionProperties) = preSolution
6577
HideSolutionNode = FALSE
@@ -72,5 +84,7 @@ Global
7284
{7064E0DB-0B73-4534-84D0-1C96DA7E5AD1} = {2A0DC227-73C5-4E3A-853A-83007AD56B85}
7385
{21EA96CC-71E2-4CDD-B95A-C75EBD4AF2FA} = {2A0DC227-73C5-4E3A-853A-83007AD56B85}
7486
{50453B82-ACBF-4E25-9582-1113F274D53E} = {2A0DC227-73C5-4E3A-853A-83007AD56B85}
87+
{AFB5ABDF-4F9B-455B-BDA0-CC03D5597FE5} = {2A0DC227-73C5-4E3A-853A-83007AD56B85}
88+
{76F4C14E-54ED-42AC-84F7-2072B14ED59E} = {2A0DC227-73C5-4E3A-853A-83007AD56B85}
7589
EndGlobalSection
7690
EndGlobal

src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ internal abstract class ActiveScriptJsEngineBase : IInnerJsEngine
4141
/// </summary>
4242
private ActiveScriptSiteWrapper _activeScriptSite;
4343

44+
/// <summary>
45+
/// JavaScript engine mode
46+
/// </summary>
47+
private readonly JsEngineMode _engineMode;
48+
4449
/// <summary>
4550
/// Name of JavaScript engine mode
4651
/// </summary>
@@ -61,15 +66,16 @@ internal abstract class ActiveScriptJsEngineBase : IInnerJsEngine
6166
/// Constructs instance of the ActiveScript JavaScript engine
6267
/// </summary>
6368
/// <param name="clsid">CLSID of JavaScript engine</param>
64-
/// <param name="engineModeName">Name of JavaScript engine mode</param>
69+
/// <param name="engineMode">JavaScript engine mode</param>
6570
/// <param name="lowerIeVersion">Lowest supported version of Internet Explorer</param>
6671
/// <param name="languageVersion">Version of script language</param>
6772
/// <param name="useEcmaScript5Polyfill">Flag for whether to use the ECMAScript 5 Polyfill</param>
6873
/// <param name="useJson2Library">Flag for whether to use the JSON2 library</param>
69-
protected ActiveScriptJsEngineBase(string clsid, string engineModeName, string lowerIeVersion,
74+
protected ActiveScriptJsEngineBase(string clsid, JsEngineMode engineMode, string lowerIeVersion,
7075
ScriptLanguageVersion languageVersion, bool useEcmaScript5Polyfill, bool useJson2Library)
7176
{
72-
_engineModeName = engineModeName;
77+
_engineMode = engineMode;
78+
_engineModeName = JsEngineModeHelpers.GetModeName(engineMode);
7379
_pActiveScript = IntPtr.Zero;
7480

7581
try
@@ -167,43 +173,43 @@ protected static bool IsSupported(string clsid, ref bool? isSupported, ref objec
167173
}
168174

169175
/// <summary>
170-
/// Executes a mapping from the host type to a script type
176+
/// Makes a mapping of value from the host type to a script type
171177
/// </summary>
172178
/// <param name="value">The source value</param>
173179
/// <returns>The mapped value</returns>
174-
private static object MapToScriptType(object value)
180+
private object MapToScriptType(object value)
175181
{
176-
if (value == null)
177-
{
178-
return DBNull.Value;
179-
}
180-
181-
if (value is Undefined)
182-
{
183-
return null;
184-
}
182+
return TypeMappingHelpers.MapToScriptType(value, _engineMode);
183+
}
185184

186-
return value;
185+
/// <summary>
186+
/// Makes a mapping of array items from the host type to a script type
187+
/// </summary>
188+
/// <param name="args">The source array</param>
189+
/// <returns>The mapped array</returns>
190+
private object[] MapToScriptType(object[] args)
191+
{
192+
return TypeMappingHelpers.MapToScriptType(args, _engineMode);
187193
}
188194

189195
/// <summary>
190-
/// Executes a mapping from the script type to a host type
196+
/// Makes a mapping of value from the script type to a host type
191197
/// </summary>
192198
/// <param name="value">The source value</param>
193199
/// <returns>The mapped value</returns>
194-
private static object MapToHostType(object value)
200+
private object MapToHostType(object value)
195201
{
196-
if (value == null)
197-
{
198-
return Undefined.Value;
199-
}
200-
201-
if (value is DBNull)
202-
{
203-
return null;
204-
}
202+
return TypeMappingHelpers.MapToHostType(value);
203+
}
205204

206-
return value;
205+
/// <summary>
206+
/// Makes a mapping of array itemp from the script type to a host type
207+
/// </summary>
208+
/// <param name="args">The source array</param>
209+
/// <returns>The mapped array</returns>
210+
private object[] MapToHostType(object[] args)
211+
{
212+
return TypeMappingHelpers.MapToHostType(args);
207213
}
208214

209215
private JsRuntimeException ConvertActiveScriptExceptionToJsRuntimeException(
@@ -367,16 +373,7 @@ public void Execute(string code)
367373

368374
public object CallFunction(string functionName, params object[] args)
369375
{
370-
int argumentCount = args.Length;
371-
var processedArgs = new object[argumentCount];
372-
373-
if (argumentCount > 0)
374-
{
375-
for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++)
376-
{
377-
processedArgs[argumentIndex] = MapToScriptType(args[argumentIndex]);
378-
}
379-
}
376+
var processedArgs = MapToScriptType(args);
380377

381378
object result = InvokeScript(() =>
382379
{
@@ -435,6 +432,34 @@ public void RemoveVariable(string variableName)
435432
InvokeScript(() => _activeScriptSite.DeleteProperty(variableName));
436433
}
437434

435+
public void EmbedHostObject(string itemName, object value)
436+
{
437+
InvokeScript(() =>
438+
{
439+
var processedValue = MapToScriptType(value);
440+
object oldValue = _activeScriptSite.GetItem(itemName);
441+
_activeScriptSite.SetItem(itemName, processedValue);
442+
443+
try
444+
{
445+
_activeScript.AddNamedItem(itemName, ScriptItemFlags.IsVisible | ScriptItemFlags.GlobalMembers);
446+
}
447+
catch (Exception)
448+
{
449+
if (oldValue != null)
450+
{
451+
_activeScriptSite.SetItem(itemName, oldValue);
452+
}
453+
else
454+
{
455+
_activeScriptSite.RemoveItem(itemName);
456+
}
457+
458+
throw;
459+
}
460+
});
461+
}
462+
438463
#endregion
439464

440465
#region IDisposable implementation

src/MsieJavaScriptEngine/ActiveScript/ActiveScriptSiteWrapper.cs

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ internal class ActiveScriptSiteWrapper : IActiveScriptSite, IDisposable
3535
/// </summary>
3636
private Dictionary<string, object> _siteItems = new Dictionary<string, object>();
3737

38+
/// <summary>
39+
/// Synchronizer
40+
/// </summary>
41+
private readonly object _synchronizer = new object();
42+
3843
/// <summary>
3944
/// Last ActiveScript exception
4045
/// </summary>
@@ -124,32 +129,29 @@ private void InitScriptDispatch()
124129
/// </summary>
125130
/// <param name="name">The name associated with the item, as specified in the
126131
/// IActiveScript.AddNamedItem method</param>
127-
private object GetItem(string name)
132+
public object GetItem(string name)
128133
{
129-
lock (_siteItems)
134+
lock (_synchronizer)
130135
{
131136
object result;
132137

133138
return _siteItems.TryGetValue(name, out result) ? result : null;
134139
}
135140
}
136141

137-
/// <summary>
138-
/// Allows the scripting engine to obtain information about an item added with the
139-
/// IActiveScript.AddNamedItem method. Gets the COM ITypeInfo
140-
/// </summary>
141-
/// <param name="name">The name associated with the item, as specified in the
142-
/// IActiveScript.AddNamedItem method</param>
143-
private IntPtr GetTypeInfo(string name)
142+
public void SetItem(string name, object value)
144143
{
145-
lock (_siteItems)
144+
lock (_synchronizer)
146145
{
147-
if (!_siteItems.ContainsKey(name))
148-
{
149-
return IntPtr.Zero;
150-
}
146+
_siteItems[name] = value;
147+
}
148+
}
151149

152-
return Marshal.GetITypeInfoForType(_siteItems[name].GetType());
150+
public void RemoveItem(string name)
151+
{
152+
lock (_synchronizer)
153+
{
154+
_siteItems.Remove(name);
153155
}
154156
}
155157

@@ -330,10 +332,13 @@ private void Dispose(bool disposing)
330332

331333
_lastException = null;
332334

333-
if (_siteItems != null)
335+
lock (_synchronizer)
334336
{
335-
_siteItems.Clear();
336-
_siteItems = null;
337+
if (_siteItems != null)
338+
{
339+
_siteItems.Clear();
340+
_siteItems = null;
341+
}
337342
}
338343

339344
if (_dispatch != null)
@@ -372,48 +377,43 @@ public void GetLcid(out int lcid)
372377
/// </summary>
373378
/// <param name="name">The name associated with the item, as specified in the
374379
/// IActiveScript.AddNamedItem method</param>
375-
/// <param name="returnMask">A bit mask specifying what information about the item should be
380+
/// <param name="mask">A bit mask specifying what information about the item should be
376381
/// returned. The scripting engine should request the minimum amount of information possible
377382
/// because some of the return parameters (for example, ITypeInfo) can take considerable
378383
/// time to load or generate</param>
379-
/// <param name="item">A variable that receives a pointer to the IUnknown interface associated
384+
/// <param name="pUnkItem">A variable that receives a pointer to the IUnknown interface associated
380385
/// with the given item. The scripting engine can use the IUnknown.QueryInterface method to
381-
/// obtain the IDispatch interface for the item. This parameter receives null if returnMask
386+
/// obtain the IDispatch interface for the item. This parameter receives null if mask
382387
/// does not include the ScriptInfo.IUnknown value. Also, it receives null if there is no
383388
/// object associated with the item name; this mechanism is used to create a simple class when
384389
/// the named item was added with the ScriptItem.CodeOnly flag set in the
385390
/// IActiveScript.AddNamedItem method.</param>
386391
/// <param name="pTypeInfo">A variable that receives a pointer to the ITypeInfo interface
387-
/// associated with the item. This parameter receives null if returnMask does not include the
392+
/// associated with the item. This parameter receives null if mask does not include the
388393
/// ScriptInfo.ITypeInfo value, or if type information is not available for this item. If type
389394
/// information is not available, the object cannot source events, and name binding must be
390395
/// realized with the IDispatch.GetIDsOfNames method. Note that the ITypeInfo interface
391396
/// retrieved describes the item's coclass (TKIND_COCLASS) because the object may support
392397
/// multiple interfaces and event interfaces. If the item supports the IProvideMultipleTypeInfo
393398
/// interface, the ITypeInfo interface retrieved is the same as the index zero ITypeInfo that
394399
/// would be obtained using the IProvideMultipleTypeInfo.GetInfoOfIndex method.</param>
395-
public void GetItemInfo(string name, ScriptInfoFlags returnMask, out object item, out IntPtr pTypeInfo)
400+
public void GetItemInfo(string name, ScriptInfoFlags mask, ref IntPtr pUnkItem, ref IntPtr pTypeInfo)
396401
{
397-
if ((returnMask & ScriptInfoFlags.IUnknown) > 0)
402+
object item = GetItem(name);
403+
if (item == null)
398404
{
399-
item = GetItem(name);
400-
if (item == null)
401-
{
402-
throw new COMException(string.Format(Strings.Runtime_ItemNotFound, name), ComErrorCode.ElementNotFound);
403-
}
404-
}
405-
else
406-
{
407-
item = null;
405+
throw new COMException(
406+
string.Format(Strings.Runtime_ItemNotFound, name), ComErrorCode.ElementNotFound);
408407
}
409408

410-
if ((returnMask & ScriptInfoFlags.ITypeInfo) > 0)
409+
if (mask.HasFlag(ScriptInfoFlags.IUnknown))
411410
{
412-
pTypeInfo = GetTypeInfo(name);
411+
pUnkItem = Marshal.GetIDispatchForObject(item);
413412
}
414-
else
413+
414+
if (mask.HasFlag(ScriptInfoFlags.ITypeInfo))
415415
{
416-
pTypeInfo = IntPtr.Zero;
416+
pTypeInfo = Marshal.GetITypeInfoForType(item.GetType());
417417
}
418418
}
419419

src/MsieJavaScriptEngine/ActiveScript/ChakraActiveScriptJsEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ internal sealed class ChakraActiveScriptJsEngine : ActiveScriptJsEngineBase
2424
/// Constructs instance of the Chakra ActiveScript JavaScript engine
2525
/// </summary>
2626
public ChakraActiveScriptJsEngine()
27-
: base(CHAKRA_CLSID, JsEngineModeName.ChakraActiveScript, "9",
27+
: base(CHAKRA_CLSID, JsEngineMode.ChakraActiveScript, "9",
2828
ScriptLanguageVersion.EcmaScript5, false, false)
2929
{ }
3030

src/MsieJavaScriptEngine/ActiveScript/ClassicActiveScriptJsEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal sealed class ClassicActiveScriptJsEngine : ActiveScriptJsEngineBase
2626
/// <param name="useEcmaScript5Polyfill">Flag for whether to use the ECMAScript 5 Polyfill</param>
2727
/// <param name="useJson2Library">Flag for whether to use the JSON2 library</param>
2828
public ClassicActiveScriptJsEngine(bool useEcmaScript5Polyfill, bool useJson2Library)
29-
: base(CLASSIC_CLSID, JsEngineModeName.Classic, "6",
29+
: base(CLASSIC_CLSID, JsEngineMode.Classic, "6",
3030
ScriptLanguageVersion.None, useEcmaScript5Polyfill, useJson2Library)
3131
{ }
3232

src/MsieJavaScriptEngine/ActiveScript/IActiveScriptSite.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ void GetLcid(
3434
/// </summary>
3535
/// <param name="name">The name associated with the item, as specified in the
3636
/// IActiveScript.AddNamedItem method</param>
37-
/// <param name="returnMask">A bit mask specifying what information about the item should be
37+
/// <param name="mask">A bit mask specifying what information about the item should be
3838
/// returned. The scripting engine should request the minimum amount of information possible
3939
/// because some of the return parameters (for example, ITypeInfo) can take considerable
4040
/// time to load or generate.</param>
41-
/// <param name="item">A variable that receives a pointer to the IUnknown interface associated
41+
/// <param name="pUnkItem">A variable that receives a pointer to the IUnknown interface associated
4242
/// with the given item. The scripting engine can use the IUnknown.QueryInterface method to
43-
/// obtain the IDispatch interface for the item. This parameter receives null if returnMask
43+
/// obtain the IDispatch interface for the item. This parameter receives null if mask
4444
/// does not include the ScriptInfo.IUnknown value. Also, it receives null if there is no
4545
/// object associated with the item name; this mechanism is used to create a simple class when
4646
/// the named item was added with the ScriptItem.CodeOnly flag set in the
4747
/// IActiveScript.AddNamedItem method.</param>
4848
/// <param name="pTypeInfo">A variable that receives a pointer to the ITypeInfo interface
49-
/// associated with the item. This parameter receives null if returnMask does not include the
49+
/// associated with the item. This parameter receives null if mask does not include the
5050
/// ScriptInfo.ITypeInfo value, or if type information is not available for this item. If type
5151
/// information is not available, the object cannot source events, and name binding must be
5252
/// realized with the IDispatch.GetIDsOfNames method. Note that the ITypeInfo interface
@@ -56,9 +56,9 @@ void GetLcid(
5656
/// would be obtained using the IProvideMultipleTypeInfo.GetInfoOfIndex method.</param>
5757
void GetItemInfo(
5858
[In] [MarshalAs(UnmanagedType.LPWStr)] string name,
59-
[In] ScriptInfoFlags returnMask,
60-
[Out] [MarshalAs(UnmanagedType.IUnknown)] out object item,
61-
[Out] out IntPtr pTypeInfo);
59+
[In] ScriptInfoFlags mask,
60+
[In] [Out] ref IntPtr pUnkItem,
61+
[In] [Out] ref IntPtr pTypeInfo);
6262

6363
/// <summary>
6464
/// Retrieves a host-defined string that uniquely identifies the current document version. If

0 commit comments

Comments
 (0)